I have a method that reads images, converts them (size, format) and writes them back. This always worked very well, but now I've come across some JPEG images (from a Press Agency) that obviously contain some meta-data (IPTC). When converting those images, the colors are all wrong. My first guess was, that those are CMYK images but they are not.
The problem must come from the reading, because it doesn't matter whether I convert the image to a smaller JPEG or a PNG, it always looks the same.
At first, I used ImageIO.read()
to read the image. I now get the actual ImageReader
via ImageIO.getImageReadersByMIMEType()
and tried to tell the reader to ignore meta data by setting the ignoreMetadata
parameter of ImageReader#setInput(Object input, boolean seekForwardOnly, boolean ignoreMetadata)
but had no success.
Then I created a version of the image without the metadata (using Fireworks). That image is converted correctly.
The only difference I could find out, is, that with the not-working image the value of the reader's variable colorSpaceCode
is 2, whilest with the working image, the value is 3. There's also an outColorSpaceCode
which is 2 for both images.
As the source comment of the reader only says Set by setImageData native code callback. A modified IJG+NIFTY colorspace code I'm really stuck now. So any help would be much appreciated.
You can get original image (~3 MB) by going here and clicking download. The left image below shows what I get from the original image, the right shows what it should look like.
I found a solution now, that works, at least if my resulting image is also a JPEG: First I read the image (from byte array imageData), and most important, I also read the metadata.
InputStream is = new BufferedInputStream(new ByteArrayInputStream(imageData));
Image src = null;
Iterator<ImageReader> it = ImageIO.getImageReadersByMIMEType("image/jpeg");
ImageReader reader = it.next();
ImageInputStream iis = ImageIO.createImageInputStream(is);
reader.setInput(iis, false, false);
src = reader.read(0);
IIOMetadata imageMetadata = reader.getImageMetadata(0);
Now i'd do some converting (i.e. shrink in size) ... and at last I'd write the result back as a JPEG image. Here it is most important to pass the metadata we got from the original image to the new IIOImage
.
Iterator<ImageWriter> iter = ImageIO.getImageWritersByMIMEType("image/jpeg");
ImageWriter writer = iter.next();
ImageWriteParam iwp = writer.getDefaultWriteParam();
iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
iwp.setCompressionQuality(jpegQuality);
ImageOutputStream imgOut = new MemoryCacheImageOutputStream(out);
writer.setOutput(imgOut);
IIOImage image = new IIOImage(destImage, null, imageMetadata);
writer.write(null, image, iwp);
writer.dispose();
Unfortunately, if I'd write a PNG image, I still get the wrong colors (even if passing the metadata), but I can live with that.