关于Paint 的 setXfermode(Xfermode xfermode) 的理解
来源:互联网 发布:手机归属地数据库下载 编辑:程序博客网 时间:2024/04/28 05:54
相信很多人在使用Paint的setXfermode(Xfermode xfermode)时,也会有很多问题,比如哪些是源图,哪些是目标图,Canvas是怎样绘制的等等。通过参考一些资料,终于明白了Canvas、Bitmap及图层的关系。
一、Canvas与Bitmap
在讲解Paint 的setXfermode时,先来说一下Canvas的相关知识。
1、Canvas的获取
Canvas常用的获取方式有两种,一种我们通过重写View.onDraw方法,View中的Canvas对象会被当做参数传递过来,我们操作这个Canvas,效果会直接的显示在View中。另一种是通过new 一个Canvas对象,方法如下:
Bitmap bitmap = Bitmap.createBitmap(100,100, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); //或者 // Canvas canvas = new Canvas(); // canvas.setBitmap(bitmap);
总之,Canvas需要一个非空的Bitmap(画布),用来呈现Canvas绘制的视图。
2、Bitmap
每一个Bitmap都是一个画布,是用来呈现视图的。我们通过Bitmap.createBitmap(…)时,创建的是一个透明的画布,所有的图像都是画在bitmap上的。我们知道每一次调用canvas.drawxxx函数时,都会生成一个专用的透明图层来画这个图形,画完以后,就盖在了画布上。所以如果我们连续调用五个draw函数,那么就会生成五个透明图层,画完之后依次盖在画布上显示。画布有两种,第一种是view的原始画布,是通过onDraw(Canvas canvas)函数传进来的,其中参数中的canvas就对应的是view的原始画布,控件的背景就是画在这个画布上的!另一种是人造画布,通过saveLayer()、new Canvas(bitmap)这些方法来人为新建一个画布。尤其是saveLayer(),一旦调用saveLayer()新建一个画布以后,以后的所有draw函数所画的图像都是画在这个画布上的,只有当调用restore()、resoreToCount()函数以后,才会返回到原始画布上绘制。
二、setXfermode(Xfermode xfermode)
PorterDuffXfermode是 Xfermode的一个子类,也是一个唯一没有过时的子类,功能很强大。该类有且只有一个含参的构造方法PorterDuffXfermode(PorterDuff.Mode mode),mode模式及效果图如下
下面以一个例子来说明它的使用
首先创建源图 srcBitmap,目标图dstBitmap
//定义一个绘制矩形的Bitmap private Bitmap makeSrc(int w, int h) { Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bm); Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); p.setColor(0xFF66AAFF); c.drawRect(0, 0, w, h, p); return bm; } //定义一个绘制圆形Bitmap private Bitmap makeDst(int w, int h) { Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bm); Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); p.setColor(0xFFFFCC44); c.drawOval(new RectF(0, 0, w, h), p); return bm; }
绘制好srcBitmap 和 dstBitmap 后,接下来,让我们去见证一下奇迹。
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.GREEN);//将背景设置为绿色 int sc = canvas.saveLayer(0, 0, screenW, screenH, null, Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);//创建一个新的Bitmap,在新的画布上演示图形混合后的效果 canvas.drawBitmap(dstBitmap, 0, 0, mPaint); mPaint.setXfermode(pdXfermode); //设置Paint的Xfermode canvas.drawBitmap(srcBitmap, width / 2, height / 2, mPaint); mPaint.setXfermode(null); canvas.restoreToCount(sc);// 还原画布,将新创建的画布合并到原画布上 }
运行的效果是这样的
那如果把saveLayer去掉,代码变成如下,会有什么要的效果呢
canvas.drawColor(Color.GREEN);//将背景设置为绿色 canvas.drawBitmap(dstBitmap, 0, 0, mPaint); mPaint.setXfermode(pdXfermode); //设置Paint的Xfermode canvas.drawBitmap(srcBitmap, width / 2, height / 2, mPaint); mPaint.setXfermode(null);
运行的效果是这样的
怎么会变成这样呢,难道setXfermode没起作用,弄的我是一脸懵逼。在讲解原因之前先来说一下saveLayer的绘图流程。
1. 有saveLayer时
当调用saveLayer时,会创建一个透明的bitmap,以后调用的Canvas.drawXXX(),都是在新的bitmap上进行绘制。除了黄色的圆,其他的都是透明的。在绘制源图时,会根据目标图的透明度进行计算,目标图与源图相交时,由于黄色圆之外的都是空像素,所以源图与目标图相交之外的地方就不会显示了。
xFermode合成过程如下
2. 无saveLayer时
当第二次去掉saveLayer代码时,所有的绘图操作都放在了原始View的Canvas所对应的Bitmap上了。我们先把整个画布给染成了绿色,然后再画上了一个圆形,所以在应用xfermode来画源图像的时候,目标图像当前Bitmap上的所有图像了,也就是整个绿色的屏幕和一个圆形了。所以这时候源图像的相交区域是没有透明像素的,这也就不难解释出现的问题了。
xFermode合成过程如下
三、另一种实现方式
前面已经说了,既然saveLayer会创建一个新的bitmap,那么如果通过Bitmap.createBitmap(…)会实现上面的效果吗。代码如下
首先创建一个Canvas
mBitmap = Bitmap.createBitmap(screenW, screenH, Bitmap.Config.ARGB_8888);mCanvas = new Canvas(mBitmap);
这就创建了一个新的透明的画布,然后将它传递给Canvas。
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.GREEN);//将背景设置为绿色 mCanvas.drawBitmap(dstBitmap, 0, 0, mPaint); mPaint.setXfermode(pdXfermode); //设置Paint的Xfermode mCanvas.drawBitmap(srcBitmap, width / 2, height / 2, mPaint); mPaint.setXfermode(null); canvas.drawBitmap(mBitmap,0,0,null); }
在绘制目标图和源图时是在新创建的mBitmap上,最后在将mBitmap绘制到原View的画布上,绘制效果如下,同样实现了saveLayer的功能。
注:以上的总结参考了http://www.2cto.com/kf/201605/505751.html ,然后加了一些自己的理解,也算是对自己的一个总结。如果有跑偏的地方,也希望能给出指正。
1 0
- 关于Paint 的 setXfermode(Xfermode xfermode) 的理解
- 详解Paint的setXfermode(Xfermode xfermode)
- 详解Paint的setXfermode(Xfermode xfermode)
- 详解Paint的setXfermode(Xfermode xfermode)
- Android中Paint的setXfermode(Xfermode xfermode)方法讲解
- 详解Paint的setXfermode(Xfermode xfermode)(好文章在此记录)
- Paint:xfermode的使用
- Paint 的 Xfermode 的用法
- 安卓 Paint 的 Xfermode
- android.graphics.Paint方法setXfermode (Xfermode x...
- android.graphics.Paint方法setXfermode (Xfermode x...
- android.graphics.Paint方法setXfermode (Xfermode x
- android.graphics.Paint方法setXfermode (Xfermode x...
- android.graphics.Paint方法setXfermode (Xfermode x
- Paint的Xfermode的使用和经验总结
- Xfermode的正确用法
- Paint之Xfermode属性
- Paint---Xfermode、 PixelXorXfermode
- Java初学阶段知识总结
- MVC ViewBag 传多个Model到视图
- cpp的STL之string
- kali linux安装完成后的更新源问题
- 前端做图,零基础如何学习数位板绘画?
- 关于Paint 的 setXfermode(Xfermode xfermode) 的理解
- OpenCV2 显示汉字,未使用CvxText和FreeType库
- 程序员笑话0X02
- 51nod-1042 数字0-9的数量
- php 怎么截取字符 substr() 函数
- 升级macOS10 Xcode8后 APP提交不出现构建版本
- KoaHub.JS用于Node.js的cron作业调度程序代码
- 讯飞移动广告平台iOS SDK接入指南
- 一起学opencv2 (四) 图片的整合