Java imageio grayscale PNG problem

I have a grayscale image (actually "Lena") and I want to try it out I regard it as 512 × 512 PNG files, 216 kinds of grayscale

What happens when I read it with Java imageio:

String name = args[0];
    File fi = new File(name);
    BufferedImage img = ImageIO.read(fi);

I got a bufferedimage with only 154 colors! I was only aware of this, which led to the rough image and lack of dark black

What's more exciting is that when I use XnView to convert PNG to GIF, in this case, this is a lossless program. Read GIF with the above code, and I get all 216 colors in bufferedimage

Is there a document or description, and what happens when my PNG reads it? Are there any settings to solve this problem? I'm on the latest jdk1 These experiments have been done on 8 It's just that my trust in Java PNG support has been lost. I'll use color PNG later

Solution

Welcome to the "great" world of Java hidden color management!

For Java (at least imageio), all internal content is sRGB, which implies color management, which usually has the opposite effect on what you actually want to do For grayscale images, at least imageio of most readers is used, and at least for grayscale images without embedded ICC profiles (I have not tested other images), Java will automatically "assign" ICC profiles with whitepoint = D50 and gamma = 1.0 I stumbled upon this

Then, when you access pixels (I assume you use img. Getrgb () or something like that?) When, you actually access the sRGB value (Java default color space on Windows)

As a result, when converted to sRGB, the gamma value is ~ 2.2 (the gamma of sRGB is actually a little complex, but generally close to 2.2), which effectively applies the gamma correction of (1 / gamma) = 2.2 to the image, (a) makes your image appear "light", (b) because the gamma correction is from 256 to 256 discrete values, you also effectively loosen some of your gray shadows

If you access bufferedimage data in different ways, you can also see the effect: a) access configuration file:

ColorSpace colorSpace = img.getColorModel().getColorSpace();
if ( colorSpace instanceof ICC_ColorSpace ) {
    ICC_Profile profile = ((ICC_ColorSpace)colorSpace).getProfile();
    if ( profile instanceof ICC_ProfileGray ) {
        float gamma = ((ICC_ProfileGray)profile).getGamma();
        system.out.println("Gray Profile Gamma: "+gamma); // 1.0 !
    }
}

b) Accessing some pixel values differently

//access sRGB values (Colors translated from img's ICC profile to sRGB)
System.out.println( "pixel 0,0 value (sRGB): " + Integer.toHexString(img.getRGB(0,0)) ); // getRGB() actually means "getSRGB()"
//access raw raster data,this will give you the uncorrected gray value
//as it is in the image file
Raster raster = image.getRaster();
System.out.println( "pixel 0,0 value (RAW gray value): " + Integer.toHexString(raster.getSample(0,0)) );

If your pixel (0,0) is not accidental 100% black or 100% white, you will see that the sRGB value is "higher" than the gray value, such as gray = D1 – > sRGB = ffeaea (alpha, red, green, blue)

From my point of view, it will not only reduce your gray level, but also make your image brighter (the same as using gamma correction with a 1 / gamma value of 2.2) It is more logical if Java without a gray image of an embedded ICC profile converts gray to sRGB with r = g = b = grayvalue, or assigns ICC gray profile whitepoint = D50, gamma = 2.2 (at least on Windows) Since sRGB is not exactly gamma 2.2, the latter will still make you lose some gray tones

About why it applies to GIF: gif format has no concept of "grayscale" or ICC profile, so your image is a 256 tone palette image (256 colors are exactly 256 color grayscale) When opening GIF, Java assumes that the RGB value is sRGB

Solution: according to your actual usage, your solution may be to access the grid data of each image pixel (gray = raster.getsample (x, y, 0)) and put it into sRGB image setting r = g = b = gray But there may be a more elegant way

About your trust in Java or PNG: because it has implicit color conversion, I am trying to study java imageio in many aspects Our idea is to build in color management, and developers don't need much knowledge about color management As long as you only use sRGB (and your input is also sRGB, or there is no color profile, so it can be legally considered sRGB), this is effective to a certain extent If there are other color spaces in the input image (such as Adobe RGB), it will start Gray is another matter, especially the (abnormal) gray contour of imageio assuming gamma = 1.0 Now to understand what imageio is doing, you need to know not only your ABC in color management, but also what Java is doing I didn't find this information in any documents! Conclusion: imageio can indeed be considered correct This is usually not what you expect, and you may dig deeper to find out why or change behavior if it's not what you want to do

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>