19
votes

I am trying to automatically change the color for a set of icons. Every icon has a white filled layer and the other part is transparent. Here is an example: (in this case it's green, just to make it visible)

icon search

I tried to do the following:

private static BufferedImage colorImage(BufferedImage image) {
        int width = image.getWidth();
        int height = image.getHeight();

        for (int xx = 0; xx < width; xx++) {
            for (int yy = 0; yy < height; yy++) {
                Color originalColor = new Color(image.getRGB(xx, yy));
                System.out.println(xx + "|" + yy + " color: " + originalColor.toString() + "alpha: "
                        + originalColor.getAlpha());
                if (originalColor.equals(Color.WHITE) && originalColor.getAlpha() == 255) {
                    image.setRGB(xx, yy, Color.BLUE.getRGB());
                }
            }
        }
        return image;
    }

The problem I have is that every pixel I get has the same value:

32|18 color: java.awt.Color[r=255,g=255,b=255]alpha: 255

So my result is just a colored square. How can I achieve to change the color of the non-transparent parts only? And why is it, that all pixels have even the same alpha value? I guess that's my main problem: That the alpha value isn't read correctly.

4

4 Answers

20
votes

Why it doesn't work, I don't know, this will.

This changes all the pixles to blue, maintaining their alpha values...

enter image description here

import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

public class TestColorReplace {

    public static void main(String[] args) {
        try {
            BufferedImage img = colorImage(ImageIO.read(new File("NWvnS.png")));
            ImageIO.write(img, "png", new File("Test.png"));
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    private static BufferedImage colorImage(BufferedImage image) {
        int width = image.getWidth();
        int height = image.getHeight();
        WritableRaster raster = image.getRaster();

        for (int xx = 0; xx < width; xx++) {
            for (int yy = 0; yy < height; yy++) {
                int[] pixels = raster.getPixel(xx, yy, (int[]) null);
                pixels[0] = 0;
                pixels[1] = 0;
                pixels[2] = 255;
                raster.setPixel(xx, yy, pixels);
            }
        }
        return image;
    }
}
15
votes

The problem is, that

Color originalColor = new Color(image.getRGB(xx, yy));

discards all the alpha values. Instead you have to use

 Color originalColor = new Color(image.getRGB(xx, yy), true);

to keep alpha values available.

0
votes

If your bitmap is already set in an ImageView, just do :

imageView.setColorFilter(Color.RED);

to set all non transparent pixels to red.

0
votes

Since we will always be replacing only the first three bands of the RGB pixel, more effective way to achieve the same without unnecessary allocation of new arrays would be:

private static void colorImageAndPreserveAlpha(BufferedImage img, Color c) {
    WritableRaster raster = img.getRaster();
    int[] pixel = new int[] {c.getRed(),c.getGreen(),c.getBlue()};
    for (int x = 0; x < raster.getWidth(); x++) 
        for (int y = 0; y < raster.getHeight(); y++)
            for (int b = 0; b < pixel.length; b++)
                raster.setSample(x,y,b,pixel[b]);    
}