混合模式

  • 混合模式能够将两个图片无缝结合,实现两张图片融合的效果,它是通过Paint类中的Xfermode setXfermode(Xfermode xfermode)函数实现的,Xfermode是一个空类和之前一样都是通过自类来实现不同的功能,子类有AvoidXfermode, PixelXorXfermode和PorterDuffXfermode
  • 由于PixelXorXfermode在API16已经完全过时,所以基本用不上
  • AvoidXfermode完全不支持硬件加速和PorterDuffXfermode部分不支持硬件加速
使用注意点:
  • 禁用硬件加速:
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
  • 使用离屏绘制:
//新建图层
int layerId = canvas.saveLayer(0, 0, getWidth(), getHeight(), null, Canvas.ALL_SAVE_FLAG);
//核心绘制代码
...
//还原图层
canvas.restoreToCount(layerId);
AvoidXfermode(现已不用)
  • 虽然在API16已经禁用,但是还没又可以替代的方法,所以还是可以在API16以上的平台使用
//opColor:一个十六进制的AARRGGBB形式的颜色值
//tolerance:表示容差
//mode:取值为Mode.TARGET(表示将指定的颜色替换掉)和Mode.AVOID(表示将Mode.TARGET的相反区域颜色替换掉)
public AvoidXfermode(int opColor, int tolerance, Mode mode);
  • 容差概念:
  • 容差是指与目标色可以容忍的最大颜色差异,容差越大,所覆盖的颜色区域就越大,当容差为0的时候,表示只选择与目标色一模一样的颜色区域,当容差为100的时候,表示与目标色的颜色差异在100的范围内都是可以接受的,最大的容差为255,在255范围内意味着所有颜色都将被选中。
  • AvoidXfermode原理:
  • 将目标区域的颜色值清空,然后再替换为目标颜色
PorterDuffXfermode:
//mode:表示混合模式,枚举值有18个,表示各种混合模式,每种模式对应一种算法
public PorterXfermode(PorterDuff.Mode mode);

Enum Values

算法

ADD

Saturate(S + D)

CLEAR

[0, 0]

DARKEN

[Sa + Da - Sa * Da, Sc * (1-Da) + Dc * (1-Sa) + min(Sc, Dc)]

DST

[Da, Dc]

DST_ATOP

[Sa, Sa* Dc+ Sc * (1-Da)]

DST_IN

[Sa * Da, Sa * Dc]

DST_OUT

[Da * (1-Sa), Dc*(1-Sa)]

DST_OVER

[Sa+(1-Sa)* Da, Rc = Dc + (1-Sa) + max(Sc, Dc)]

LIGHTEN

[Sa + Da - Sa* Da, Sc * (1-Da)+Dc*(1-Sa) + max(Sc, Da)]

MULTIPLY

[Sa * Da, Sc * Dc]

OVERLAY

SCREEN

[Sa + Da - Sa* Da, Sc + Dc - Sc * Dc]

SRC

[Sa, Sc]

SRC_ATOP

[Da, Sc* Da + (1-Sa)* Dc]

SRC_IN

[Sa * Da, Sc* Da]

SRC_OUT

[Sa * (1-Da),Sc*(1-Da)]

SRC_OVER

[Sa+(1-Sa)* Da, Rc=Sc+(1-Sa)* Dc]

XOR

[Sa+Da-2* Sa * Da, Sc*(1-Da) + (1-Sa)* Dc]

  • 公式参数解释:

参数

说明

Sa

Source alpha 表示源图像的Alpha通道

Sc

Source color 表示源图像的颜色

Da

Destination alpha 表示目标图像的Alpha通道

Dc

Destination color 表示目标图像的颜色

[1,2]

1表示计算后的Alpha通道,2代表计算后的颜色值

  • DST, SRC解释:
DST:目标图像
SRC:源图像

eg: SRC_IN模式

public PorterDuffXfermodeView(Context context, AttributeSet attrs) {
super(context, attrs);
setLayerType(LAYER_TYPE_SOFTWARE, null);
dstBmp = makeDst(width, height);
srcBmp = makeSrc(width, height);
paint = new Paint();
}
private Bitmap makeDst(int w, int h){
Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bm);
Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
//画一张空白的图片,然后再图片上画一个黄色的圆形,中间有一个圆形的位图,除圆形以外其他都是空白像素
p.setColor(0xFFFFCC44);
canvas.drawOval(new RectF(0, 0, w, h), p);
return bm;
}


private Bitmap makeSrc(int w, int h){
Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bm);
Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);


p.setColor(0xFF66AAFF);
canvas.drawRect(0, 0, w,h, p);
return bm;
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int layId = canvas.saveLayer(0, 0, getWidth(), getHeight(), null, Canvas.ALL_SAVE_FLAG);
canvas.drawBitmap(dstBmp, 0, 0, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(srcBmp, width/2, height/2, paint);
paint.setXfermode(null);
canvas.restoreToCount(layId);
}

混合模式(一)_Android 自定义动画


首先我们绘制的黄色圆形时目标图像, 蓝色圆形时源图像,对于模式SRC_IN [Sa * Da, Sc * Da]来说,当目标图像为看空白像素时,计算结果为空白像素(因为Da=0),当目标图像不透明,相交部分显示源图像像素。

  • SRC_IN模式实在相交时利用目标图像的透明度来改变源图像的透明度的饱和度的,当目标图像的透明度为0时,源图像就完全不显示
颜色叠加的相关模式:
  • 针对色彩变换的模式有:
  • Mode.ADD: 饱和度相加
  • Mode.LIGHTEN:变亮
  • Mode.DARKEN:变暗
  • Mode.MULTIPLY:正片叠底
  • Mode.OVERLAY:叠加
  • Mode.SCREEN:滤色

1.饱和度相加:

Mode.ADD
//ADD模式:对src和dst两张土拍你相交区域的饱和度进行相加
Saturate(S + D)

相交部分饱和度发生变化

混合模式(一)_硬件加速_02

2.变亮模式:

Mode.LIGHTEN
//一般用于灯光效果
[Sa + Da - Sa * Da, Sc*(1-Da)+Dc*(1-Sa)+max(Sc,Dc)]

混合模式(一)_混合模式_03

3.变暗模式:

Mode.DARKEN
[Sa + Da - Sa * Da, Sc*(1-Da)+Dc*(1-Sa)+min(Sc,Dc)]

混合模式(一)_硬件加速_04

4.正片叠底:

Mode.MULTIPLY
[Sa * Da, Sc * Dc]

混合模式(一)_混合模式_05

5.叠加模式:

Mode.OVERLAY
Google并未给出相应的算法

混合模式(一)_Android 自定义动画_06

6.滤色模式:

Mode.SCREEN
[Sa + Da - Sa * Da, Sc + Dc - Sc * Dc]

混合模式(一)_混合模式_07

总结:
  • 这几种模式都是PS中存在的模式,通过计算改版相交区域的颜色值的
  • 除了Mode.MULTIPLY会在目标图像透明时将结果对应区域配置为透明,其他图像都不收目标图像的透明像素的影响,即非相交区域保持原样
  • 一般只考虑两种混合模式:
  • 两个不透明区域的混合
  • 源图像与完全透明区域的混合