混合透明颜色
Blending transparent colors
我正在开发自己的图像编辑器,但 运行 遇到了一些麻烦。我对其他图像编辑器如何处理将透明颜色混合在一起感到困惑。
以下是 Photoshop 和其他一些程序的处理方式:
如你所见,这不是简单的颜色搭配!它会因您将哪一个画在另一个之上而有所不同。
这是迄今为止我在编辑器中能够得到的最接近的值。透明的红色和透明的绿色绘制正确,但是当我在红色上绘制绿色时,我会得到非常亮的绿色 (0.5, 1, 0, 0.75),当我在绿色上绘制红色时,我会得到亮橙色 (1, 0.5, 0, 0.75).
让我如此接近的公式如下:
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 像素图逐个像素地合并到另一个像素图上。如果你想混合像素,据我所知似乎没有其他方法可以做到。
郑重声明,canvas 是透明的黑色 (0, 0, 0, 0)。谁能指出我的公式哪里出了问题?
感谢 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,它们自己变得更暗。
最终结果:
我正在开发自己的图像编辑器,但 运行 遇到了一些麻烦。我对其他图像编辑器如何处理将透明颜色混合在一起感到困惑。
以下是 Photoshop 和其他一些程序的处理方式:
如你所见,这不是简单的颜色搭配!它会因您将哪一个画在另一个之上而有所不同。
这是迄今为止我在编辑器中能够得到的最接近的值。透明的红色和透明的绿色绘制正确,但是当我在红色上绘制绿色时,我会得到非常亮的绿色 (0.5, 1, 0, 0.75),当我在绿色上绘制红色时,我会得到亮橙色 (1, 0.5, 0, 0.75).
让我如此接近的公式如下:
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 像素图逐个像素地合并到另一个像素图上。如果你想混合像素,据我所知似乎没有其他方法可以做到。
郑重声明,canvas 是透明的黑色 (0, 0, 0, 0)。谁能指出我的公式哪里出了问题?
感谢 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,它们自己变得更暗。
最终结果: