tags:

views:

1087

answers:

4

When I read certain JPG files, colors are flattened. Here is a simple example that reads a jpg and just writes the same image to another file.

import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;

public class JPegReadTest {
    public static void main(String[] args) {
        if (args.length == 2) {
            try {
                BufferedImage src = ImageIO.read(new File(args[0]));
                ImageIO.write(src, "jpg", new File(args[1]));
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            System.err.println("Usage: java JPegReadTest src dest");
        }
    }
}

If you try this with for example http://www.flickr.com/photos/visualpanic/233508614/sizes/l/ , the colors of the destination image differ from the source file. Why is that? How to fix it?

Also tried saving the image as png, but the colors are bland in it too (so assuming color info is not read properly).

+4  A: 

It could be several reasons.

  1. JPEG color data is often stored as YCrCb instead of RGB, although conversions should be mostly unnoticeable.
  2. JPEG often has an embedded color profile, but many applications do not understand this and simply ignore it (in which case, your output file might be missing the color profile).
  3. Gamma value could be reset or missing after Java mangles it.

I didn't actually try your example... could you please post both before and after files? Without actually being able to examine the result file, it's hard to tell if this extra data is there or not.

Edit: Yeah, it's clear that your original and converted images have different color profiles. Java stripped out the original's color profile and used generic sRGB instead. They look the same to us on Windows with Firefox and assorted programs because these programs don't use the color profile when renderer. However, on your Mac, Mac actually supports these color profiles (cue debate over Macs for graphics, etc.) and so they render differently. I don't have a Mac handy, but I suspect that if you open the files in Photoshop on any platform, you'll see the difference.

erjiang
Ok, here are the before and after files.http://terokinnunen.jalbum.net/Colortest/orig.jpghttp://terokinnunen.jalbum.net/Colortest/converted-jpg.jpgAlso tried saving as png, still blandhttp://terokinnunen.jalbum.net/Colortest/converted-png.png
ketorin
Interesting: for me (Ubuntu 9.04, Firefox 3.5/Gimp) the original and converted look pretty much the same (modulu JPEG artifacts). The only difference that I can find with GIMP is that the original specifies "sRGB IEC61966-2.1" as the color space, while the converted has "sRGB built-in".
Joachim Sauer
They do? Indeed interesting. For me (Mac and Safari or Firefox) the colors are notably different in converted ones. I also checked with Windows and to my surprise they also do look pretty much the same, only a slight difference.
ketorin
My theory is that the differences lies the following two: 1.) do the environment in question handle color profiles at all? 2.) what color profiles for monitor/image/output device are configured?
Joachim Sauer
Yes, I think we have the root cause, the lost color profile info! This was so unexpected that I'd be happy to formulate this to a good stackoverflow question-answer pair. So, in my opinion, a proper response should include code how to preserve the required info. I tried following instructions here: http://forums.java.net/jive/message.jspa?messageID=205964 , but did not succeed at least yet.
ketorin
Also, Mac uses different default gamma than Windows and Linux, would that explain this? Snow Leopard will change the default gamma, see http://www.appleinsider.com/articles/08/10/25/new_snow_leopard_seed_leak_confirms_cocoa_finder_more.html
ketorin
@ketorin: you asked "why", not "how to avoid this problem". Since you find the answer is good (and I agree), you should accept this answer. And perhaps ask another question about the "how"... :-)
PhiLho
A: 

jpeg is a lossy format. When read in, java stores it as a raw format much like an BMP. Then it's being written out again causing data loss. Also, there isnt much control over the quality like when using something like GIMP.

Maybe look into using other APIs like Image Magick to give you more control over quality.

Nick
Irrelevant. OP is pointing out a significant color-profile issue beyond mere recompression.
erjiang
A: 

JPEG is a lossy format.

That means that if you open a file and save it again you will lose some information unless you take very specific steps not to lose any (in which case the possible manipulations are very restricted).

Additionally ImageIO.write() probably uses some default quality settings for saving JPEG files, which might be lower than the original, which would lead to an additional loss of quality.

Try saving to a PNG file and you'll see that it will look the same as the source.

Joachim Sauer
I tried saving to png, but it also looks bland in color, the same as jpg saved image. I have a hunch that the colors are not even read properly.
ketorin
In that case the problem might be that some color profile is stored in the image that Java doesn't read/interpret.
Joachim Sauer
+2  A: 

Perhaps your source image has an assigned color profile with a gamut wider than sRGB (like Adobe RGB), and your load/save cycle isn't preserving the colorspace information? With no color profile, your viewer will assume sRGB, and the compressed gamut will make everything look "blah". If you have exiftool,

exiftool -ProfileDescription filename.jpg

is a quick way to verify the color profiles on your source and output images.

hobbs
ketorin
Oops, that was wrong thread: http://forums.java.net/jive/message.jspa?messageID=205964
ketorin