Question

I'm trying (In Java) to get the resulting color when I combine 2 colors, the one on top having an alpha transparency. Basically, I'm trying to assign a background color to an image, but I've broken it down to each pixel being changed individually. I've looked at several articles, including this one, to no avail. Does anybody know how to perform this kind of RGBA/RGB color mixing? My current code uses this png:

PNG Image

And produces this JPG:

JPG Image

This is the function that I'm currently using. The background for the demo images was set to full blue, or an int of 255.

public static void PNGToJPEGConvert(String PNGPath, String NewJPEGPath, int BackColor) throws IOException {
    try {
        BufferedImage bufferedImage = ImageIO.read(new File(PNGPath));
        BufferedImage newImage;
        int R1, G1, B1, R2 = (BackColor & 0xFF0000) >> 16, G2 = (BackColor & 0xFF00) >> 8, B2 = (BackColor & 0xFF), W1, W2, W3, M1, M2, R3, G3, B3;
        float br;
        newImage = new BufferedImage(bufferedImage.getWidth(), bufferedImage.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
        for(int x=0; x < bufferedImage.getWidth(); x++) {
            for(int y=0; y < bufferedImage.getHeight(); y++) {
                R1 = BufferedImageGetPixelARGB(bufferedImage, "R", x, y);
                G1 = BufferedImageGetPixelARGB(bufferedImage, "G", x, y);
                B1 = BufferedImageGetPixelARGB(bufferedImage, "B", x, y);
                W1 = Math.min(R1, Math.min(G1, B1));
                W2 = Math.min(R2, Math.min(G2, B2));
                R1 -= W1;
                G1 -= W1;
                B1 -= W1;
                R2 -= W2;
                G2 -= W2;
                M1 = Math.max(R1, Math.max(G1, B1));
                M2 = Math.max(R2, Math.max(G2, B2));
                br = (M1 + M2)/(2*BufferedImageGetPixelARGB(bufferedImage, "A", x, y));
                R3 = (int) ((R1 + R2) * br);
                G3 = (int) ((G1 + G2) * br);
                B3 = (int) ((B1 + B2) * br);
                W3 = (W1 + W2) / 2;
                R3 += W3;
                G3 += W3;
                B3 += W3;
                newImage.setRGB(x, y, RGBValuesToInt(R3, G3, B3));
            }
        }
        try {
            ImageIO.write(newImage, "jpg", new File(NewJPEGPath));
        } catch(Exception e) {

        }
    } catch(Exception e) {

    }
}

Thanks for the help, -Neil

Was it helpful?

Solution

Basically it is

float masking_factor = mask_value/255.0;
composed_value = int(
    source_pixel_value * (1 - masking_factor) + 
    overlay_pixel_value * masking_factor
);

We suppose that all values are 8-bit, that is, 0 to 255, and mask is monochrome. Where mask is completely black, it is fully transparent, and only source pixels are visible. Where mask is completely white, it is fully opaque, and only overlay pixels are visible. Values in between give intermediate opacity.

But if alpha blending is the only thing you want to implement, there are better ways to do it than working with individual pixels. See Graphics2D and its .setComposite() method.

OTHER TIPS

public static Color mixColorsWithAlpha(Color color1, Color color2, int alpha)
{
    float factor = alpha / 255f;
    int red = (int) (color1.getRed() * (1 - factor) + color2.getRed() * factor);
    int green = (int) (color1.getGreen() * (1 - factor) + color2.getGreen() * factor);
    int blue = (int) (color1.getBlue() * (1 - factor) + color2.getBlue() * factor);
    return new Color(red, green, blue);
}

This would be the same as painting color2 (with the given alpha value) over color1.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top