8.2.1 PorterDuffXfermode 概述
官方文档链接
PorterDuffXfermode 的构造函数如下:
它只有一个参数 PorterDuff.Mode,表示混合模式,枚举值有 18 个,表示各种图形混合模式,每一种模式都对应着一种算法,如下图所示。
比如,LIGHTEN 的计算方式为 [Sa + Da - Sa * Da, Sc * (1 - Da) + Dc * (1 - Sa) + max(Sc, Dc)],其中 Sa 全称为 Source alpha 表示源图的 Alpha 通道;Sc 全称为 Source color 表示源图的颜色;Da 全称为 Destination alpha 表示目标图的 Alpha 通道;Dc 全称为 Destination color 表示目标图的颜色,在每个公式中,都会被分为两部分 [……,……],其中 “,” 前的部分为 “Sa + Da - Sa * Da” 这一部分的值代表计算后的 Alpha 通道;而 “,” 后的部分为 “Sc * (1 - Da) + Dc * (1 - Sa) + max(Sc, Dc)” 这一部分的值代表计算后的颜色值,图形混合后的图片就是依据这个公式来对 DST 和 SRC 两张图像中每一个像素进行计算,得到最终的结果的。
显示的是两个图形一圆一方通过一定的计算产生不同的组合效果,其中圆形是底部的目标图像,方形是上方的源图像。
在上面的公式中涉及到一个概念,目标图 DST,源图 SRC。那什么是源图,什么是目标图呢?我们简单举例子来说明一下:
首先需要自定义一个控件并进行初始化;然后禁用硬件加速;新建两张空白图片,然后在图片上分别画一个圆形 (DST) 和一个矩形 (SRC) 并填充相应的颜色,图形以外的位置都是空白像素;最后在离屏绘制部分,现在 (0, 0) 位置把圆形图像画出来,然后设置 PorterDuffXfermode 的模式为 Mode.SRC_IN,之后再以圆形中心为左上角点画出矩形,清空 Xfermode。
在 Xfermode 设置前画出的图像叫做目标图像,即给谁应用 Xfermode;在 Xfermode 设置后画出的图像叫做源图像,即拿什么应用 Xfermode。
该示例的效果如下图所示。
对于 Mode.SRC_IN,它的计算公式为 [Sa * Da, Sc * Da]。在这个公式中,结果值的透明度和颜色值都是由 Sa、Sc 分别乘以目标图像的 Da 来计算的。当目标图像为空白像素时,计算结果也将为空白像素;当目标图像不透明时,相交区域将显示源图像像素。所以,从效果图中可以看出,两图像相交部分显示的是源图像;对于不相交的部分,此时目标图像的透明度是 0,源图像不显示。
8.2.2 颜色叠加相关模式
这部分涉及到的几个模式有 Mode.ADD(饱和度相加)、Mode.LIGHTEN(变亮)、Mode.DARKEN(变暗)、Mode.MULTIPLY(正片叠底)、Mode.OVERLAY(叠加),Mode.SCREEN(滤色)。
1. Mode.ADD(饱和度相加)
它的公式是 Saturate(S + D)。ADD 模式简单来说就是对 SRC 与 DST 两张图片相交区域的饱和度进行相加。使用 8.2.1 节中的例子,将 PorterDuff.Mode.SRC_IN 改为 PorterDuff.Mode.ADD,效果如下图所示。
从效果图中可以看出,只有源图与目标图像相交的部分的图像的饱和度产生了变化,没相交的部分是没有变的,因为对方的饱和度是 0,当然不相交的位置饱和度是不会变的。这个模式的应用范围比较少,暂时想不到哪里会用到。
2. Mode.LIGHTEN(变亮)
它的算法是: [Sa + Da - Sa * Da, Sc * (1 - Da) + Dc * (1 - Sa) + max(Sc, Dc)]。
这个效果比较容易理解,两个图像重合的区域才会有颜色值变化,所以只有重合区域才有变亮的效果,源图像非重合的区域,由于对应区域的目标图像是空白像素,所以直接显示源图像。
在实际应用中,会出现这种情况:当选中一本书时,给这本书加上灯光效果,如下图所示。
代码如下:
3. Mode.DARKEN(变暗)
对应公式是: [Sa + Da - Sa * Da, Sc * (1 - Da) + Dc * (1 - Sa) + max(Sc, Dc)]。
4. Mode.MULTIPLY(正片叠底)
公式是:[Sa * Da, Sc * Dc]。
从公式中可以看出,计算 Alpha 值时的公式是 Sa * Da,是用源图像的 Alpha 值乘以目标图像的 Alpha 值。由于源图像的非相交区域所对应的目标图像像素的 Alpha 是 0,所以结果像素的 Alpha 值仍是 0,源图像的非相交区域在计算后是透明的。
5. Mode.OVERLAY(叠加)
Google 没有给出这种模式的算法,效果如下图所示。
6. Mode.SCREEN(滤色)
对应公式是:[Sa + Da - Sa * Da, Sc + Dc - Sc * Dc]。
到这里,这六种混合模式就讲完了,下面总结一下:
- 这几种模式都是 PhotoShop 中存在的模式,是通过计算改变交合区域的颜色值的。
- 除了 Mode.MULTIPLY(正片叠底)会在目标图像透明时将结果对应区域置为透明,其它图像都不受目标图像透明像素影响,即源图像非交合部分保持原样。
7. 示例:Twitter 标识的描边效果
在图一中,小鸟整个都是蓝色的。在图二中,只有小鸟的边缘部分是白色的,中间部分是透明的。在最终的合成图中:图一和图二中小鸟与边缘的是显示的,而且还有某种效果,但小鸟中间的区域变透明了,显示的是底部 Activity 的背景色。
前面学到的几种样式中,只有 Mode.MULTIPLY(正片叠底)会在两个图像的一方透明时,结果像素就是透明的。所以这里使用的模式就是 Mode.MULTIPLY 模式。
代码如下: