5

I have an image, call it grayscale.jpg. Now I open that image in The Gimp and change the color mode to RGB and save it as color.jpg. If I view grayscale.jpg and color.jpg in any image viewer, they look exactly the same. But if I open the images with javax.imageio.ImageIO

import javax.imageio.ImageIO;

input = ImageIO.read(new File("grayscale.jpg"));
System.out.format("Grayscale value: %x\n", input.getRGB(200, 200));

input = ImageIO.read(new File("color.jpg"));
System.out.format("Color value: %x\n", input.getRGB(200, 200));

The color image will return the correct value, say 0xff6c6c6c. The grayscale image will return a different, lighter, incorrect value like 0xffaeaeae.

Grayscale value: 0xffaeaeae // Incorrect (Lighter)
Color value:     0xff6c6c6c // Correct

In other words, javax.imageio.ImageIO thinks grayscale images are much lighter than they actually are. How can I accurately read grayscale images?

Edit

Here's more context. My users upload images, which may be grayscale. My Java runs on the server and does some pretty complex image processing. So an ideal solution is to just fix my Java code as opposed to cobbling something together with command line tools.

Dave Aaron Smith
  • 4,517
  • 32
  • 37
  • After more digging, this is a duplicate of http://stackoverflow.com/questions/6474753/my-batch-jpg-resizer-works-with-color-images-but-grayscale-ones-become-washed-o – Dave Aaron Smith Dec 20 '11 at 18:42
  • Just confirmed that this bug still exists in Java 8.181, in 2019. BufferedImage.getRGB applies a bizarre transform to the gray byte that makes it up to 30% brighter, while using BufferedImage.getRaster().getPixel() returns the proper color. – MasterHD Jul 12 '19 at 07:05

1 Answers1

-1

Your test are irrelevant because you are using JPEG, which is lossy. Depending on the compression, you might have other color values. So, try the same with PNG, which is lossless.

You can use this image to test the correctness of javax.imageio. Convert this one to grayscale with Gimp and make sure you save it as PNG. Then load both (this one and the converted one) the same way. And compare in a for loop all the colors of the y-axis.

enter image description here

Sample code:

BufferedImage inputGrayscale = ImageIO.read(new File("grayscale.png"));    
BufferedImage inputColor = ImageIO.read(new File("color.png"));

for (int i = 0; i < 256; ++i)
{
    System.out.printf(i + "Grayscale value: %x\n", inputGrayscale.getRGB(10, i));
    System.out.printf(i + "Color value: %x\n", inputColor.getRGB(10, i));
    System.out.println();
}
Martijn Courteaux
  • 67,591
  • 47
  • 198
  • 287
  • 1
    It's not just a compression thing. If I read every pixel and write it out to a file, essentially copying the image pixel by pixel, the copy of the color image will look correct while the copy of the grayscale image will be much lighter than the input file. – Dave Aaron Smith Dec 20 '11 at 17:49
  • Also, see my edit which adds more context. These images are coming from my users and I don't want them to have to worry about .png vs .jpg. They should be able to directly upload whatever their camera outputs. – Dave Aaron Smith Dec 20 '11 at 17:50