前言
本章主要介绍颜色渲染器PorterDuff。
PorterDuff其实来自两个人名:Tomas Porter和Tom Duff。利用PorterDuff.Mode,我们可以实现图片的任意叠加混合,eg.实现画图中的橡皮擦功能、显示圆形图片等等
1、核心代码
以圆和矩形为例。dst为下层,是先画的图形(这里我选择的是灰色的圆);src为上层,后画的图形(我选用的是蓝色矩形)。实验时,设置的圆的直径与矩形宽高相等,这样重叠起来方便看效果。
(1)核心代码1(直接用canvas绘制):
int sc = canvas.saveLayer(0, 0, canvas.getWidth(), canvas.getHeight(), null, Canvas.ALL_SAVE_FLAG);//创建一个新的layer // canvas.drawARGB(255, 139, 197, 186);//画布颜色 //先绘制一个下层图像 canvas.drawCircle(100,100,100,dstPaint); //绘制上层图像 PorterDuffXfermode mode = new PorterDuffXfermode(PorterDuff.Mode.CLEAR); srcPaint.setXfermode(mode); // canvas.drawRect(new Rect(0,0,200,200),srcPaint);//圆和矩形位置重叠 canvas.drawRect(new Rect(100,100,300,300),srcPaint);//圆和矩形位置稍有偏移 srcPaint.setXfermode(null); // 还原混合模式 canvas.restoreToCount(sc); // 将这个layer绘制到canvas默认的layer
注意蓝色代码:
int sc = canvas.saveLayer(0, 0, canvas.getWidth(), canvas.getHeight(), null, Canvas.ALL_SAVE_FLAG);//创建一个新的layer
srcPaint.setXfermode(null); // 还原混合模式
canvas.restoreToCount(sc); // 将这个layer绘制到canvas默认的layer
这段代码最好加上,否则某些模式下原本不该显示的地方出现白色填充。特别是如果设置了画布颜色,效果会很明显,eg.CLEAR,会显示一个灰色圆和白色矩形(除非新建一个图层,也就是上面这点代码,这样就可以变成原来的效果)。具体原因参见 Android中Canvas绘图之PorterDuffXfermode使用及工作原理详解 or Android PorterDuffXfermode使用中的一些坑
(2)核心代码2(使用Bitmap绘制)
int sc = canvas.saveLayer(0, 0, canvas.getWidth(), canvas.getHeight(), null, Canvas.ALL_SAVE_FLAG);//创建一个新的layer Bitmap dstBm= Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888); Bitmap srcBm= Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888); Canvas dstCanvas = new Canvas(dstBm);//将画布内容转换为bitmap Canvas srcCanvas= new Canvas(srcBm); //先绘制一个下层图像 dstCanvas .drawCircle(100,100,100,dstPaint); canvas.drawBitmap(dstBm,0,0,dstPaint); //绘制上层图像 srcCanvas.drawRect(new Rect(100,100,300,300),srcPaint);//圆和矩形位置稍有偏移 PorterDuffXfermode mode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN); srcPaint.setXfermode(mode); // canvas.drawRect(new Rect(0,0,200,200),srcPaint);//圆和矩形位置重叠 canvas.drawBitmap(srcBm,0,0,srcPaint);
(3)重点说明
对于网上疯传的下面两种不同模式图,本人亲测,双方各有道理。只不过,前者是用采用canvas直接绘图导致的;后者是官方推荐的一种写法,也就是上下层均用bitmap实现。本文将就上述两种方法,分别进行测试。
纠正一下,CLEAR效果两个方式得到的都一样。不一样的是:SRC、SRC_IN、DST_IN、SRC_OUT、DST_ATOP、MULTIPLY这六个,本文会在第三点进行比对显示,方便区分。
2、使用canvas直接画图
2.1 总结
橙色部分为两种方法的不同地方。
PorterDuff.Mode |
说明 |
SRC |
显示上层区域;若此时下层区域存在没有被上层图像覆盖的部分,也会显示 |
DST |
仅显示下层绘制,上层不绘制 |
SRC_OVER |
正常显示,但上层居上显示 |
DST_OVER |
正常显示,但下层居上显示 |
SRC_IN |
显示下层,并将交集部分替换成上层(上层交集部分嵌入到下层) |
DST_IN |
仅显示下层,同DST |
SRC_OUT |
取非交集部分(将上层的交集部分挖出) |
DST_OUT |
取下层非交集部分 |
SRC_ATOP |
显示下层,并将交集部分替换成上层,同SRC_IN |
DST_ATOP |
正常显示,下层居上显示,同DST_OVER |
XOR |
去除交集区域 |
DARKEN |
取两层全部区域,交集区域变暗【必须关闭硬件加速】 |
LIGHTEN |
取两层全部区域,交集区域变亮【必须关闭硬件加速】 |
MULIPLY |
取下层全部区域,交集区域色彩叠加 |
SCREEN |
取两层全部区域,交集部分变为透明色 |
CLEAR |
取下层非交集部分 |
2.2具体分析
特别说明:由于我的界面背景设置成白色,所以下面图中原本透明的地方就显示成了白色,如果设置成其他颜色也会随之响应改变。
(1)SRC
①圆和矩形位置刚好重叠的时候
②圆和矩形稍有偏移时
(2)DST
①圆和矩形位置刚好重叠的时候
②圆和矩形稍有偏移时
(3)SRC_OVER
(4)DST_OVER
(5)SRC_IN
(6)DST_IN
(7)SRC_OUT
(8)DST_OUT
(8)SRC_ATOP
(9)DST_ATOP
(10)XOR
(11)DARKEN
无效果。原因:需要关闭硬件加速
①未关闭前
②关闭后
关闭硬件加速的代码:
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){ //View从API Level 11才加入setLayerType方法 //关闭硬件加速 setLayerType(View.LAYER_TYPE_SOFTWARE, null); }
(12)LIGHTEN
无明显效果。原因:需要关闭硬件加速①未关闭前
②关闭后
(13)MULIPLY
(14)SCREEN
滤色模式。
(15)CLEAR
3、使用Bitmap绘图
特别说明:由于我的界面背景设置成白色,所以下面图中原本透明的地方就显示成了白色,如果设置成其他颜色也会随之响应改变。
一定是要两个都用bitmap绘制。
3.1总结
PorterDuff.Mode |
说明 |
SRC |
仅显示上层区域 |
DST |
仅显示下层绘制,上层不绘制 |
SRC_OVER |
正常显示,但上层居上显示 |
DST_OVER |
正常显示,但下层居上显示 |
SRC_IN |
仅显示上层交集部分 |
DST_IN |
仅显示下层交集部分 |
SRC_OUT |
取上层非交集部分 |
DST_OUT |
取下层非交集部分 |
SRC_ATOP |
显示下层,并将交集部分替换成上层,同SRC_IN |
DST_ATOP |
显示上层,并将交集部分替换成下层(下层交集部分嵌入到上层) |
XOR |
去除交集区域 |
DARKEN |
取两层全部区域,交集区域变暗 |
LIGHTEN |
取两层全部区域,交集区域变亮 |
MULIPLY |
取交集部分叠加后颜色 |
SCREEN |
取两层全部区域,交集部分变为透明色 |
CLEAR |
取下层非交集部分 |
3.2具体分析
下面主要就两个方式的不同之处进行实验(下面的(1)(5)...没顺序,方便快速找到另一种方法的模式位置)。
(1)SRC
(5)SRC_IN
(6)DST_IN
(7)SRC_OUT
(9)DST_ATOP
(13)MULIPLY
4、参考
各个击破搞明白PorterDuff.Mode ☆☆☆☆内含一些特殊情况,待实验测试
有坑?? 为何wing坠入PorterDuffXferMode的万丈深渊(PorterDuffXferMode深入试验) ☆☆☆☆
PorterDuffXferMode不正确的真正原因PorterDuffXferMode深入试验) ☆☆☆☆罗列了许多常见问题
Android 自定义View学习(五)——Paint 关于PorterDuffXfermode学习 ☆☆☆内含一些demo包括圆形图片,值得学习
Android PorterDuffXfermode使用中的一些坑 ☆☆☆内含一些现象的分析
Android中Canvas绘图之PorterDuffXfermode使用及工作原理详解 ☆☆☆一些问题分析
PorterDuffXfermode 正确使用方式(详解) -----内含代码分析
android PorterDuffXferMode真正的效果测试集合(对比官方demo)
Android 颜色渲染PorterDuff及Xfermode详解