混合透明色

时间:2017-04-26 06:37:57

标签: image-processing colors libgdx photoshop image-editing

我正在开发自己的图像编辑器,而且我遇到了一些障碍。我对其他图像编辑器如何处理将透明色混合在一起感到难过。

以下是Photoshop和其他一些程序的用法:

Colors in Photoshop

正如您所看到的,它不是简单的颜色组合!它取决于你在另一个上绘制的那个。

这是我在编辑器中迄今为止能够近似的近似值。正确绘制透明的红色和透明绿色,但是当我在红色上绘制绿色时,我得到一个非常亮的绿色(0.5,1,0,0.75),当我在绿色上绘制红色时,我得到一个明亮的橙色(1,0.5,0, 0.75)。

Colors in my editor

让我这么接近的公式如下:

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));
    }
}

正如你可能猜到的那样,我将一个libGDX像素图逐个像素地合并到另一个像素图上。如果你想混合像素,据我所知,似乎没有其他方法可以做到这一点。

对于记录,画布是透明黑色(0,0,0,0)。谁能指出我的公式出错了?

1 个答案:

答案 0 :(得分:1)

感谢Mark Setchell让我指向了正确的方向!

这是最终代码,源自alpha blending formulas on Wikipedia

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;
        if(src_a == 0) continue; //don't draw if src color is fully transparent. This also prevents a divide by zero if both src_a and dst_a are 0.

        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! All lines are now correct.

        //we need to calculate the final alpha first.
        float final_a = src_a + dst_a * (1 - src_a);

        float final_r = ((src_r * src_a) + (dst_r * dst_a * (1f - src_a))) / final_a;
        float final_g = ((src_g * src_a) + (dst_g * dst_a * (1f - src_a))) / final_a;
        float final_b = ((src_b * src_a) + (dst_b * dst_a * (1f - src_a))) / final_a;

        memtex.pixmap.drawPixel(x, y, Color.rgba8888(final_r, final_g, final_b, final_a));
    }
}

如果不首先计算最终的alpha并除以它,在连续的绘制操作中颜色会变得更暗和更暗,因为即使(0,0,0,0)被绘制到像素,它们也会变得更暗通过将它们的RGB乘以一遍又一遍的alpha。

最终结果:

Final result