2017-04-26 182 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小時),所以我會設置提醒。 –