我正在使用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文件的更好方法吗?

让我知道是否有什么可以让我的问题更清楚。

谢谢!

最佳答案

如评论中所述,您不应直接使用TIFFPackBitsCompressor,而是在TIFFImageWriter中将“ PackBits”指定为压缩类型时,JAI ImageIO TIFF插件(ImageWriteParam)将在内部使用它。如果先将压缩器实例转换为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是基于字节数据run-length encoding的非常简单的压缩算法。由于16位数据可能在单个样本的高字节和低字节之间变化很大,因此PackBits通常不是压缩此类数据的好选择。

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

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算法(带有预测器步骤)的执行效果更好。对于“真实”数据,可能会有更多干扰,因此您的结果可能介于这些极端之间。

07-26 09:05