Bouki
Bouki

Reputation: 1359

java background transparent

I have a gif image which contains only a colored shape, and a transparent background.

I would like to replace the shape's color by the one I want (the color pallet for this gif is only 2 colors: transparent and white in my case).

I've created a filter which correctly replace white with red (this is a test).

However I'm encountering an issue with my method imageToBufferedImage, it removes the transparency and replace it with black (don't know why).

So what I've done so far is this:

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.awt.image.FilteredImageSource;
import java.awt.image.ImageFilter;
import java.awt.image.ImageProducer;
import java.awt.image.RGBImageFilter;
import java.io.File;
import javax.imageio.ImageIO;

public class TestPNG {
    
    public static void main(String[] args) throws Exception {

        File in = new File("bg.gif");
        BufferedImage source = ImageIO.read(in);
        int color = source.getRGB(0, 0);

        Image image = makeColorTransparent(source, new Color(color), new Color(255, 0, 0));

        BufferedImage transparent = imageToBufferedImage(image);

        File out = new File("bg2.gif");
        ImageIO.write(transparent, "gif", out);

    }

    private static BufferedImage imageToBufferedImage(Image image) {
        BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2 = bufferedImage.createGraphics();
        //g2.setBackground(Color.blue);
        g2.clearRect(0, 0, 200, 40);
        g2.drawImage(image, 0, 0, null);
        g2.dispose();
        return bufferedImage;
    }

    public static Image makeColorTransparent(BufferedImage im, final Color search, final Color replace) {
        ImageFilter filter = new RGBImageFilter() {
                public final int filterRGB(int x, int y, int rgb) {
                        if (rgb == search.getRGB()) {
                            return replace.getRGB();
                        } else {
                            return rgb;
                        }
                }
        };
        ImageProducer ip = new FilteredImageSource(im.getSource(), filter);
        return Toolkit.getDefaultToolkit().createImage(ip);
    }

}

Upvotes: 5

Views: 8235

Answers (5)

Tatarize
Tatarize

Reputation: 10796

You clear out the pixels with the use of a composite. You can't just paint transparent pixels over other pixels or any of that trash. The Porter-Duff rules are clear, doing any of that will cause pixels to mix according to the composite rule. So just change, the rule clear the pixels.

The problem is most of the solutions are trying to coax the image into getting the pixels you want at the end, using the rule. Change the rule for a second and everything gets way easier.

Composite composite = g.getComposite();

g.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR));
g.fillRect(0, 0, bufferedimage.getWidth(), bufferedimage.getHeight());

g.setComposite(composite);

That will clear a graphics object of the current pixels. Then just paint back on what you want. My example restored the previous composite as you'll be surprised how often that stuff goes weird, this way you just get cleared pixels and can start over without changing anything with the graphics context.

Upvotes: 0

Nulano
Nulano

Reputation: 1333

There are 3 problems in your code:

1) Replace

Image image = makeColorTransparent(source, new Color(color), new Color(255, 0, 0));

with

Image image = makeColorTransparent(source, color, new Color(255, 0, 0));

and

public static Image makeColorTransparent(BufferedImage im, final Color search, final Color replace) {
...
if (rgb == search.getRGB()) {
...
}

with

public static Image makeColorTransparent(BufferedImage im, final int search, final Color replace) {
...
if (rgb == search) {
...
}

BECAUSE for some reason, the source.getRGB(0, 0) ignores alpha value and it becomes white ((255, 255, 255, 0) becomes (255, 255, 255, 255))

2) You can't use int color = source.getRGB(0, 0), because it uses the color of first pixel (transparent). You should use some other code (like asking for the color in console) to find out what pixel's color to store in int color

3) You are clearing the color of BufferedImage bufferedImage in imageToBufferedImage(...) with Color.BLACK (default). Replace //g2.setBackground(Color.blue); with g2.setBackground(new Color(0, 0, 0, 0)); or remove the g2.clearRect(...);

Upvotes: 2

camickr
camickr

Reputation: 324118

Just guessing:

a) Maybe you don't need the clearRect(...) method.

b) Maybe you can use something like:

g2.setColor(new Color(0, 0, 0, 0));
g2.fillRect(...);

Upvotes: 0

Mark Peters
Mark Peters

Reputation: 81074

You have this:

    g2.drawImage(image, 0, 0, null);

From the Javadoc for this method:

Transparent pixels in the image do not affect whatever pixels are already there.

Since you cleared your image, filling it with the background colour, the pixels are already black so they stay black.

Try

g2.setBackground(new Color(0, 0, 0, 0) );
g2.clearRect(0, 0, 200, 40);

before painting your image.

Upvotes: 0

Thomas
Thomas

Reputation: 88707

Sure your image supports an alpha channel? Tried drawing a non-black full size rectangle into bufferedImage first?

Upvotes: 0

Related Questions