• Java 解析Tiff深入研究


    最近在读取客户发过来的tiff文件是,底层竟然报错了,错误: bandOffsets.length is wrong!  没办法,因为错误消息出现在tiff的read中,因此就对底层序中tiff读取的代码进行了研究。

    借助这篇文章,我们需要先了解Tiff文件的具体结构,可以参考这篇文章, TIFF文件结构详解 https://blog.csdn.net/oYinHeZhiGuang/article/details/121710467  讲的很好!

    下面我们来看下imageio-ext中的tiff读取代码,主要类TiffImageReader,我们来看下Java程序是如何读取tiff文件的。

    构造方法:

    1. public TIFFImageReader(ImageReaderSpi originatingProvider) {
    2. super(originatingProvider);
    3. }

    这个类需要通过一个ImageReaderSpi来实例化,其实这种SPI的设计模式,Java的很多开源项目都在用到,这里我们通过TIFFImageReaderSpi这个类即可。

    其次设置文件的路径,以及其它一些参数,通过该类的如下方法:

    1. public void setInput(Object input,
    2. boolean seekForwardOnly,
    3. boolean ignoreMetadata)

    这个方法,里面有input就是需要读取的文件, seekForwardOnly设置为true表示: 只能从这个输入源按升序读取图像和元数据。 ignoreMetadata设置为true表示读取忽略元数据

    接下来就是对tiff元数据的读取,具体参见getImageMetadata(int imageIndex)这个方法:

    1. public IIOMetadata getImageMetadata(int imageIndex) throws IIOException {
    2. seekToImage(imageIndex, true);
    3. TIFFImageMetadata im =
    4. new TIFFImageMetadata(imageMetadata.getRootIFD().getTagSetList());
    5. Node root =
    6. imageMetadata.getAsTree(TIFFImageMetadata.nativeMetadataFormatName);
    7. im.setFromTree(TIFFImageMetadata.nativeMetadataFormatName, root);
    8. if (noData != null) {
    9. im.setNoData(new double[] {noData, noData});
    10. }
    11. if (scales != null && offsets != null) {
    12. im.setScales(scales);
    13. im.setOffsets(offsets);
    14. }
    15. return im;
    16. }

    其中的seekToImage(imageIndex, true)为最主要的逻辑处理,这个方法中,第一个参数,imageIndex为tiff多页中的第几个,第二参数设置标示该tiff页是否已经被解析过

    1. private void seekToImage(int imageIndex, boolean optimized) throws IIOException {
    2. checkIndex(imageIndex);
    3. // TODO we should do this initialization just once!!!
    4. int index = locateImage(imageIndex);
    5. if (index != imageIndex) {
    6. throw new IndexOutOfBoundsException("imageIndex out of bounds!");
    7. }
    8. final Integer i= Integer.valueOf(index);
    9. //optimized branch
    10. if(!optimized){
    11. readMetadata();
    12. initializeFromMetadata();
    13. return;
    14. }
    15. // in case we have cache the info for this page
    16. if(pagesInfo.containsKey(i)){
    17. // initialize from cachedinfo only if needed
    18. // TODO Improve
    19. if(imageMetadata == null || !initialized) {// this means the curindex has changed
    20. final PageInfo info = pagesInfo.get(i);
    21. final TIFFImageMetadata metadata = info.imageMetadata.get();
    22. if (metadata != null) {
    23. initializeFromCachedInfo(info, metadata);
    24. return;
    25. }
    26. pagesInfo.put(i,null);
    27. }
    28. }
    29. readMetadata();
    30. initializeFromMetadata();
    31. }

    这个方法当中,第一次加载tiff,通过readMetadata()和initializeFromMetadata()将tiff的元信息缓存起来,方便后面再次读取。

    读取过程

    主要是要结合Tiff的格式进行理解࿰

  • 相关阅读:
    PostgreSQL常用命令使用
    《太赫兹雷达成像技术》阅读笔记 1:第一章 概论
    IDEA 2022报错:Error running,Command line is too long. Shorten command line
    DX 的 HLSL 和 GL 的 GLSL的 矩阵构建的行列区别
    万里数据库入围赛迪数据库市场研究报告领导者象限,成最大黑马
    红外小目标:DNANet网络结构与模型搭建
    百度飞浆OCR识别表格入门python实践
    从零开始学习CANoe 系列文章目录汇总
    Spring Cloud学习笔记(Ribbon):Ribbon的应用样例
    Apple m1 pro SourceTree 拉代码,AndroidStudio运行
  • 原文地址:https://blog.csdn.net/Chenhui98/article/details/126578096