Xfermode 图像的混合模式

http://blog.csdn.net/cquwentao/article/details/51407135


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);
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

这段代码展示了两个图片的合成,从代码的两个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);
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

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" image
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;
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

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

我们来看看src_in的计算公式:[Sa * Da, Sc * Da] 
效果图:(黄色圆形是dst,蓝色正方形是src) 
这里写图片描述

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

使用建议

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

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




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值