如何更改 ImageIO 写入字节序
Posted
技术标签:
【中文标题】如何更改 ImageIO 写入字节序【英文标题】:How to change the ImageIO write Endianness 【发布时间】:2017-07-03 13:52:53 【问题描述】:我正在使用
将 PDF 的 RenderedImage 写入 tiff 文件javax.imageio.ImageIO.write(RenderedImage,"tif" ,file)
我希望我的 tiff 文件 endian 是 little-endian,但是它是以 big-endian 编写的,可以帮助解释如何将其更改为 little-endian 吗?
还可以解释为什么使用大端写入的数据比原始文件大小要大吗? 我尝试在我的 java 代码之外将数据转换为 little-endian,文件大小从 16 MB 大幅减少到 943 字节。
【问题讨论】:
您使用的是哪个 ImageIO 的 TIFF 插件?使用(我的)TwelveMonkeys 插件,您可以使用stream.setByteOrder(LITTLE_ENDIAN)
简单地设置ImageInputStream
的字节序(字节顺序)。它还支持使用传递给ImageWriter.write(...)
的流元数据设置字节顺序。这种方式也适用于 JAI。但是,如果您看到尺寸如此缩小,我认为这是完全错误的......
我正在使用 TwelveMonkeys 插件,感谢您的建议,我可以设置字节序,但是我在设置压缩时仍然遇到问题,可以使用相同的插件在 tiff 上设置压缩吗?以及如何做到这一点?我想这就是文件大小更大的原因。
【参考方案1】:
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();
【讨论】:
以上是关于如何更改 ImageIO 写入字节序的主要内容,如果未能解决你的问题,请参考以下文章