最近在读取客户发过来的tiff文件是,底层竟然报错了,错误: bandOffsets.length is wrong! 没办法,因为错误消息出现在tiff的read中,因此就对底层序中tiff读取的代码进行了研究。
借助这篇文章,我们需要先了解Tiff文件的具体结构,可以参考这篇文章, TIFF文件结构详解 https://blog.csdn.net/oYinHeZhiGuang/article/details/121710467 讲的很好!
下面我们来看下imageio-ext中的tiff读取代码,主要类TiffImageReader,我们来看下Java程序是如何读取tiff文件的。
- public TIFFImageReader(ImageReaderSpi originatingProvider) {
- super(originatingProvider);
- }
这个类需要通过一个ImageReaderSpi来实例化,其实这种SPI的设计模式,Java的很多开源项目都在用到,这里我们通过TIFFImageReaderSpi这个类即可。
其次设置文件的路径,以及其它一些参数,通过该类的如下方法:
- public void setInput(Object input,
- boolean seekForwardOnly,
- boolean ignoreMetadata)
这个方法,里面有input就是需要读取的文件, seekForwardOnly设置为true表示: 只能从这个输入源按升序读取图像和元数据。 ignoreMetadata设置为true表示读取忽略元数据
接下来就是对tiff元数据的读取,具体参见getImageMetadata(int imageIndex)这个方法:
- public IIOMetadata getImageMetadata(int imageIndex) throws IIOException {
- seekToImage(imageIndex, true);
- TIFFImageMetadata im =
- new TIFFImageMetadata(imageMetadata.getRootIFD().getTagSetList());
- Node root =
- imageMetadata.getAsTree(TIFFImageMetadata.nativeMetadataFormatName);
- im.setFromTree(TIFFImageMetadata.nativeMetadataFormatName, root);
- if (noData != null) {
- im.setNoData(new double[] {noData, noData});
- }
- if (scales != null && offsets != null) {
- im.setScales(scales);
- im.setOffsets(offsets);
- }
- return im;
- }
其中的seekToImage(imageIndex, true)为最主要的逻辑处理,这个方法中,第一个参数,imageIndex为tiff多页中的第几个,第二参数设置标示该tiff页是否已经被解析过
- private void seekToImage(int imageIndex, boolean optimized) throws IIOException {
- checkIndex(imageIndex);
-
- // TODO we should do this initialization just once!!!
- int index = locateImage(imageIndex);
- if (index != imageIndex) {
- throw new IndexOutOfBoundsException("imageIndex out of bounds!");
- }
-
- final Integer i= Integer.valueOf(index);
- //optimized branch
- if(!optimized){
-
- readMetadata();
- initializeFromMetadata();
- return;
- }
- // in case we have cache the info for this page
- if(pagesInfo.containsKey(i)){
- // initialize from cachedinfo only if needed
- // TODO Improve
- if(imageMetadata == null || !initialized) {// this means the curindex has changed
- final PageInfo info = pagesInfo.get(i);
- final TIFFImageMetadata metadata = info.imageMetadata.get();
- if (metadata != null) {
- initializeFromCachedInfo(info, metadata);
- return;
- }
- pagesInfo.put(i,null);
-
- }
- }
-
- readMetadata();
- initializeFromMetadata();
- }
这个方法当中,第一次加载tiff,通过readMetadata()和initializeFromMetadata()将tiff的元信息缓存起来,方便后面再次读取。
主要是要结合Tiff的格式进行理解