tiffjavax.imageiotwelvemonkeys

How to keep the stream of ImageOutputStream in memory?


The following code uses twelvemonkeys to create a tiff file. The created file gets flushed to disk automatically. But I would like the file to be created in memory only. How to achive this with the ImageOutputStream?

try {
  // Create output stream
  ImageOutputStream output = ImageIO.createImageOutputStream(targetFile);

  try {
    writer.setOutput(output);

    ImageWriteParam param = writer.getDefaultWriteParam();
    TIFFImageWriteParam tiffWriteParam = (TIFFImageWriteParam) param;
    tiffWriteParam.setCompressionMode(ImageWriteParam.MODE_DISABLED);     

    TIFFImageMetadata metadata = (TIFFImageMetadata) createMetadata(sourceFile);     

    // Set dpi
    String nativeFormat = TIFFMedataFormat.SUN_NATIVE_IMAGE_METADATA_FORMAT_NAME;
    // Node nativeTree = metadata.getAsTree(nativeFormat);
    IIOMetadataNode newTree =
        new IIOMetadataNode("com_sun_media_imageio_plugins_tiff_image_1.0");
    IIOMetadataNode ifdNode = new IIOMetadataNode("TIFFIFD");
    newTree.appendChild(ifdNode);
    createTIFFFieldNode(ifdNode, TIFF.TAG_RESOLUTION_UNIT, TIFF.TYPE_SHORT, 2);
    createTIFFFieldNode(ifdNode, TIFF.TAG_X_RESOLUTION, TIFF.TYPE_RATIONAL, new Rational(300));
    createTIFFFieldNode(ifdNode, TIFF.TAG_Y_RESOLUTION, TIFF.TYPE_RATIONAL, new Rational(300));
    metadata.mergeTree(nativeFormat, newTree);

    IIOImage iioimage = new IIOImage(image, null, metadata);
    writer.write(metadata, iioimage, tiffWriteParam);
  } finally {      
    output.close();
  }
} finally {  
  writer.dispose();
}

Solution

  • To prevent ImageIO from creating a disk cached ImageOutputStream, you may invoke the static ImageIO.setUseCache(false). The catch here, is that it will disable disk caching for ImageIO globally, which may not be desirable. In addition, you need to use a ByteArrayOutputStream or other in-memory structure, to actually store the TIFF image data.

    For example:

    ImageIO.setUseCache(false);  // Typically in a static initializer somewhere
    
    ...
    
    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
    try (ImageOutputStream output = ImageIO.createImageOutputStream(bytes)) {
        ... // Write image & meta data
    }
    

    Another option which does not affect ImageIO globally, is to replace the ImageIO.createImageOutputStream(...) call and just create a new MemoryCacheImageOutputStream(..) wrapping a ByteArrayOutputStream to hold the result.

    Example:

    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
    try (ImageOutputStream output = new MemoryCacheImageOutputStream(bytes)) {
        ... // Write image & meta data
    }
    

    A third option (which is likely to be slightly more efficient), is to subclass ImageOutputStreamImpl and implement yourself, using something more fancy, like in-memory ByteChannel or a ByteBuffer as backing. The cool thing about this, is obviously that you can use memory-mapped files or off-heap memory. But it will need some more effort to implement.

    I'll probably go with the second option, unless profiling or otherwise tells you this doesn't perform well enough for you, then investigate option three.