问题描述
我试图动态创建巨大的TIFF图像,而不将整个图像保存在内存中。我选择TIFF格式是因为它似乎是Java ImageWriters中唯一支持此功能的格式。
无论如何,我都会得到一个多页文件(使用writetoSequence
方法时)或仅包含最后一个图块的图像(使用write()
方法时)。
我的基本代码如下:
final ImageWriter tiffImageWriter = ImageIO.getimageWritersByFormatName("TIFF").next();
final ImageWriteParam param = tiffImageWriter.getDefaultWriteparam();
param.setTilingMode(MODE_EXPLICIT);
param.setTiling(TILE_SIZE,TILE_SIZE,0);
try (ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(response.getoutputStream())) {
tiffImageWriter.setoutput(imageOutputStream);
for (int tileX = 0; tileX < 10; tileX++) {
for (int tileY = 0; tileY < 10; tileY++) {
final BufferedImage bufferedImage = ... // some method producing a BufferedImage of size TILE_SIZExTILE_SIZE
tiffImageWriter.write(null,new IIOImage(bufferedImage,null,null),param);
imageOutputStream.flush();
}
}
}
tiffImageWriter.dispose();
response.getoutputStream()
是我的服务的输出流。
运行此代码的结果是一个TILE_SIZE x TILE_SIZE
大小的图像,其中最后一个图块为内容。
我想知道是否有可能做到这一点,或者此功能是为其他目的设计的?
解决方法
您已经知道,write
和writeToSequence
在这种情况下不起作用。而且他们不应该这样做。这些方法分别用于写入单个图像文件或多个图像文件。它们不是用于部分写入图像。要使用javax.imageio
API编写图像,而不必一次将整个图像保存在内存中,则至少有两个选择:
- 使用单个平铺的
RenderedImage
。您需要创建一个自定义实现,以按需创建每个切片(您可能已经完成了)。但是,正如您在your previous Q&A中发现的那样,切片大小(以及编写者是否将全部使用切片)取决于ImageWriter
的实现。因此,您可能必须为所使用的书写器调整图块大小。可能有一个内存中的切片缓存来获得不错的性能。 - 使用
ImageWriter
方法canWriteEmpty
/canReplacePixels
,如果它们都返回true
,则使用prepareWriteEmpty
/endWriteEmpty
(对于整个图片),然后是每个图块的prepareReplacePixels
,replacePixels
,endReplacePixels
。看来这应该适用于JAI或Java9 +TIFFImageWriter
(仅适用于未压缩的图像)。我知道目前这并不适用于TwelveMonkeysTIFFImageWriter
,因为这是一个非常罕见的用例。
考虑到您的代码示例和期望,第二种选择似乎是最接近您要寻找的选择。