2017-04-26 176 views
0

我正在开发自己的图像编辑器,并且遇到了一些障碍。我很难理解其他图像编辑器如何处理混合透明颜色。混合透明颜色

这里的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)。任何人都可以指出我的配方出错了吗?

+0

我认为它更像'浮final_r =(src_r * src_a +(dst_r * dst_a *(1F - src_a));'等等 –

+0

@MarkSetchell的(1,0,0,0.5)导致(0.5,0,0,0.5)被提交到画布,并且在连续的绘制操作中它保持不变将这些像素的R值减半Pic:http://i.imgur.com/eFS5FXt.png –

+0

再次从HSB的角度来看这个,在第二幅图像中,颜色的色调和饱和度是正确的!唯一不正确的组件就是亮度。还没有想出h将这个因素纳入公式中...... –

回答

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

没有首先计算最终α和它划分,颜色会得到越来越暗的连续战平操作,因为即使(0,0,0,0)被吸引到他们”的像素d通过将它们的RGB乘以它们的α来反复地使它们变暗。

最终结果:

Final result

+0

干得好!并感谢您与社区分享。您可以也应该接受您自己的答案,只要点击投票计数旁边的空白勾号/复选标记即可。 –

+0

@MarkSetchell会做!有一段时间,直到我可以接受它为止(还剩20小时),所以我会设置提醒。 –