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

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

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的图像将不同。

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

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

一些坑

相信很多同学看了谷歌的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)

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

使用建议

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

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

更多相关文章

  1. Android(安卓)matrix 控制图片的旋转、缩放、移动
  2. android拍照与读取相册
  3. Android(安卓)报错:Caused by: android.os.FileUriExposedExcepti
  4. Android异步加载图像小结 (含线程池,缓存方法)
  5. android解决坚屏拍照和保存图片旋转90度的问题,并兼容4.0
  6. [Android]在App中使用相机
  7. android WebView 图片缩放功能小结
  8. Android(安卓)主流图片库Picasso Glide Fresco对比分析
  9. android背景选择器selector用法汇总

随机推荐

  1. Android(安卓)群英传-第五章:Android(安
  2. android drawBitmapMesh and drawVertice
  3. eclipse项目导入android studio 各类问题
  4. Android知识点总结:Android选取、拍照与裁
  5. Android(安卓)React Native环境配置以及
  6. android 各个版本的发布时间与变动---and
  7. android上使用 google map 会遇到的一些
  8. Android之Tab分页标签的实现方法一-----T
  9. Android实践系列之项目基础配置
  10. android手机短信屏蔽