Colour->Grayscale conversion failure using ColorConvertOp on Mustang

Hi,

Here is what I want to do: I have a color BufferedImage, and I want to convert it to a grayscale one. The original image is stored as a PNG. I came up with the following code fragment (I use the Sixlegs PNG library to load PNG files, as it appears that ImageIO sometimes fails to load some of them):


BufferedImageOp operation = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
BufferedImage my_icon;
BufferedImage my_disabled_icon;

(...)

try
{
    my_icon = new PngImage().read(new File("duke.png"));
    my_disabled_icon = operation.filter(my_icon, null);
}
catch (IOException e)
{
    (...)
}

my_icon indeed contains a valid Image - I verified this by blitting the content of my_icon on screen.
OTOH, my_disabled_icon triggers a NullPointerException with Java Mustang (build 94) at the operation.filter() line. A typical Exception trace starts with:


java.lang.NullPointerException
        at java.awt.image.ColorConvertOp.filter(ColorConvertOp.java:238)

I am puzzled by this - did I forget anything, or is that a bug I inadvertantly jumped on ?
Also, maybe there’s another, better way to generate a grayscale image from a coloured one ?

Well, the NPE is thrown on the first line that references the source
image. So it looks like you’re passing a null image.

Print out my_icon just before calling filter(), and provide a full
stack trace.

Does this happen on JDK 6 only?

You don’t have some multithreading going on by any chance?
May be it gets nulled out after the assignment but before filter()?

Thanks,
Dmitri
Java2D Team

My apologizes, I obviously copied the wrong stack trace - you’ll find the correct one below.

I used the following piece of code:


        (...)
        BufferedImageOp operation = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
        try
        {
            System.out.println("BEFORE:"+my_icon);
            my_disabled_icon = operation.filter(my_icon, null);
        }
        catch (Exception e)
        {
            e.printStackTrace();
            System.out.println("AFTER :"+my_icon);
        }

And got the following results:


my_icon BEFORE:BufferedImage@5aaa4bf8: type = 0 ColorModel: #pixelBits = 16 numComponents = 2 color space = java.awt.color.ICC_ColorSpace@6261b548 transparency = 3 has alpha = true isAlphaPre = false ByteInterleavedRaster: width = 32 height = 32 #numDataElements 2 dataOff[0] = 0

java.lang.NullPointerException
        at java.awt.image.ComponentColorModel.getDataElements(ComponentColorModel.java:1538)
        at sun.awt.image.PixelConverter.rgbToPixel(PixelConverter.java:39)
        at sun.java2d.loops.SurfaceType.pixelFor(SurfaceType.java:400)
        at sun.java2d.SurfaceData.pixelFor(SurfaceData.java:691)
        at sun.java2d.SunGraphics2D.validateColor(SunGraphics2D.java:1646)
        at sun.java2d.SunGraphics2D.<init>(SunGraphics2D.java:242)
        at sun.java2d.SunGraphicsEnvironment.createGraphics(SunGraphicsEnvironment.java:349)
        at java.awt.image.BufferedImage.createGraphics(BufferedImage.java:1137)
        at java.awt.image.ColorConvertOp.ICCBIFilter(ColorConvertOp.java:317)
        at java.awt.image.ColorConvertOp.filter(ColorConvertOp.java:262)

        (... the rest of the stack is the app-specific location of the error, which is the convert() line.)

my_icon AFTER :BufferedImage@5aaa4bf8: type = 0 ColorModel: #pixelBits = 16 numComponents = 2 color space = java.awt.color.ICC_ColorSpace@6261b548 transparency = 3 has alpha = true isAlphaPre = false ByteInterleavedRaster: width = 32 height = 32 #numDataElements 2 dataOff[0] = 0

I indeed get no error with a JDK 1.5.0-07. Actually, I didn’t seem to get that error with an earlier version of the JDK (I think the last one I used before b94 was b85).

Although there is multithreading in the application, there is no modification possible in that block, as there’s only one thread that access it, so it isn’t an issue.

This looks like a regression in JDK 6.
One possible cause is the following fix integrated into b92:
6279846: Pixel values are different when source and dest ColorSpace supplied to ColorConvertOp are same
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6279846

I will let the responsible engineer know, and file a bug.
Thanks a lot for the report!

Could you post the image you’re loading? Just in case it’s specific to the image.

Thank you,
Dmitri
Java2D Team

Thanks a lot for your help ! Here are two images that triggered the bug on my system:

http://www.ailesse.be/plt_coin.111.png

http://www.ailesse.be/silvercoin.111.png

Hm… I can’t seem to reproduce this. There must be a difference in how you load the images.
Here’s my code (coin1,2.png are the image files you posted):


import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ColorConvertOp;
import java.io.File;
import javax.imageio.ImageIO;

public class GrayImageTest {
    public static void main(String[] args) {
        BufferedImageOp operation = 
            new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
        try {
            BufferedImage my_icon1 = ImageIO.read(new File("coin1.png"));
            BufferedImage my_icon2 = ImageIO.read(new File("coin2.png"));
            System.out.println("my_icon1="+my_icon1);
            System.out.println("my_icon2="+my_icon2);
            BufferedImage my_disabled_icon1 = operation.filter(my_icon1, null);
            BufferedImage my_disabled_icon2 = operation.filter(my_icon2, null);
            System.out.println("my_disabled_icon1="+my_disabled_icon1);
            System.out.println("my_disabled_icon2="+my_disabled_icon2);
        } catch (Exception e) {
            e.printStackTrace();
        }      
    }
}

It works fine on java 6 and java 5:


[tdv@nukite:] -< /tmp/scratch >
#>java GrayImageTest
my_icon1=BufferedImage@5e5a50: type = 13 IndexColorModel: #pixelBits = 8 numComponents = 4 color space = java.awt.color.ICC_ColorSpace@7b6889 transparency = 2 transIndex   = 0 has alpha = true isAlphaPre = false ByteInterleavedRaster: width = 32 height = 32 #numDataElements 1 dataOff[0] = 0
my_icon2=BufferedImage@c2ff5: type = 13 IndexColorModel: #pixelBits = 8 numComponents = 4 color space = java.awt.color.ICC_ColorSpace@7b6889 transparency = 2 transIndex   = 6 has alpha = true isAlphaPre = false ByteInterleavedRaster: width = 32 height = 32 #numDataElements 1 dataOff[0] = 0
my_disabled_icon1=BufferedImage@c832d2: type = 0 ColorModel: #pixelBits = 16 numComponents = 2 color space = java.awt.color.ICC_ColorSpace@181edf4 transparency = 3 has alpha = true isAlphaPre = false ByteInterleavedRaster: width = 32 height = 32 #numDataElements 2 dataOff[0] = 0
my_disabled_icon2=BufferedImage@1808199: type = 0 ColorModel: #pixelBits = 16 numComponents = 2 color space = java.awt.color.ICC_ColorSpace@16df84b transparency = 3 has alpha = true isAlphaPre = false ByteInterleavedRaster: width = 32 height = 32 #numDataElements 2 dataOff[0] = 0
[tdv@nukite:] -< /tmp/scratch >
#>java -version
java version "1.5.0_04-ea"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_04-ea-b01)
Java HotSpot(TM) Server VM (build 1.5.0_04-ea-b01, mixed mode)
[tdv@nukite:] -< /tmp/scratch >
#>java6 GrayImageTest
my_icon1=BufferedImage@b1c260: type = 12 IndexColorModel: #pixelBits = 4 numComponents = 4 color space = java.awt.color.ICC_ColorSpace@503429 transparency = 2 transIndex   = 0 has alpha = true isAlphaPre = false BytePackedRaster: width = 32 height = 32 #channels 1 xOff = 0 yOff = 0
my_icon2=BufferedImage@1908ca1: type = 13 IndexColorModel: #pixelBits = 8 numComponents = 4 color space = java.awt.color.ICC_ColorSpace@503429 transparency = 2 transIndex   = 6 has alpha = true isAlphaPre = false ByteInterleavedRaster: width = 32 height = 32 #numDataElements 1 dataOff[0] = 0
my_disabled_icon1=BufferedImage@ab853b: type = 0 ColorModel: #pixelBits = 16 numComponents = 2 color space = java.awt.color.ICC_ColorSpace@1bd0dd4 transparency = 3 has alpha = true isAlphaPre = false ByteInterleavedRaster: width = 32 height = 32 #numDataElements 2 dataOff[0] = 0
my_disabled_icon2=BufferedImage@b82368: type = 0 ColorModel: #pixelBits = 16 numComponents = 2 color space = java.awt.color.ICC_ColorSpace@137c60d transparency = 3 has alpha = true isAlphaPre = false ByteInterleavedRaster: width = 32 height = 32 #numDataElements 2 dataOff[0] = 0
[tdv@nukite:] -< /tmp/scratch >
#>java6 -version
java version "1.6.0-rc"
Java(TM) SE Runtime Environment (build 1.6.0-rc-b96)
Java HotSpot(TM) Server VM (build 1.6.0-rc-b96, mixed mode)

How are you loading the images?

Thanks,
Dmitri
Java2D Team

Also, the images could have been somehow converted when you uploaded them.
Could you please send them to me directly: tdv at sun dot com ?

Thanks,
Dmitri