一、Xfermode
通过使用Xfermode将绘制的图形的像素和Canvas上对应位置的像素按照一定的规则进行混合,形成新的像素,再更新到Canvas中形成最终的图形
使用的时候都是通过Paint.setXfermode
我们一个像素的颜色都是由四个分量组成,即ARGB,A表示的是我们Alpha值,RGB表示的是颜色
S表示的是原像素,原像素的值表示[Sa,Sc] Sa表示的就是源像素的Alpha值,Sc表示源像素的颜色值
D表示的是目标像素,目标像素的值表示[Da,Dc] Da表示的就是目标像素的Alpha值
蓝色矩形表示的是原图片,黄色圆表示的是目标图片
二、混合模式分类(16种)
1、SRC类 source 原图
----优先显示的是源图片
SRC [Sa, Sc] ---- 处理图片相交区域时,总是显示的是原图片
SRC_IN [Sa * Da, Sc * Da] ---- 处理图片相交区域时,受到目标图片的Alpha值影响
当我们的目标图片为空白像素的时候,目标图片也会变成空白
简单的来说就是用目标图片的透明度来改变源图片的透明度和饱和度,当目标图片的透明度为0时,源图片就不会显示
示例:圆角头像 、倒影图片
SRC_OUT [Sa * (1 - Da), Sc * (1 - Da)] — 同SRC_IN类似 (1 - Da)
用我们目标图片的透明度的补值来改变源图片的透明度和饱和度,当目标图片的透明度为不透明时,源图片就不会显示
示例:橡皮擦效果
目标图片 — 手势的轨迹
源图片 — 擦除的图片
刮刮卡效果 实现
SRC_ATOP [Da, Sc * Da + (1 - Sa) * Dc]
---- 当透明度为100%和0%时,SRC_IN 和 SRC_ATOP是通用的
当透明度不为上述的两个值时,SRC_ATOP 比 SRC_IN 源图像的饱和度会增加,变得更亮一些
示例:用SRC_ATOP来实现 圆角头像 、倒影图片 对比一下SRC_IN
2、DST类 destination 目标图片
----优先显示的是目标图片
DST_IN [Sa * Da, Sa * Dc] ----- 对比一下SRC_IN,正好和我们SRC_IN想法,在相交的时候以源图片的透明度来改变目标图片的透明度和饱和度
当源图片的透明度为0的时候,目标图片完全不显示
示例:心电图效果,不规则水波纹效果,当然也可以做SRC_IN 的效果(注意选择谁为源图片,谁为目标图片)
心电图效果-
目标图片 ---心电图
源图片 ---- 不透明的图 就是通过改变透明图片的不透明区域的宽度,来实现心电图的动画效果
3、其他的叠加效果
MULTIPLY[Sa * Da, Sc * Dc] —
应用:可以把图片的轮廓取出来
LIGHTEN – 变亮
书架 头顶灯光变亮效果
实现: 刮刮卡效果
SRC_IN例子:
package com.dongnao.lsn5_paint_xfermode_src;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
/**
* @author liuml
* @explain
* @time 2018/1/16 15:00
*/
public class ImageView_SRC_IN extends View {
private Paint mBitPaint;
private Bitmap BmpDST, BmpSRC;//目标图片,原图
public ImageView_SRC_IN(Context context) {
super(context);
}
public ImageView_SRC_IN(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
//关闭硬件加速
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
mBitPaint = new Paint();
//目标图片是圆角 边角透明 内容是白底
BmpDST = BitmapFactory.decodeResource(getResources(), R.drawable.shade, null);
//原图是新垣结衣
BmpSRC = BitmapFactory.decodeResource(getResources(), R.drawable.xyjy6, null);
}
/**
* 除了save()方法Canvas还给我们提供了一系列的saveLayerXXX方法给我们保存画布,
* 与save()方法不同的是,saveLayerXXX方法会将所有的操作存到一个新的Bitmap中而不影响当前Canvas的Bitmap,
* 而save()方法则是在当前的Bitmap中进行操作,并且只能针对Bitmap的形变和裁剪进行操作,
* saveLayerXXX方法则无所不能
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
/**
* ALL_SAVE_FLAG 很简单也是我们新手级常用的标识保存所有;
CLIP_SAVE_FLAG 是裁剪标识位;
MATRIX_SAVE_FLAG 是变换的标识位;
CLIP_TO_LAYER_SAVE_FLAG、FULL_COLOR_LAYER_SAVE_FLAG和HAS_ALPHA_LAYER_SAVE_FLAG
只对saveLayer和saveLayerAlpha有效。
CLIP_TO_LAYER_SAVE_FLAG 表示对当前图层执行裁剪操作需要对齐图层边界;
FULL_COLOR_LAYER_SAVE_FLAG 表示当前图层的色彩模式至少需要是8位色,
HAS_ALPHA_LAYER_SAVE_FLAG 表示在当前图层中将需要使用逐像素Alpha混合模式,
关于色彩深度和Alpha混合大家可以参考维基百科
*/
int layoutId = canvas.saveLayer(0, 0, getWidth(), getHeight(), null,Canvas.ALL_SAVE_FLAG );
canvas.drawBitmap(BmpDST,0,0,mBitPaint);
//设置Xfermode 的模式 src_in 优先原图 PorterDuffXfermode ,Porter,Duff 两个人名
mBitPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(BmpSRC,0,0,mBitPaint);
mBitPaint.setXfermode(null);
canvas.restoreToCount(layoutId);
}
}
是时候拿出 那张经典的图片了
https://www.jianshu.com/p/d11892bbe055
这篇文章讲的很不错 每种模式都讲的很清楚 可以看下
有时候会感觉分不清先绘制的是源图还是后绘制的是源图,这个时候可以这么记,先绘制的是目标图。