This discussion is archived
4 Replies Latest reply: Feb 20, 2012 9:30 AM by Maxideon RSS

Translucent grayscale png image looks washed out - brightness change

917116 Newbie
Currently Being Moderated
Hi!
I'm having trouble with translucent grayscale png images. These images are coming from a GetMap-request (request for an image) to a geoserver, and I'm trying to understand why they behave like they do.
The thing is I have to make several image-requests like this - both color and grayscale images - and draw them all together on a new BufferedImage. But as soon as I do this with one of these grayscale images they become washed out. I have a simple code example to illustrate:
public static void main(String[] args) throws IOException {
     String aFilename = "ortosvsweref99", aSuffix = "png";
     BufferedImage aSrcImage = ImageIO.read(new File(aFilename + "." + aSuffix));
     BufferedImage aDestImage = new BufferedImage(aSrcImage.getWidth(null), aSrcImage.getHeight(null), BufferedImage.TYPE_INT_RGB);
     Graphics2D aDestGraphics = aDestImage.createGraphics();
     aDestGraphics.drawImage(aSrcImage, 0, 0, null);
// Use aDestGraphics to draw other images to aDestImage here...
     ImageIO.write(aSrcImage, aSuffix, new FileOutputStream("testSrc." + aSuffix));
     ImageIO.write(aDestImage, aSuffix, new FileOutputStream("testDest." + aSuffix));
}
An image example can be downloaded here: http://img214.imageshack.us/img214/5853/ortosvsweref99.png
Using this as input, you can see that testDest.png looks different from testSrc.png.

The things I've singled out that differs from when I load other images that are drawn correctly are these:
aSrcImage.getType() returns BufferedImage.TYPE_CUSTOM
aSrcImage.getColormodel().getTransparency() returns ColorModel.TRANSLUCENT
aSrcImage.getColormodel().getColorSpace().getType() ColorSpace.TYPE_GRAY

I've tried this example with both java-1.6.0.26 and jdk1.7.0_01 getting the same results. Anyone got an educated guess as to what's going on? Is it the TYPE_CUSTOM that causes the problem, or is it something else completely?

Best regards,
/Johan Lindbergh
  • 1. Re: Translucent grayscale png image looks washed out - brightness change
    morgalr Explorer
    Currently Being Moderated
    I have the same type of problem on my Ubuntu instance when I go to borderless/pixel by pixel transparency. I do not have that problem in Windows 7, nor do I have the condition happen in either install with a boardered JFrame. This suggests to me that I have a driver incompatibility with pixel by pixel (boarderless) transparencies.
  • 2. Re: Translucent grayscale png image looks washed out - brightness change
    Maxideon Explorer
    Currently Being Moderated
    When going from a non-sRGB color space to an sRGB one, the ColorConvertOp class does a slight gamma alteration. This causes the image to come out 'brighter' then expected.

    Under most circumstances the underlying drawing routines don't do this gamma alteration. However, TYPE_CUSTOM images can cause the routines to simply call getRGB() to draw, which in turn does the same gamma alteration.

    A workaround is that anytime you detect a gray+alpha TYPE_CUSTOM image then do the image conversion manually, like so:
    BufferedImage src = //TYPE_CUSTOM gray/alpha image
     
    //keep the alpha
    BufferedImage dst = new BufferedImage(src.getWidth(),
            src.getHeight(),BufferedImage.TYPE_4BYTE_ABGR);
    
    Raster srcRaster = src.getRaster();
    WritableRaster dstRaster = dst.getRaster();
    int[] gray = null, alpha = null;
    int w = srcRaster.getWidth();
    for(int y = 0; y < src.getHeight(); y++) {
        gray  = srcRaster.getSamples(0,y,w,1,0,gray);
        alpha = srcRaster.getSamples(0,y,w,1,1,alpha);
    
        dstRaster.setSamples(0,y,w,1,0,gray);
        dstRaster.setSamples(0,y,w,1,1,gray);
        dstRaster.setSamples(0,y,w,1,2,gray);
        dstRaster.setSamples(0,y,w,1,3,alpha);
    }
    
    //don't keep the alpha
    BufferedImage dst = new BufferedImage(src.getWidth(),
            src.getHeight(),BufferedImage.TYPE_BYTE_GRAY);
    int row[] = null;
    for(int y = 0; y < dst.getHeight(); y++) {
        dst.getRaster().setSamples(0,y,dst.getWidth(),1,0,
                src.getRaster().getSamples(0,y,src.getWidth(),1,0,row));
    }
    There are more efficient ways to do the ABGR case, but that's the gist of it.
  • 3. Re: Translucent grayscale png image looks washed out - brightness change
    917116 Newbie
    Currently Being Moderated
    Thank you Maxideon, your post was really helpful!
    I tried writing directly to the destination image raster as you suggested, and it works perfectly!

    I actually tried earlier using an explicit ColorConvertOp in the drawImage call, going from TYPE_GRAY and/or CS_GRAY to TYPE_LINEAR_RGB and/or CS_sRGB but didn't get the expected image contrast. This is probably also as you say because it does a bit of gamma alteration. The question that pops up in my head then is: why? Is this a bug in Java? Or is this gamma alteration needed in other cases?

    Thanks again Maxideon!
  • 4. Re: Translucent grayscale png image looks washed out - brightness change
    Maxideon Explorer
    Currently Being Moderated
    My familiarity with this problem comes from trying to color convert CMYK jpeg images. Using the ColorConvertOp class the images would come out brighter then compared to other image editing software. It turned out that the ColorConvertOp class was treating ICC_Profiles with class 'output' as always having a rendering intent of 'relative colorimetric', instead of 'perceptual' (line #383). I don't know enough about color conversions nor profiles to know if this a bug with the ColorConvertOp class or if the profiles shouldn't be of class 'output.'

    The fix was to change the profile's class to 'display' before doing the conversion. But then someone noted that the fix doesn't work for gray custom format BufferedImages as you can get from the png format. Indeed I don't know why it doesn't work for gray images, nor do I know if the gamma correction is technically correct or not. All I know is that the fix for that particular case is to simply copy the raster. I've tried to find a single workaround that would satisfy both CMYK images and gray images, hoping that would get to the heart of the matter, but I've not found one.

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points