2

I am trying to create a huge TIFF image dynamically without holding the whole image in memory. I've chosen the TIFF format because it seems to be the only one among Java ImageWriters which supports this feature.

However whatever I tried I get either a multi-paged file (when I use writeToSequence method) or an image containing just the last tile (when I use write() method).

My basic code looks like that:

        final ImageWriter tiffImageWriter = ImageIO.getImageWritersByFormatName("TIFF").next();
        final ImageWriteParam param = tiffImageWriter.getDefaultWriteParam();
        param.setTilingMode(MODE_EXPLICIT);
        param.setTiling(TILE_SIZE, TILE_SIZE, 0, 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();

Here response.getOutputStream() is an output stream from my service.

The outcome of running this code is an image of TILE_SIZE x TILE_SIZE size with the last tile as a content.

I wonder if it even possible to do this trick or this feature is designed for something else?

Andremoniy
  • 34,031
  • 20
  • 135
  • 241
  • This QA here seems to be a duplicate of your question: https://stackoverflow.com/questions/6904752/write-tiled-output-of-tiff-using-imageio-in-java if it works for you can you let us know and we can make this question a duplicate? – ControlAltDel Aug 11 '20 at 18:13
  • @ControlAltDel not at all, has nothing to do with the problem I have. – Andremoniy Aug 11 '20 at 18:15
  • Can you make this into a complete example then? Maybe even generate just generate a BufferedImage with some simple graphic, and how you want them together. – matt Aug 11 '20 at 21:06

1 Answers1

0

As you have already figured out, write and writeToSequence will not work in this case. And they are not supposed to. These methods are for writing a single image file, or a multiple image file respectively. They are not for partially writing images. To write an image using the javax.imageio API, without having to keep the entire image in memory at a time, you have at least two options:

  • Use a single, tiled RenderedImage. You need to make a custom implementation that creates each tile on demand (which you have probably already done). But as you figured out in your previous Q&A, the tile sizes (and whether the writer will use tiles at all) is up to the ImageWriter implementation. So you may have to tune the tile sizes for the writer you use. And probably have an in-memory tile cache to get decent performance.
  • Use the ImageWriter methods canWriteEmpty/canReplacePixels, and if they both return true, use prepareWriteEmpty/endWriteEmpty (for the entire image), then prepareReplacePixels, replacePixels, endReplacePixels for each tile. It seems that this should work for the JAI or Java9+ TIFFImageWriter (for uncompressed images only). I know it does not for the TwelveMonkeys TIFFImageWriter at the moment, as it's quite a rare use case.

The second option seems to be the one closest to what you are looking for, given your code sample and expectations.

Harald K
  • 26,314
  • 7
  • 65
  • 111