带 Alpha 通道的色彩叠加问题

作者头像
周骅 , 
• 951个字 • 4分钟读完
hero

css3 的 rgba 色彩模式、png/gif 图片的 alpha 通道、canvas 的 rgba 色彩模式、css3 的阴影、css3 的 opacity 属性等等,这些应用在网页中,有意无意间,我们的页面多了许多半透明的效果。我们知道,在没有 alpha 通道的情况下,两个颜色叠加,上层的颜色会直接覆盖下层的颜色,但有了 alpha 通道,一切就没有这么简单了。今天,我们就要探讨一下,网页中,rgba(r1,g1,b1,a1)+rgba(r2,g2,b2,a2)rgba(r_1, g_1, b_1, a_1) + rgba(r_2, g_2, b_2, a_2) 会得到什么。

为表述方便,不妨假设最后我们得到的色彩是 rgba(r,g,b,a)rgba(r, g, b, a)

先考虑透明度。一个色彩透明度 opacityopacity 介于0到1之间,opacity=0opacity=0 表示完全透明,opacity=1opacity=1 表示不透明。把要叠加上来的色彩想象成一块玻璃,如果这块玻璃的透明度是0.2,意味着它允许透过80%的光线,阻挡20%的光线。

好,现在想象有两块玻璃,透明度分别是 a1a_1a2a_2,那么光线的通过率分别为 1a11-a_11a21-a_2。所以可以认为,光线穿过第一块玻璃后,剩余 1a11-a_1;再通过第二块玻璃后,还有 (1a1)(1a2)(1-a1)(1-a_2),这就是两块玻璃的综合透光率,相应的,透明度就是 1(1a1)(1a2)1-(1-a_1)(1-a_2)

所以我们能得到第一个结论:

a=1(1a1)(1a2)a=1-(1-a_1)(1-a_2)

,即

a=a1+a2a1a2a=a_1+a_2-a_1 a_2

接下来考虑 rgb 各分量,它们的计算方法是一样的,我们仅以r通道为例,进行推导。还是想象一块半透明的玻璃,它本身是红色的,但由于它允许其他光线透过,所以玻璃本身的颜色会变淡。人们实际感受到的颜色,只是玻璃原本的颜色乘以透明度的结果。

如果有两块玻璃呢,它们的红色浓度分别是 r1r_1r2r_2,透明度分别是 a1a_1a2a_2。那么第一块玻璃让人感受到的红色浓度为 r1a1r_1 a_1,第二块玻璃让人感受到的红色浓度为 r2a2r_2 a_2,第一块玻璃的红色色彩穿过第二块玻璃,并与第二块的红色叠加在一起的颜色浓度就是:

rreal=r1a1(1a2)+r2a2=r1a1+r2a2r1a1a2r_{real}=r_1 a_1 (1-a_2) + r_2 a_2 = r_1 a_1 +r_2 a_2-r_1 a_1 a_2

接下来,我们再把两块玻璃合起来,当成一块玻璃,这个整体的红色浓度为 rr,透明度为 aa。这个 aa 我们之前已经推导过了,是 a1+a2a1a2a_1+a_2-a_1 a_2。那么,我们有:

rreal=ra=r(a1+a2a1a2)r_{real} = r a = r (a_1 + a_2 - a_1 a_2)

由这两个等式,我们可以得出:

r=r1a1+r2a2r1a1a2a1+a2a1a2r=\dfrac{r_1 a_1 +r_2 a_2-r_1 a_1 a_2}{a_1 + a_2 - a_1 a_2}

g 和 b 两个分量上也是如此,在此从略。从推导出来的等式上,我们能直接得出一个结论:颜色叠加的运算,不具备交换率、结合率,也就是说,叠加的顺序很重要。

最后来验证一下吧:

rgba(235, 152, 80, 0.6) + rgba(234, 97, 124, 0.8)

rgba(234, 104, 118, 0.92)