如何更改ImageIO写入Endianness

时间:2017-07-03 13:52:53

标签: java tiff javax.imageio endianness

我正在使用

将PDF的RenderedImage写入tiff文件
javax.imageio.ImageIO.write(RenderedImage,"tif" ,file)

我期待我的tiff文件endian是little-endian,但是它在big-endian中写道,可以帮助解释如何将它更改为little-endian?

还可以解释为什么使用big-endian编写的数据比原始文件大小更大? 我试图将数据转换为我的java代码之外的little-endian,文件大小从16 MB大幅减少到943字节。

1 个答案:

答案 0 :(得分:3)

ImageIO API没有标准化的方式来指定字节顺序(字节顺序)。如何执行此操作,或者是否支持它,是依赖于插件的。

对于TIFF格式,存在多个插件(JAI,GeoTIFF,TwelveMonkeys,JDK9)。所有提到的插件(据我所知)支持使用发送到ImageWriter.write(...)的流元数据设置字节序。字节顺序是您可以在TIFF流元数据中设置的唯一字段。

ImageWriter writer = ImageIO.getImageWritersByFormatName("TIFF").next();
writer.setOutput(stream);

IIOMetadata streamMetadata = writer.getDefaultStreamMetadata();

IIOMetadataNode root = new IIOMetadataNode("com_sun_media_imageio_plugins_tiff_stream_1.0");
IIOMetadataNode byteOrder = new IIOMetadataNode("ByteOrder");
byteOrder.setAttribute("value", order == LITTLE_ENDIAN ? "LITTLE_ENDIAN" : "BIG_ENDIAN");
root.appendChild(byteOrder);

streamMetadata .mergeTree("com_sun_media_imageio_plugins_tiff_stream_1.0", root);

// ...

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

此外,如果未使用流元数据指定,则TwelveMonkeys TIFF插件将使用其写入的ImageOutputStream的字节顺序。以这种方式指定字节顺序在我看来更直接,但插件之间显然不太兼容。

try (ImageOutputStream stream = ImageIO.createImageOutputStream(out)) {
    stream.setByteOrder(ByteOrder.LITTLE_ENDIAN);

    ImageIO.write(image, "TIFF", stream);
}

关于文件大小,大多数已知的TIFF插件默认会写入未压缩的图像数据。遗憾的是,无法使用ImageIO便捷方法直接指定压缩设置,因此使用这些方法编写的任何TIFF都将被解压缩。

ImageIO API要求您获取要写入的格式的ImageWriter,并传入ImageWriteParam以指定压缩设置。请注意,支持的压缩类型可能因插件而异。另请注意,产生最佳压缩率的压缩类型取决于您尝试压缩的图像数据。

ImageWriter writer = ImageIO.getImageWritersByFormatName("TIFF").next();
writer.setOutput(stream);

ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionType("LZW"); // "Zlib", "PackBits", "JPEG", "CCITT T.4", "CCITT T.6" etc.
param.setCompressionQuality(0.5f); // Applies only to some compression types. Generally:
                                   // * 0.0 means highest compression
                                   // * 1.0 means best quality

您可以使用以下命令查询当前插件中可用的压缩类型:

String[] types = param.getCompressionTypes();