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),
我们摘抄如下图片:

android Xfermode_第1张图片

这里可以看到一共有18种模式,右边有每种模式对应的计算公式
数组中前一个代表alpha,后一个代表color
sa:源图像的alpha(什么是源图像后面讲解)
sc:源图像的color
da:目标图像的alpha(目标图像的意义后面和源图像一起讲解)
dc:目标图像的color

源图像和目标图像的合并就是这里的模式所要控制的,那么我们先来看一段代码,以便理解源图像和目标图像的关系。

canvas.translate(x, y);canvas.drawBitmap(mDstB, 0, 0, paint);paint.setXfermode(sModes[0]);canvas.drawBitmap(mSrcB, 0, 0, paint);paint.setXfermode(null);

这段代码展示了两个图片的合成,从代码的两个canvas.drawBitmap方法可以看到,其中第一次调用传入的为mDstB,第二次为mSrcB,这里就表明了源图和目标图的关系。先绘制到canvas上的叫做目标图像,后面绘制的叫做源图。

我们来看一看谷歌官方的相关模式图:

这里值得注意的是:上诉图都是在关闭硬件加速的情况下合成的,如果开启了硬件加速,clear以及darken,lighten的图像将不同。

这里有一张摘抄于谷歌硬件加速的官方表格:

android Xfermode_第2张图片

从中可以看出有的模式不支持硬件加速。

一些坑

相信很多同学看了谷歌的demo之后,都去写过代码尝试,但是发现结果不同。其实这里要仔细看看谷歌的实现代码,有几个重要的点。

1 绘制的时候开启了cavas的layer,这样主要在合成的时候,开拓一个单独的干净的图层,排除其他已经绘制图像的干扰。这个我在前面的篇幅中讲到过。canvas变换

canvas.saveLayer(x, y, x + W, y + H, 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);

2 关闭了硬件加速

setLayerType(LAYER_TYPE_SOFTWARE, null);

3 最重要的一点,两张大小相等,留白透明的合成图片
这里大家可能有点困惑,来看看谷歌官方的创建圆形和方形两个合成图片的代码:

private static final int W = 64;private static final int H = 64;mSrcB = makeSrc(W, H);mDstB = makeDst(W, H);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;}// create a bitmap with a rect, used for the "src" imagestatic 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;}

实际上可以看到,创建两个图片的步骤基本一致,首先都是创建大小为64的透明图片,然后在上面绘制圆形和正方形。随后将两个图片合成,也就是说,其实这两个图片是一样大。并且合成的时候是完全四个角对齐的。只是上面绘制的圆形和正方形并不在这个透明图片的中心。

我们来看看src_in的计算公式:[Sa * Da, Sc * Da]
效果图:(黄色圆形是dst,蓝色正方形是src)
android Xfermode_第3张图片

这里为什么是这样一个图形呢,看上面的公式,最终图像的alpha值为sa*da,由于两张图片除了圆形和正方形以外的其他地方都是透明的,也就是alpha为0,那么也就是说,除了相交的地方,其他的地方都会被合成为透明,自然也就只剩这个弧形了。那么color=sc*da,同样的道理,源图的颜色是蓝色,目标图像的alpha为1,所以自然颜色就成了蓝色了。

使用建议

其实从上面的谷歌示例中可以看出,两个图像的合成,上面的结果是比较好理解的,相应的公式之所以设置上透明度因子基本也是这个原因。

使用的过程中,尽量使用相同大小的两个图片来合成,且留白处为透明。这样的情况下,合成图片的效果更容易预测。

更多相关文章

  1. Android - 小功能 - Android系统详解之获取图片和视频的缩略图
  2. android 图片平铺实现
  3. android流式布局、待办事项应用、贝塞尔曲线、MVP+Rxjava+Retrof
  4. Android获取相册中图片的路径 4.4版本前后的变化
  5. Android中的基础----在按钮上显示图像的方式
  6. android图片特效,图片过滤
  7. 不支持gif动态图片
  8. Android进阶2之检索Android的图片库并显示图片详细信息

随机推荐

  1. Python-字典的基本操作
  2. Python安装后pip不能用的问题
  3. 如何用PYGtk设置Gtk Icon主题?
  4. 在python中复制命令的正确方法[复制]
  5. 在模块和/或包中组织Python类
  6. 如何删除第一个和最后一个双引号
  7. Python:在类中定义对象
  8. 转python爬虫:BeautifulSoup 使用select方
  9. 感知机(python实现)
  10. conda不是内部或者外部命令