将TIFF图像逐块写入输出流

问题描述

我试图动态创建巨大的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大小的图像,其中最后一个图块为内容

我想知道是否有可能做到这一点,或者此功能是为其他目的设计的?

解决方法

您已经知道,writewriteToSequence在这种情况下不起作用。而且他们不应该这样做。这些方法分别用于写入单个图像文件或多个图像文件。它们不是用于部分写入图像。要使用javax.imageio API编写图像,而不必一次将整个图像保存在内存中,则至少有两个选择:

  • 使用单个平铺的RenderedImage。您需要创建一个自定义实现,以按需创建每个切片(您可能已经完成了)。但是,正如您在your previous Q&A中发现的那样,切片大小(以及编写者是否将全部使用切片)取决于ImageWriter的实现。因此,您可能必须为所使用的书写器调整图块大小。可能有一个内存中的切片缓存来获得不错的性能。
  • 使用ImageWriter方法canWriteEmpty / canReplacePixels,如果它们都返回true,则使用prepareWriteEmpty / endWriteEmpty(对于整个图片),然后是每个图块的prepareReplacePixelsreplacePixelsendReplacePixels。看来这应该适用于JAI或Java9 + TIFFImageWriter(仅适用于未压缩的图像)。我知道目前这并不适用于TwelveMonkeys TIFFImageWriter,因为这是一个非常罕见的用例。

考虑到您的代码示例和期望,第二种选择似乎是最接近您要寻找的选择。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...