【问题标题】:TIFFPackBitsCompressor - NPE?TIFFPackBitsCompressor - NPE?
【发布时间】:2017-03-24 20:39:00
【问题描述】:

我正在使用 com.sun.media.imageioimpl.plugins.tiff.TIFFPackBitsCompressor 来尝试对使用 PackBits 的 tiff 字节数组进行编码。我对这个类不熟悉,也没有找到很多关于如何使用它的例子。但是,在遵循 javadoc 时,每次尝试对数据进行编码时,我都会得到一个 NPE。据我所知,我的值都不是空值。在这一点上,我已经用多个值尝试了这些测试,但下面是我最近的迭代:

                TIFFPackBitsCompressor pack = new TIFFPackBitsCompressor();
                //bImageFromConvert is a 16-bit BufferedImage with all desired data.
                short[] bufferHolder = ((DataBufferUShort) bImageFromConvert.getRaster().getDataBuffer()).getData();
                //Since bImageFromConvert is 16-bits, the short array isn't the right length. 
                //The below conversion handles tihs issue
                byte[] byteBuffer = convertShortToByte(bufferHolder);
                //I'm not entirely sure what this int[] in the parameters should be. 
                //For now, it is a test int[] array containing all 1s
                int[] testint = new int[byteBuffer.length];
                Arrays.fill(testint, 1);
                //0 offset. dimWidth = 1760, dimHeight = 2140. Not sure what that last param is supposed to be in layman's terms.
                //npe thrown at this line.
                int testOut = pack.encode(byteBuffer, 0, dimWidth, dimHeight, testint, 1);

有人对正在发生的事情有任何见解吗?另外,如果有的话,有没有人知道在 java 程序中使用 PackBits 对我的 TIFF 文件进行编码的更好方法?

如果有什么可以让我的问题更清楚,请告诉我。

谢谢!

【问题讨论】:

  • 堆栈跟踪在哪里?无论如何,我认为您不应该自己使用压缩器,而是当您在ImageWriteParam 中将“PackBits”指定为压缩类型时,JAI ImageIO TIFF 插件(TIFFImageWriter)会使用它。你也可以在参数中传递一个压缩器实例,如果你先将它转换为TIFFImageWriteParam,但这对于插件不知道的自定义压缩更有用。

标签: java tiff javax.imageio jai


【解决方案1】:

正如评论中所说,您不应该直接使用TIFFPackBitsCompressor,而是当您在@987654325 中将“PackBits”指定为压缩类型时,JAI ImageIO TIFF 插件(TIFFImageWriter)在内部使用它@。你也可以在参数中传递一个压缩器实例,如果你先将它转换为TIFFImageWriteParam,但这对于插件不知道的自定义压缩更有用。

还要注意,压缩器只会写入 PackBits 压缩的像素数据,它不会创建完整的 TIFF 文件。

写PackBits压缩TIFF文件的正常方式是:

BufferedImage image = ...; // Your input image

ImageWriter writer = ImageIO.getImageWritersByFormatName("TIFF").next(); // Assuming a TIFF plugin is installed

try (ImageOutputStream out = ImageIO.createImageOutputStream(...)) { // Your output file or stream
    writer.setOutput(out);

    ImageWriteParam param = writer.getDefaultWriteParam();
    param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
    param.setCompressionType("PackBits");

    writer.write(null, new IIOImage(image, null, null), param);
}

writer.dispose();

使用 JAI ImageIO 和 TwelveMonkeys ImageIO TIFF 插件,上述代码应该可以正常工作。


PS:PackBits 是一种非常简单的压缩算法,基于 byte 数据的run-length encoding。由于 16 位数据可能在单个样本的高字节和低字节之间变化很大,因此 PackBits 通常不是压缩此类数据的好选择。

正如我的 cmets 所述,使用完全随机的值我得到了以下结果:

Compression      | File size
-----------------|-----------------
None             |  7 533 680 bytes
PackBits         |  7 593 551 bytes
LZW w/predictor  | 10 318 091 bytes
ZLib w/predictor | 10 318 444 bytes

这并不奇怪,因为完全随机的数据通常不可压缩(不会丢失数据)。对于可能更类似于“摄影”图像数据的线性渐变,我得到了完全不同的结果:

Compression      | File size
-----------------|-----------------
None             |  7 533 680 bytes
PackBits         |  7 588 779 bytes
LZW w/predictor  |    200 716 bytes
ZLib w/predictor |    144 136 bytes

如您所见,这里的 LZW 和 Deflate/Zlib 算法(带有预测器步骤)的性能要好得多。对于“真实”数据,可能会有更多噪音,因此您的结果可能介于这两个极端之间。

【讨论】:

  • 当一个文件正在写入并且是 tiff 格式时,它大约是原始文件大小的两倍。如果有帮助,short[] 会保存 16 位图像的包装字节。图像为 1760x2140 像素,原始图像大小为 7,532,800 字节(无元数据,只有像素字节)。此代码生成的文件 15,119,390 字节(包括 tiff 元数据)。
  • @Sarah 您刚刚发现 PackBits 对您的数据来说是一种非常低效的压缩算法(通常对于 16 位数据来说它是低效的)。使用上面的代码,我将黑色图像(仍然是 1760x2140 16 位/像素)压缩到 120 KB。用随机噪声填充图像,文件大小变为 7,5 MB。将 LZW 或 ZLib 与预测器一起使用会产生大约 10 MB 的大小,但它仍可能为您产生更好的结果,因为您的数据不是随机的。
猜你喜欢
  • 2020-06-13
  • 1970-01-01
  • 1970-01-01
  • 2012-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-06
  • 2021-01-19
相关资源
最近更新 更多