http://blog.csdn.net/cquwentao/article/details/51407135
1 概述
xfermode主要指图像的混合模式,在Android中,paint可以设置不同的xfermode来达到不同的效果。 Xfermode有三个子类:AvoidXfermode,PixelXorXfermode,PorterDuffXfermode;
由于前面两个都已经被废弃,并且并不支持硬件加速,所以这里主要讲解PorterDuffXfermode。
2 PorterDuffXfermode
大家可能会奇怪,为什么这种合成模式的名称会叫做PorterDuff。其实这是两个发明人的名字组合而成的,他们是Thomas Porter 和 Tom Duff。
这里的模式有很多种,从谷歌的官方文档中
(http://developer.android.com/reference/android/graphics/PorterDuff.Mode.html),
我们摘抄如下图片:
这里可以看到一共有18种模式,右边有每种模式对应的计算公式
数组中前一个代表alpha,后一个代表color
sa:源图像的alpha(什么是源图像后面讲解)
sc:源图像的color
da:目标图像的alpha(目标图像的意义后面和源图像一起讲解)
dc:目标图像的color
源图像和目标图像的合并就是这里的模式所要控制的,那么我们先来看一段代码,以便理解源图像和目标图像的关系。
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
这段代码展示了两个图片的合成,从代码的两个canvas.drawBitmap方法可以看到,其中第一次调用传入的为mDstB,第二次为mSrcB,这里就表明了源图和目标图的关系。先绘制到canvas上的叫做目标图像,后面绘制的叫做源图。
我们来看一看谷歌官方的相关模式图:
这里值得注意的是:上诉图都是在关闭硬件加速的情况下合成的,如果开启了硬件加速,clear以及darken,lighten的图像将不同。
这里有一张摘抄于谷歌硬件加速的官方表格:
从中可以看出有的模式不支持硬件加速。
一些坑
相信很多同学看了谷歌的demo之后,都去写过代码尝试,但是发现结果不同。其实这里要仔细看看谷歌的实现代码,有几个重要的点。
1 绘制的时候开启了cavas的layer,这样主要在合成的时候,开拓一个单独的干净的图层,排除其他已经绘制图像的干扰。这个我在前面的篇幅中讲到过。canvas变换
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
2 关闭了硬件加速
setLayerType(LAYER_TYPE_SOFTWARE, null);
3 最重要的一点,两张大小相等,留白透明的合成图片
这里大家可能有点困惑,来看看谷歌官方的创建圆形和方形两个合成图片的代码:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
实际上可以看到,创建两个图片的步骤基本一致,首先都是创建大小为64的透明图片,然后在上面绘制圆形和正方形。随后将两个图片合成,也就是说,其实这两个图片是一样大。并且合成的时候是完全四个角对齐的。只是上面绘制的圆形和正方形并不在这个透明图片的中心。
我们来看看src_in的计算公式:[Sa * Da, Sc * Da]
效果图:(黄色圆形是dst,蓝色正方形是src)
这里为什么是这样一个图形呢,看上面的公式,最终图像的alpha值为sa*da,由于两张图片除了圆形和正方形以外的其他地方都是透明的,也就是alpha为0,那么也就是说,除了相交的地方,其他的地方都会被合成为透明,自然也就只剩这个弧形了。那么color=sc*da,同样的道理,源图的颜色是蓝色,目标图像的alpha为1,所以自然颜色就成了蓝色了。
使用建议
其实从上面的谷歌示例中可以看出,两个图像的合成,上面的结果是比较好理解的,相应的公式之所以设置上透明度因子基本也是这个原因。
使用的过程中,尽量使用相同大小的两个图片来合成,且留白处为透明。这样的情况下,合成图片的效果更容易预测。