@946898963
2020-03-06T23:08:00.000000Z
字数 3735
阅读 876
Canvas与Paint
Xfermode国外有大神称之为过渡模式,这种翻译比较贴切但恐怕不易理解,大家也可以直接称之为图像混合模式,因为所谓的“过渡”其实就是图像混合的一种。Xfermode有三个子类:AvoidXfermode, PixelXorXfermode和PorterDuffXfermode。由于AvoidXfermode, PixelXorXfermode都已经被标注为过时了,所以这次主要研究的是仍然在使用的PorterDuffXfermode。
该类有且只有一个含参的构造方法PorterDuffXfermode(PorterDuff.Mode mode),虽说构造方法的签名列表里只有一个PorterDuff.Mode的参数,但是它可以实现很多酷毙的图形效果!!而PorterDuffXfermode就是图形混合模式的意思,其概念最早来自于SIGGRAPH的Tomas Proter和Tom Duff,混合图形的概念极大地推动了图形图像学的发展,延伸到计算机图形图像学像Adobe和AutoDesk公司著名的多款设计软件都可以说一定程度上受到影响,而我们PorterDuffXfermode的名字也来源于这俩人的人名组合PorterDuff,那PorterDuffXfermode能做些什么呢?我们先来看一张API DEMO里的图片:
这张图片从一定程度上形象地说明了图形混合的作用:两个图形,按照不同模式,组合成不同的结果显示出来。
Android 提供了 18 种图片混排模式(比上图多了两种ADD和OVERLAY),这些混排模式会用到两个图层:先绘制的图是目标图(DST) ,后绘制的图是源图(SRC)。
各种模式的具体的作用,根据例子来学习。
获取了屏幕宽高,然后画了一个矩形一个圆形,计算了一下它们的位置,然后设置下图层,接着设下下画笔 setXfermode,最后绘制到 canvas 上。
public class XfermodeView extends View {
private Context context;
//屏幕宽高
private int screenW;
//绘制的图片宽高
private int width = 200;
private int height = 200;
//上层SRC的Bitmap和下层Dst的Bitmap
private Bitmap srcBitmap, dstBitmap;
public XfermodeView(Context context) {
this(context, null);
}
public XfermodeView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public XfermodeView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics dm = new DisplayMetrics();
manager.getDefaultDisplay().getMetrics(dm);
screenW = dm.widthPixels;
//实例化两个Bitmap
srcBitmap = makeSrc(width, height);
dstBitmap = makeDst(width, height);
}
@Override
public void onMeasure(int width, int height) {
setMeasuredDimension(screenW, 8000);
}
//定义一个绘制圆形 Bitmap 的方法
private 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(0xFFE54261);
c.drawOval(new RectF(0, 0, w * 3 / 4, h * 3 / 4), p);
return bm;
}
//定义一个绘制矩形的 Bitmap 的方法
private 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(0xFF3097F3);
c.drawRect(w / 3, h / 3, w * 19 / 20, h * 19 / 20, p);
return bm;
}
@Override
protected void onDraw(Canvas canvas) {
Paint paint = new Paint();
paint.setFilterBitmap(false);
paint.setStyle(Paint.Style.FILL);
paint.setTextSize(48.0f);
for (PorterDuff.Mode mode : PorterDuff.Mode.class.getEnumConstants()) {
Log.d("modes", mode.name());
canvas.drawText(mode.name(), 10, 50, paint);
canvas.drawBitmap(srcBitmap, (screenW / 3 - width) / 2, 100, paint);
canvas.drawBitmap(dstBitmap, (screenW / 3 - width) / 2 + screenW / 3, 100, paint);
int sc = canvas.saveLayer(0, 0, screenW, 300, null, Canvas.ALL_SAVE_FLAG);
canvas.drawBitmap(dstBitmap, (screenW / 3 - width) / 2 + screenW / 3 * 2,
100, paint); //绘制
//设置Paint的Xfermode
paint.setXfermode(new PorterDuffXfermode(mode));
canvas.drawBitmap(srcBitmap, (screenW / 3 - width) / 2 + screenW / 3 * 2,
100, paint);
paint.setXfermode(null);
// 还原画布
canvas.restoreToCount(sc);
canvas.translate(0, 400);
}
}
}
所绘制不会提交到画布上
只保留源图像的 alpha 和 color,所以绘制出来只有源图
只保留目标图的 alpha 和 color,所以绘制出来只有目标图
把源图绘制在上方
目标图绘制在上方
两者相交的地方绘制源图
两者相交的地方绘制目标图,绘制的效果会受到原图处的透明度影响
不相交的地方绘制源图
在不相交的地方绘制目标图
源图和目标图相交处绘制源图,不相交的地方绘制目标图
源图和目标图相交处绘制目标图,不相交的地方绘制源图
不相交的地方按原样绘制源图和目标图
取两图层全部区域,交集部分颜色加深
取两图层全部区域,点亮交集部分颜色
取两图层交集部分叠加后颜色
取两图层全部区域,交集部分变为透明色
饱和度叠加
叠加
参考链接:
Android Paint PorterDuffXfermode