PNG Transparency error

Hello, I got a PNG image in my game ->

http://img211.imageshack.us/img211/4742/effectquestgate10sb3.png

When it is rendered in java, it appears like this:

http://img381.imageshack.us/img381/6696/glitcheddb3.jpg

Why is that? It also looks like that in paint, but in windows explorer it looks fine…

Thank you in advance.

It would help if you were to show us the code you’re using…

Anyway, mspaint only supports bitmask transparency, i.e. either a pixel is 100% transparent or it is 100% visible. The java code you are using is probably loading this image with bitmask transparency… you need to be using “translucent” transparency…

Loading an image with ImageIO usually does this automatically for you. This code shows the image correctly:


import javax.imageio.*;
import javax.swing.*;
import java.awt.image.*;
import java.awt.*;
import java.io.*;
class ImgPanel extends JPanel {
	BufferedImage img;
	public ImgPanel() {
		img = null;
		try {
			img = ImageIO.read(getClass().getResource("swirl.png"));
		}
		catch (IOException e) {
			e.printStackTrace();
		}
		setPreferredSize(new Dimension(img.getWidth(),img.getHeight()));
	}
	public void paintComponent(Graphics g) {
		/* draw red rectangle to show transparency works */
		g.setColor(Color.red);
		g.fillRect(0,0,getWidth(),getHeight());

		g.drawImage(img,0,0,null);
	}
}
public class Test extends JFrame {
	public Test() {
		super("Test");
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		getContentPane().add(new ImgPanel());
		pack();
		setVisible(true);
	}
	public static void main(String args[]) {
		new Test();
	}
}

The Transparency class outlines the different transarency options for Images

Here’s a very useful png examining utility - so you know exactly what your paint tool is outputing.

http://entropymine.com/jason/tweakpng/

Ok, I load it using this :


    public Picture(URL $locator) {
        img = p.getToolkit().createImage($locator);
        x = img.getWidth(null)/2;
        y = img.getHeight(null)/2;
        img = ImageTransparencyTransformer.getInstance().filter(img);
    }

Yeah don’t use that. Instead:


public Picture(URL $locator) {
        img = ImageIO.read(@locator);
        x = img.getWidth()/2;
        y = img.getHeight()/2;
    }

ImageIO will return a BufferedImage, so instead of storing an Image, store a BufferedImage.

Okay Demonpants, I will try that :smiley:

Oops @locator should be $locator, that’s a typo. Just whatever the String/URL reference to your image file is. :slight_smile:

Hmm, one more question, how do I read it from an InputStream? I tried ImageIO.read(stream) but it reads it with bitmask transparency.

I use this but doesn’t work.


        BufferedImage bi = null;
        try {
            bi = ImageIO.read(this.getClass().getClassLoader().getResourceAsStream("renoria/" + key));
        } catch (IOException ex) {
            Logger.getLogger(ImageLoader.class.getName()).log(Level.SEVERE, null, ex);
        }

Thanks.

That should work. What sort of image are you loading? You can also try to draw the image into a new BufferedImage.


BufferedImage temp = ImageIO.read(...);
BufferedImage useableImage = new BufferedImage(temp.getWidth(),temp.getHeight(),BufferedImage.TYPE_INT_ARGB);
Graphics2D g = useableImage.getGraphics();
g.drawImage(temp,0,0,null);
g.dispose();

After you do that, useableImage will contain the image from the file but it will be TYPE_INT_ARGB, which will have “cleaner” alpha access.

Ahh yes I found the error, the filter was returning an opaqe pixel, I fixed it now :smiley: Thanks everyone!

Your code example assumes the pixels of the newly constructed BufferedImage are initialised to 0x00000000, an assumption you would expect to be safe. However as far as i’m aware the BufferedImage javadoc makes no such guarantee, and I know of atleast 1 Apple VM release that did not conform to this assumption. (it initialised the pixels to an opaque grey)

So for completeness you should set the compositing rule so as to only use the alpha component of the source. (see above quoted code)

yeah I found the error, I had to change


    public int filterRGB(int x, int y, int rgb) {
        int r = (rgb >> 16) & 0xFF;
        int g = (rgb >> 8) & 0xFF;
        int b = (rgb) & 0xFF;
        if (r == 255 && g == 21 && b == 255) {
            return 0x00000000;
        }
        return 0xff000000 | r >> 16 | g >> 8 | b;
    }

to:


    public int filterRGB(int x, int y, int rgb) {
        int r = (rgb >> 16) & 0xFF;
        int g = (rgb >> 8) & 0xFF;
        int b = (rgb) & 0xFF;
        if (r == 255 && g == 21 && b == 255) {
            return 0x00000000;
        }
        return rgb;
    }

Thanks alot guys, it was my own fault :smiley:

Huh that’s interesting. I’ve never encountered that not working but it’s good to know.

I’m pretty sure its because

0xFF000000

Alpha/Red/Green/Blue

Then FF means fully opque alpha.

Had to change it so it returned the same value as the one inputted.

BufferedImages are guaranteed to be initialized with 0s (even if the spec doesn’t say it), they are backed by java arrays - at least in Sun implementation. I would bet that that Apple bug that had BIs initialized to gray (could you give a link to the report?) was pre-1.5, which is for all intended purposes long gone…

Dmitri

It was indeed a looooong time ago - someone reported it as a bug against something i’d written, can’t remember what it was, or even if it was on this forum! (might have been on the Sun forums)

I’ll have a quick hunt for it.

Had a search & couldn’t find it.

Incidentally, while your implicit guarantee that the DataBuffer will be initialized to zeros is good to know, it doesn’t catch all scenarios.

One situation is when a value of 0 in the DataBuffer doesn’t translate to the pixel being considered transparent black.
e.g.


BufferedImage bi = new BufferedImage(400,400, BufferedImage.TYPE_BYTE_INDEXED, new IndexColorModel(8, 2, new byte[] {0x7F,0,0,0x7F,0,0,0,0},0,true));

I admit it’s a rather contrived example :wink:

Well I’ve been assuming it’s transparent and never had a problem reported by anyone playing my game. And because I always used TYPE_INT_ARGB I don’t see that there will be a problem.

I didn’t say that the image will be initialized to transparent pixel, I said it will be init-ed with 0s. What 0 means obviously depends on the color model.

For INT_ARGB it means that pixels are transparent.

Dmitri