Android绘图基础之xfermode & layer
来源:互联网 发布:dnf上号就网络连接中断 编辑:程序博客网 时间:2024/06/06 05:54
转载请注明出处:http://blog.csdn.net/crazy1235/article/details/73835933
- layer
- xfermode
- CLEAR
- DST
- SRC
layer
android的绘图机制有点类似于 [PhotoShop] 的方式!可以分成很多个图层(layer)
每个图层绘制自己的内容,然后图层之间可以合并!
(图片转自网络)
Api 中关于图层的操作有如下几个函数:
save()
restore()
restoreToCount(int saveCount)
简单来说,save()就是保存canvas当前的坐标状态,restore()就是恢复上一次保存的坐标状态!
距离说明一下:
canvas.save(); // 保存状态canvas.rotate(90, canvas.getWidth() / 2, canvas.getHeight() / 2);paint.setStrokeWidth(20);paint.setColor(Color.RED);canvas.drawLine(canvas.getWidth() / 2, 0, canvas.getWidth() / 2, canvas.getHeight(), paint);canvas.restore(); // 恢复状态canvas.drawCircle(canvas.getWidth() - 100, canvas.getWidth() - 100, 100, paint);
保存状态之后,旋转画布90°,然后绘制一条直线。如果不旋转画布的话,该直线是上下居中的,但是此时旋转了画布,就变成了横向居中了。
接着恢复画布上一次的状态,绘制了一个圆形!
而如果不进行状态保存与恢复!
canvas.rotate(90, canvas.getWidth() / 2, canvas.getHeight() / 2);paint.setStrokeWidth(20);paint.setColor(Color.RED);canvas.drawLine(canvas.getWidth() / 2, 0, canvas.getWidth() / 2, canvas.getHeight(), paint);canvas.drawCircle(canvas.getWidth() - 100, canvas.getWidth() - 100, 100, paint);
此时圆形并没有在右边的位置! 因为此时的画布是顺时针旋转了90°的状态。
android系统默认坐标是这样的:
画布旋转90°之后:
当调用了canvas.restore()的时候,就恢复了上次store()的状态,所以绘制圆形的时候位置就是正常的!
源码中关于restore()的一段注释如下:
/** * This call balances a previous call to save(), and is used to remove all * modifications to the matrix/clip state since the last save call. It is * an error to call restore() more times than save() was called. */ public void restore() { boolean throwOnUnderflow = !sCompatibilityRestore || !isHardwareAccelerated(); native_restore(mNativeCanvasWrapper, throwOnUnderflow); }
意思就是save()和restore()一般都是成对出现的!restore() 用来移除所有关于matrix/clip的修改。
restore()比save()调用的次数多时是一种错误的方式!
xfermode
setXfermode(Xfermode xfermode)
在Canvas上绘图的时候,Paint一般都要用到。而Paint中有一个setXfermode()的函数!
public Xfermode setXfermode(Xfermode xfermode) { long xfermodeNative = 0; if (xfermode != null) xfermodeNative = xfermode.native_instance; nSetXfermode(mNativePaint, xfermodeNative); mXfermode = xfermode; return xfermode; }
xfermode 有一个子类 PorterDuffXfermode
是一个图像合成模式类!
在设置Xfermode模式之前绘制的称为目标图像(DST), 在设置Xfermode模式之后绘制的称为源图像(SRC)! 所以先绘制的称为DST,后绘制的称为SRC
官方定义了 18种 合成模式!
CLEAR – 将源图像所在的位置绘制成透明图层
SRC – 只绘制源图像
DST – 只绘制目标图像
SRC_OVER – 在目标图像上面绘制源图像
DST_OVER – 在源图像顶部绘制目标图像
SRC_IN – 只在源图像和目标图像相交的地方绘制源图像
DST_IN – 只在源图像和目标图像相交的地方绘制目标图像
SRC_OUT – 只在源图像和目标图像不相交的地方绘制源图像
DST_OUT – 只在源图像和目标图像不相交的地方绘制目标图像
SRC_ATOP – 在源图像和目标图像相交的地方绘制源图像,不相交的地方绘制目标图像
DST_ATOP – 在源图像和目标图像相交的地方绘制目标图像,不想交的地方绘制源图像
XOR – 在源图像和目标图像不相交的地方绘制各自,在重叠的地方不绘制任何内容
DARKEN – 获得每个位置上两幅图像中最暗的像素并显示
LIGHTEN – 获得每个位置上两幅图像中最亮的像素并显示
MULTIPLY –
SCREEN
ADD
OVERLAY
常用的一般就是SRC_OUT, DST_OUT, SRC_IN, DST_IN, SRC_OVER, DST_OVER, XOR这几种!
将各种图像和图案,通过运用这几种图像混合模式就可以实现各种比较酷炫的效果:
圆形头像
圆角矩形头像
五角星头像
引导图层
画板功能
刮刮卡效果
……
首先需要说明的是,官方demo中的合成效果并没有问题。只不过它的src与dst图像大小是一样的,占满了整个区域!
static 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 * 3 / 4, h * 3 / 4), p); return bm; }
Dst图像占满了这个区域,但是里面的 oval 只占了 w * h区域的 3/4 。
static 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(w / 3, h / 3, w * 19 / 20, h * 19 / 20, p); return bm; }
Src图像也占满 w * h 整个区域,但是里面的 Rect 只占了一部分。
源码请移步:
https://github.com/crazy1235/ApiDemos/blob/master/app/src/main/java/com/example/android/apis/graphics/Xfermodes_Old.java
官方demo合成之后的效果如下:
看到网上很多人说,这个图不正确。其实不是不正确,而是这两个图大小是一样的,合成之后的效果即使如此!
当把两个图像的大小限制为那个圆形和矩形同样大小的时候,合成的图像就是另外一种场景!
// dst bitmap的大小与oval一致 static Bitmap makeDst(int w, int h) { w = w * 3 / 4; h = h * 3 / 4; 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; } // src bitmap的大小与rect一致 static Bitmap makeSrc(int w, int h) { w = w * 5 / 8; h = h * 5 / 8; 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; }
此时的效果如下:
源码请移步:
https://github.com/crazy1235/ApiDemos/blob/master/app/src/main/java/com/example/android/apis/graphics/Xfermodes.java
还有一点需要说明的是,并不是想某些博客里面说的必须得绘制bitmap才行。xfermode合成模式是通过像素矩阵运算达到目的的!而绘制bitmap或者绘制普通的图形(circle,oval等)底层都是通过像素矩阵运算的!所以并不是必须得绘制bitmap才能大小合成效果!
举例说明几种常用的混合模式:
CLEAR
private PorterDuffXfermode xfermode = new PorterDuffXfermode(PorterDuff.Mode.CLEAR); //CLEAR
radius = canvas.getWidth() / 3;// 1. bgcanvas.drawColor(Color.parseColor("#E0EEE0"));// 2. dstpaint.setColor(0xFFFFCC44);canvas.drawCircle(radius, radius, radius, paint);// 3. srcpaint.setColor(0xFF66AAFF);paint.setXfermode(xfermode);canvas.drawRect(radius, radius, radius * 2.5f, radius * 2.5f, paint);paint.setXfermode(null);
首先给这个画布着色 。然后绘制了一个黄色的圆形,然后对画笔设置CLEAR这种xfermode模式,最后绘制了一个蓝色方形。
效果图如下:
从效果图上看,正方形的颜色变成了白色!
PorterDuff.Mode.CLEAR 的目的就是将 源图像 所在的位置绘制成透明图像!
而屏幕本身的颜色是白色,所以矩形区域就显示成了白色!
将上面图层合成放到一个新图层中!
private PorterDuffXfermode xfermode = new PorterDuffXfermode(PorterDuff.Mode.CLEAR);radius = canvas.getWidth() / 3;canvas.drawColor(Color.BLACK); // 整个是黑色背景int sc = canvas.saveLayer(0, 0, canvas.getWidth(), radius * 3, null, Canvas.ALL_SAVE_FLAG); // layer// 1. bgcanvas.drawColor(Color.parseColor("#E0EEE0")); // 新建图层的背景// 2. dstpaint.setColor(0xFFFFCC44);canvas.drawCircle(radius, radius, radius, paint); // dst// 3. srcpaint.setColor(0xFF66AAFF);paint.setXfermode(xfermode); // canvas.drawRect(radius, radius, radius * 2.5f, radius * 2.5f, paint); // srcpaint.setXfermode(null);canvas.restoreToCount(sc); // restore
这里新建一个图层,然后将两个图像用 CLEAR模式 混合!
在新图层上进行混合的时候,由于CLEAR会将 SRC 的区域绘制成透明的图层,所以与下面的图层合并之后,矩形区域就显示了下层图层的颜色!
DST
private PorterDuffXfermode xfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC);
SRC
private PorterDuffXfermode xfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC);
参考:
http://blog.csdn.net/iispring/article/details/50472485
http://www.jianshu.com/p/d11892bbe055
https://developer.android.com/reference/android/graphics/PorterDuff.Mode.html
- Android绘图基础之xfermode & layer
- Android绘图之2D绘图基础
- android 图片操作之Xfermode
- Android|图像图像之Xfermode
- Android绘图基础之Shader
- Android xml绘图 (三)-----------Layer
- Android 绘图进阶(三):Xfermode绘制图片的保存
- android绘图处理系列(一):bitmapShader和Xfermode
- android Xfermode
- android xfermode
- Android Xfermode
- Android绘图基础之 ~~~ 在XML中绘图
- android 画图之setXfermode、Xfermode使用
- Android开发学习之Android2D绘图基础
- Android绘图基础之: Canvas 和 Paint
- Android 自定义View绘图篇之基础
- Android学习笔记之基础绘图类
- Android 绘图XML——layer-list
- ArrayList 源码分析
- PANIC: HOME is defined but could not find Nexus_5_API_22_64-x86.ini file in $HOME/.android/avd
- 多线程并发常见问题
- maven配置Tomcat
- Source Insight使用
- Android绘图基础之xfermode & layer
- Python 中的单例模式
- html5响应式网站拥有什么样的优势与特点?
- Python基础-UDP编程
- 快消品企业营销费用管理的困惑
- 线程池ThreadPoolExecutor
- 如何修改两个PHP版本,php-v和phpinfo两个不同的版本
- Ubuntu14+OpenCV3.1+Caffe虚拟机安装笔记(一)
- Android之Service学习篇一:Service启动方式之startService