I'm developing my own image editor, and I've run into a bit of a snag. I'm stumped as to how other image editors deal with blending transparent colors together.
Here's how Photoshop and a few other programs do it:
As you can see, it's not a simple mix of the colors! It varies depending on which one you draw over the other.
This is the closest I've been able to approximate so far in my editor. Transparent red and transparent green are drawn correctly, but when I draw green on red I get a really bright green (0.5, 1, 0, 0.75) and when I draw red on green I get a bright orange (1, 0.5, 0, 0.75).
The formula that's gotten me this close is as follows:
pixmap.setBlending(Blending.None);
memtex.pixmap.setBlending(Blending.None);
for(int x = 0; x < width; x++) {
for(int y = 0; y < height; y++) {
int src_color = pixmap.getPixel(x, y);
float src_r = (float)((src_color & 0xff000000) >>> 24) / 255f;
float src_g = (float)((src_color & 0x00ff0000) >>> 16) / 255f;
float src_b = (float)((src_color & 0x0000ff00) >>> 8) / 255f;
float src_a = (float)(src_color & 0x000000ff) / 255f;
int dst_color = memtex.pixmap.getPixel(x, y);
float dst_r = (float)((dst_color & 0xff000000) >>> 24) / 255f;
float dst_g = (float)((dst_color & 0x00ff0000) >>> 16) / 255f;
float dst_b = (float)((dst_color & 0x0000ff00) >>> 8) / 255f;
float dst_a = (float)(dst_color & 0x000000ff) / 255f;
//Blending formula lines! The final_a line is correct.
float final_r = (src_r * (1f - dst_r)) + (dst_r * (1f - src_a));
float final_g = (src_g * (1f - dst_g)) + (dst_g * (1f - src_a));
float final_b = (src_b * (1f - dst_b)) + (dst_b * (1f - src_a));
float final_a = (src_a * 1) + (dst_a * (1f - src_a));
memtex.pixmap.drawPixel(x, y, Color.rgba8888(final_r, final_g, final_b, final_a));
}
}
As you can probably guess, I'm merging one libGDX pixmap down onto another one, pixel by pixel. If you want to blend the pixels, there seems to be no other way to do it, as far as I know.
For the record, the canvas is transparent black (0, 0, 0, 0). Could anyone point out where my formula's gone awry?
float final_r = (src_r * src_a + (dst_r * dst_a * (1f - src_a));
and so on – Mark Setchell