ProterDuff 使用详解

开头我们来看 ProterDuff 这个词 。

好神奇的单词,完全不知道什么意思对不对(有木有),上网一搜原来是关于2D图像组合的一种理论。

这是豆瓣上的解释:http://www.douban.com/note/143111853/

那么我们为什么要组合2D图形呢?我们先来看一组图:

 

这是桌面应用程序在触摸和拖动图标时候的状态,图1中的白色围绕着bitmap的边缘,图2也是。找到桌面源码中的HolographicOutlineHelper.java查看,原来是用到了ProterDuff.Mode组合出来的图形。当然还有大量的计算。下面介绍一下ProterDuff是如何来组合图形的


这是官网文档
枚举类
public static final enum

PorterDuff.Mode

java.lang.Object
   ↳ java.lang.Enum<android.graphics.PorterDuff.Mode>
     ↳

android.graphics.PorterDuff.Mode



Summary



Enum Values
PorterDuff.Mode  ADD  Saturate(S + D)  
PorterDuff.Mode  CLEAR  [0, 0]  
PorterDuff.Mode  DARKEN  [Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc)]  
PorterDuff.Mode  DST  [Da, Dc]  
PorterDuff.Mode  DST_ATOP  [Sa, Sa * Dc + Sc * (1 - Da)]  
PorterDuff.Mode  DST_IN  [Sa * Da, Sa * Dc]  
PorterDuff.Mode  DST_OUT  [Da * (1 - Sa), Dc * (1 - Sa)]  
PorterDuff.Mode  DST_OVER  [Sa + (1 - Sa)*Da, Rc = Dc + (1 - Da)*Sc]  
PorterDuff.Mode  LIGHTEN  [Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)]  
PorterDuff.Mode  MULTIPLY  [Sa * Da, Sc * Dc]  
PorterDuff.Mode  OVERLAY   
PorterDuff.Mode  SCREEN  [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc]  
PorterDuff.Mode  SRC  [Sa, Sc]  
PorterDuff.Mode  SRC_ATOP  [Da, Sc * Da + (1 - Sa) * Dc]  
PorterDuff.Mode  SRC_IN  [Sa * Da, Sc * Da]  
PorterDuff.Mode  SRC_OUT  [Sa * (1 - Da), Sc * (1 - Da)]  
PorterDuff.Mode  SRC_OVER  [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc]  
PorterDuff.Mode  XOR  [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc]  

分别是这些意思:
1.PorterDuff.Mode.CLEAR  
  所绘制不会提交到画布上。
2.PorterDuff.Mode.SRC
   显示上层绘制图片
3.PorterDuff.Mode.DST
  显示下层绘制图片
4.PorterDuff.Mode.SRC_OVER
  正常绘制显示,上下层绘制叠盖。
5.PorterDuff.Mode.DST_OVER
  上下层都显示。下层居上显示。
6.PorterDuff.Mode.SRC_IN
   取两层绘制交集。显示上层。
7.PorterDuff.Mode.DST_IN
  取两层绘制交集。显示下层。
8.PorterDuff.Mode.SRC_OUT
 取上层绘制非交集部分。
9.PorterDuff.Mode.DST_OUT
 取下层绘制非交集部分。
10.PorterDuff.Mode.SRC_ATOP
 取下层非交集部分与上层交集部分
11.PorterDuff.Mode.DST_ATOP
 取上层非交集部分与下层交集部分
12.PorterDuff.Mode.XOR
  异或:去除两图层交集部分
13.PorterDuff.Mode.DARKEN
  取两图层全部区域,交集部分颜色加深
14.PorterDuff.Mode.LIGHTEN
  取两图层全部,点亮交集部分颜色
15.PorterDuff.Mode.MULTIPLY
  取两图层交集部分叠加后颜色
16.PorterDuff.Mode.SCREEN
  取两图层全部区域,交集部分变为透明色



然后我们就可以开始怀着一颗好奇心画图了.....
自定义一个View,在View中创建两个Bitmap,分别画方和圆,尺寸可以随便定
Java:
public class DuffView extends View {

	private Bitmap mSrcB;
	private Bitmap mDstB;
	private Shader mBG;
	// 文档说了是枚举类,共有16个
	private static final Xfermode[] sModes = { new PorterDuffXfermode(PorterDuff.Mode.CLEAR),
			new PorterDuffXfermode(PorterDuff.Mode.SRC), new PorterDuffXfermode(PorterDuff.Mode.DST),
			new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER), new PorterDuffXfermode(PorterDuff.Mode.DST_OVER),
			new PorterDuffXfermode(PorterDuff.Mode.SRC_IN), new PorterDuffXfermode(PorterDuff.Mode.DST_IN),
			new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT), new PorterDuffXfermode(PorterDuff.Mode.DST_OUT),
			new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP), new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP),
			new PorterDuffXfermode(PorterDuff.Mode.XOR), new PorterDuffXfermode(PorterDuff.Mode.DARKEN),
			new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN), new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY),
			new PorterDuffXfermode(PorterDuff.Mode.SCREEN) };

	public DuffView(Context context) {
		super(context);

	}

	public DuffView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}

	public DuffView(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		init();
	}

	// 初始化
	private void init() {
		mSrcB = makeSrc(400, 400);
		mDstB = makeDst(400, 400);
		Bitmap bitmap = Bitmap.createBitmap(new int[] { 0xFFFFFFFF, 0xFFCCCCCC, 0xFFCCCCCC, 0xFFFFFFFF }, 2, 2,
				Bitmap.Config.RGB_565);
		mBG = new BitmapShader(bitmap, TileMode.REPEAT, TileMode.REPEAT);
		Matrix m = new Matrix();
		m.setScale(6, 6);
		mBG.setLocalMatrix(m);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		canvas.drawColor(Color.WHITE);
		Paint paint = new Paint();
		paint.setFilterBitmap(false);
		canvas.translate(35, 35);
		paint.setStyle(Style.STROKE);
		paint.setShader(null);
		canvas.drawRect(0, 0, 400, 400, paint);
		// shader
		paint.setStyle(Style.FILL);
		paint.setShader(mBG);
		canvas.drawRect(0, 0, 400, 400, paint);
		int sc = canvas.saveLayer(0, 0, 400, 400, 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);
		canvas.drawBitmap(mDstB, 0, 0, paint);
		// 组合图形最关键的地方就在这里
		// paint.setXfermode(sModes[0]);
		canvas.drawBitmap(mSrcB, 0, 0, paint);
		canvas.restoreToCount(sc);
	}

	// 画圆
	static Bitmap makeDst(int w, int h) {
		Bitmap bitmap = Bitmap.createBitmap(w, h, Config.ARGB_8888);
		Canvas canvas = new Canvas(bitmap);
		Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
		p.setColor(0xFFFFCC44);
		p.setColor(Color.RED);
		canvas.drawCircle(w / 2, h / 2, w / 3, p);
		return bitmap;
	}

	// 画方
	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 / 2, h / 2, w - 20, h - 20, p);
		return bm;
	}

}

这里先运行效果看一下:


然后给画笔加上组合方式,通过setXfermode(arg0)来设置,分别运行16种效果如下:

CLEAR                     SRC                         DST                          SRC_OVER
                     
DST_OVER             SRC_IN                    DST_IN                     SRC_OUT
                     
DST_OUT                SRC_ATOP              DST_ATOP             XOR
                       
DARKEN                  LIGHTEN                 MULTIPLY               SCREEN
                     



posted @ 2015-02-28 20:07  顾明伟  阅读(672)  评论(0编辑  收藏  举报