0

The use case I'm investigating is to read a an input image (tif), modify it and write it to an output image (tif) .

I'm looking for a convenient way to ensure that the writer uses the same compression settings etc as the original image. I haven't found a convenient way to achieve this with ImageIO (with JAI plugin) . I tried probing the imageReader.getDefaultReadParam() but it doesn't contain anything of note. The imageReader.getImageMetadata(...) contains info deep inside but the data structure organization is hopeless.

My fallback approach at this time is to use Apache Commons to detect the compression (eg. Imaging.getImageInfo(inputFile).getCompressionAlgorithm()) and logically set the writer compression parameter in ImageIO.

Is there a more elegant way to accomplish this without having to jump through this hoop ?

As an aside, I can't use Apache Commons Imaging exclusively for our image processing task because it doesn't yet completely support some other formats I need eg. writing jpg

Thanks

Vinay B
  • 673
  • 8
  • 21

1 Answers1

2

It seems like the method you are looking for is:

ImageIO.getImageWriter(ImageReader)

From the API doc:

This mechanism may be used to obtain an ImageWriter that will understand the internal structure of non-pixel metadata (as encoded by IIOMetadata objects) generated by the ImageReader. By obtaining this data from the ImageReader and passing it on to the ImageWriter obtained with this method, a client program can read an image, modify it in some way, and write it back out preserving all metadata, without having to understand anything about the structure of the metadata, or even about the image format.

From the documentation, it seems you still have to pass the metadata from the reader to the writer, but at least, you don't have to care about getting the compression (or other) settings from the metadata.

The easiest way to achieve this is probably to do something like:

ImageReader reader;
reader.setInput(input);

IIOImage image = reader.readAll(0, null); // Read image and metadata in one go

doStuffWithImage(image.getRenderedImage()); // Most likely safe to cast to BufferedImage

ImageWriter writer = ImageIO.getImageWriter(reader);
writer.setOutput(output);

ImageWriteParam param = writer.getDefaultWriteParam();

// According to the API doc, the default compressionMode is
// MODE_COPY_FROM_METADATA which is what we want :-)

writer.write(null, image, param); // Don't need stream metadata for TIFF
Harald K
  • 26,314
  • 7
  • 65
  • 111
  • Thanks @haraldK, I tried your suggestion but still have the same issue. Here is a simple code sample that illustrates my point (note the mismatch in compession settings) https://gist.github.com/balamuru/2053a86da79e9fb3711d Output: ` #### input compression: CCITT Group 3 1-Dimensional Modified Huffman run-length encoding. #### in format: TIFF The output settings should match the input settings #### output compression: None #### output format: TIFF ` – Vinay B Oct 12 '14 at 18:34
  • See my (updated) last paragraph. You need to pass the metadata from the reader to the writer (your gist passes `null` as meta data). The easiest is to use `reader.readAll(0, param)`. Obtaining a writer this way only ensures the writer will understand the meta data from the reader. As both can be reused, you need to pass the meta data each time. – Harald K Oct 12 '14 at 18:40
  • Also @haraldK, does your twelvemonkeys port of ImageIO perform my desired operations any faster / more efficiently than the official package : https://github.com/haraldk/TwelveMonkeys . My requirements are resizing & adding simple shapes to the doc (commonly known as document annotations) – Vinay B Oct 12 '14 at 18:46
  • No, sorry. At least not at the moment. I try to make sure my code is as efficient as I can. But, my TIFF reader doesn't fully support meta data, and my TIFF writer is not very sophisticated yet (work in progress...). For TIFF writing you are probably better off using JAI for the time being. PS; It's not a port, it's a completely clean implementation, to avoid all the license issues related to JAI. :-) – Harald K Oct 12 '14 at 19:00
  • Thanks. That worked, I've added an updated gist at https://gist.github.com/balamuru/432f59facb5f3947902d (with a method that mods the image) . The one side effect is that modified file size (out.tif) is smaller than the input.tif (regardless of whether the image is modified or not). I verified via the linux "identify" program that the metadata for the input and output are identical, except the endianness (maybe the program just bindly copied the input metadata to the output, overwriting its real properties). Thoughts ? – Vinay B Oct 12 '14 at 19:43
  • Do the images look identical? Many compression algorithms allows implementors some flexibility, this means it's quite possible that identical data will compress better using one library than another. Also, you only read image (page) 0. Are you sure there's no more pages in the original TIFF? – Harald K Oct 13 '14 at 08:04
  • Solved my last question. The difference in size is probably due to slight differences in the program used to generate the original tif vs the generated tif. TO verify, I used the the generated tif as input to my program and the output it generated was identical in size to the input. Thanks again! – Vinay B Oct 13 '14 at 16:05