当前位置: 首页 > 工具软件 > paint-board > 使用案例 >

android 不同格式图层,android paint画笔图层混合模式

闻人嘉颖
2023-12-01

官方Xfermode的实例 里面18中模式详解

public class XfermodesActivity extends AppCompatActivity {

// create a bitmap with a circle, used for the "dst" image

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;

}

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(new SampleView(this));

}

private static class SampleView extends View {

private static final int W = 320;

private static final int H = W;

private static final int ROW_MAX = 4; // number of samples per row

private Bitmap mSrcB;

private Bitmap mDstB;

private Shader mBG; // background checker-board pattern

private Paint mPaint;

//效果作用于src源图像区域

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),

//取两图层全部区域,交集部分饱和度相加

new PorterDuffXfermode(PorterDuff.Mode.ADD),

//取两图层全部区域,交集部分叠加

new PorterDuffXfermode(PorterDuff.Mode.OVERLAY)

};

private static final String[] sLabels = {

"Clear", "Src", "Dst", "SrcOver",

"DstOver", "SrcIn", "DstIn", "SrcOut",

"DstOut", "SrcATop", "DstATop", "Xor",

"Darken", "Lighten", "Multiply", "Screen", "Add","Overlay"

};

public SampleView(Context context) {

super(context);

mSrcB = makeSrc(W, H);

mDstB = makeDst(W, H);

// make a ckeckerboard pattern

Bitmap bm = Bitmap.createBitmap(new int[]{0xFFFFFFFF, 0xFFCCCCCC, 0xFFCCCCCC, 0xFFFFFFFF}, 2, 2,

Bitmap.Config.RGB_565);

mBG = new BitmapShader(bm,

Shader.TileMode.REPEAT,

Shader.TileMode.REPEAT);

Matrix m = new Matrix();

m.setScale(6, 6);

mBG.setLocalMatrix(m);

mPaint = new Paint();

mPaint.setStrokeWidth(2);

mPaint.setStyle(Paint.Style.STROKE);

mPaint.setColor(Color.GRAY);

}

@Override

protected void onDraw(Canvas canvas) {

canvas.drawColor(Color.WHITE);

Paint labelP = new Paint(Paint.ANTI_ALIAS_FLAG);

labelP.setTextAlign(Paint.Align.CENTER);

Paint paint = new Paint();

paint.setFilterBitmap(false);

canvas.translate(15, 15);

canvas.drawBitmap(mDstB, 0, 0, paint);

canvas.drawRect(0,0, mDstB.getWidth(), mDstB.getHeight(), mPaint);

canvas.drawBitmap(mSrcB, mDstB.getWidth() + 15, 0, paint);

canvas.drawRect(mDstB.getWidth() + 15,0, mDstB.getWidth() + 15 + mSrcB.getWidth(), mSrcB.getHeight(), mPaint);

canvas.translate(0, mDstB.getHeight() + 15);

int x = 0;

int y = 0;

for (int i = 0; i < sModes.length; i++) {

// draw the border

paint.setStyle(Paint.Style.STROKE);

paint.setShader(null);

canvas.drawRect(x - 0.5f, y - 0.5f,

x + W + 0.5f, y + H + 0.5f, paint);

// draw the checker-board pattern

paint.setStyle(Paint.Style.FILL);

paint.setShader(mBG);

canvas.drawRect(x, y, x + W, y + H, paint);

// draw the src/dst example into our offscreen bitmap

int sc = canvas.saveLayer(x, y, x + W, y + H, null, Canvas.ALL_SAVE_FLAG);

canvas.translate(x, y);

//目标图像

canvas.drawBitmap(mDstB, 0, 0, paint);

paint.setXfermode(sModes[i]);

//源图像

canvas.drawBitmap(mSrcB, 0, 0, paint);

paint.setXfermode(null);

canvas.restoreToCount(sc);

// draw the label

canvas.drawText(sLabels[i], x + W / 2, y - labelP.getTextSize() / 2, labelP);

x += W + 10;

// wrap around when we've drawn enough for one row

if ((i % ROW_MAX) == ROW_MAX - 1) {

x = 0;

y += H + 30;

}

}

}

}

}

谷歌官方实例去掉透明区域重新混合

public class XfermodesView extends View {

private static int W = 250;

private static int H = 250;

private static final int ROW_MAX = 4; // number of samples per row

private Bitmap mSrcB;

private Bitmap mDstB;

private Shader mBG; // background checker-board pattern

//其中Sa全称为Source alpha表示源图的Alpha通道;Sc全称为Source color表示源图的颜色;Da全称为Destination alpha表示目标图的Alpha通道;Dc全称为Destination color表示目标图的颜色,[...,..]前半部分计算的是结果图像的Alpha通道值,“,”后半部分计算的是结果图像的颜色值。

//效果作用于src源图像区域

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),

//取两图层全部区域,交集部分饱和度相加

new PorterDuffXfermode(PorterDuff.Mode.ADD),

//取两图层全部区域,交集部分叠加

new PorterDuffXfermode(PorterDuff.Mode.OVERLAY)

};

private static final String[] sLabels = {

"Clear", "Src", "Dst", "SrcOver",

"DstOver", "SrcIn", "DstIn", "SrcOut",

"DstOut", "SrcATop", "DstATop", "Xor",

"Darken", "Lighten", "Multiply", "Screen", "Add","Overlay"

};

public XfermodesView(Context context) {

this(context, null);

}

public XfermodesView(Context context, AttributeSet attrs) {

this(context, attrs, 0);

}

public XfermodesView(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);

if (windowManager != null) {

DisplayMetrics display = new DisplayMetrics();

windowManager.getDefaultDisplay().getMetrics(display);

W = H = (display.widthPixels - 64) / ROW_MAX; //得到矩形

}

//1,API 14之后,有些函数不支持硬件加速,需要禁用

setLayerType(View.LAYER_TYPE_SOFTWARE, null);

mSrcB = makeSrc(W, H);

mDstB = makeDst(W, H);

//根据width和height创建空位图,然后用指定的颜色数组colors来从左到右从上至下一次填充颜色

//make a ckeckerboard pattern

Bitmap bm = Bitmap.createBitmap(new int[]{0xFFFFFFFF, 0xFFCCCCCC, 0xFFCCCCCC, 0xFFFFFFFF}, 2, 2, Bitmap.Config.RGB_565);

mBG = new BitmapShader(bm, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);

Matrix m = new Matrix();

m.setScale(6, 6);

mBG.setLocalMatrix(m);

}

// //google api的画法

// @Override

// protected void onDraw(Canvas canvas) {

// canvas.drawColor(Color.WHITE);

//

// Paint labelP = new Paint(Paint.ANTI_ALIAS_FLAG);

// labelP.setTextAlign(Paint.Align.CENTER);

//

// Paint paint = new Paint();

// //设置是否使用双线性过滤来绘制Bitmap,图像在放大绘制的时候,默认使用的是最近邻插值过滤,这种算法简单,但会出现马赛克现象;而如果开启了双线性过滤,就可以让结果图像显得更加平滑

// paint.setFilterBitmap(false);

//

// canvas.translate(15, 35);

//

// int x = 0;

// int y = 0;

// for (int i = 0; i < sModes.length; i++) {

// // draw the border

// paint.setStyle(Paint.Style.STROKE);

// paint.setShader(null);

// canvas.drawRect(x - 0.5f, y - 0.5f, x + W + 0.5f, y + H + 0.5f, paint);

//

// // draw the checker-board pattern

// paint.setStyle(Paint.Style.FILL);

// paint.setShader(mBG);

// canvas.drawRect(x, y, x + W, y + H, paint);

//

// // draw the src/dst example into our offscreen bitmap

// int sc = canvas.saveLayer(x, y, x + W, y + H, null);

// canvas.translate(x, y);

// canvas.drawBitmap(mDstB, 0, 0, paint);

// paint.setXfermode(sModes[i]);

// canvas.drawBitmap(mSrcB, 0, 0, paint);

// paint.setXfermode(null);

// canvas.restoreToCount(sc);

//

// // draw the label

// labelP.setTextSize(20);

// canvas.drawText(sLabels[i], x + W / 2, y - labelP.getTextSize() / 2, labelP);

//

// x += W + 10;

//

// // wrap around when we've drawn enough for one row

// if ((i % ROW_MAX) == ROW_MAX - 1) {

// x = 0;

// y += H + 30;

// }

// }

// }

//

// // create a bitmap with a circle, used for the "dst" image

// 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;

// }

@Override

protected void onDraw(Canvas canvas) {

canvas.drawColor(Color.WHITE);

Paint labelP = new Paint(Paint.ANTI_ALIAS_FLAG);

labelP.setTextAlign(Paint.Align.CENTER);

Paint paint = new Paint();

paint.setFilterBitmap(false);

canvas.translate(15, 35);

int x = 0;

int y = 0;

for (int i = 0; i < sModes.length; i++) {

// draw the border

paint.setStyle(Paint.Style.STROKE);

paint.setShader(null);

canvas.drawRect(x - 0.5f, y - 0.5f, x + W + 0.5f, y + H + 0.5f, paint);

// draw the checker-board pattern

paint.setStyle(Paint.Style.FILL);

paint.setShader(mBG);

canvas.drawRect(x, y, x + W, y + H, paint);

// 使用离屏绘制

int sc = canvas.saveLayer(x, y, x + W, y + H, null);

canvas.translate(x, y);

canvas.drawBitmap(makeDst(2 * W / 3, 2 * H / 3), 0, 0, paint);

paint.setXfermode(sModes[i]);

canvas.drawBitmap(makeSrc(2 * W / 3, 2 * H / 3), W / 3, H / 3, paint);

paint.setXfermode(null);

canvas.restoreToCount(sc);

// draw the label

labelP.setTextSize(20);

canvas.drawText(sLabels[i], x + W / 2, y - labelP.getTextSize() / 2, labelP);

x += W + 10;

// wrap around when we've drawn enough for one row

if ((i % ROW_MAX) == ROW_MAX - 1) {

x = 0;

y += H + 30;

}

}

}

// create a bitmap with a circle, used for the "dst" image

// 画圆一个完成的圆

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, h), 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(0, 0, w * 19 / 20, h * 19 / 20, p);

return bm;

}

}

简单的刮刮卡案例

public class XfermodeEraserView extends View {

private Paint mPaint;

private Bitmap mDstBmp, mSrcBmp, mTxtBmp;

private Path mPath;

public XfermodeEraserView(Context context) {

this(context, null);

}

public XfermodeEraserView(Context context, AttributeSet attrs) {

this(context, attrs, 0);

}

public XfermodeEraserView(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

init();

}

private void init() {

//初始化画笔

mPaint = new Paint();

mPaint.setColor(Color.RED);

mPaint.setStyle(Paint.Style.STROKE);

mPaint.setStrokeWidth(80);

//禁用硬件加速

setLayerType(View.LAYER_TYPE_SOFTWARE, null);

//初始化图片对象

mTxtBmp = BitmapFactory.decodeResource(getResources(), R.drawable.result);

mSrcBmp = BitmapFactory.decodeResource(getResources(), R.drawable.eraser);

mDstBmp = Bitmap.createBitmap(mSrcBmp.getWidth(), mSrcBmp.getHeight(), Bitmap.Config.ARGB_8888);

//路径(贝塞尔曲线)

mPath = new Path();

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

//绘制刮奖结果

canvas.drawBitmap(mTxtBmp, 0, 0, mPaint);

//使用离屏绘制

int layerID = canvas.saveLayer(0, 0, getWidth(), getHeight(), mPaint, Canvas.ALL_SAVE_FLAG);

//先将路径绘制到 bitmap上

Canvas dstCanvas = new Canvas(mDstBmp);

dstCanvas.drawPath(mPath, mPaint);

//绘制 目标图像

canvas.drawBitmap(mDstBmp, 0, 0, mPaint);

//设置 模式 为 SRC_OUT, 擦橡皮区域为交集区域需要清掉像素

mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));

//绘制源图像

canvas.drawBitmap(mSrcBmp, 0, 0, mPaint);

mPaint.setXfermode(null);

canvas.restoreToCount(layerID);

}

private float mEventX, mEventY;

@Override

public boolean onTouchEvent(MotionEvent event) {

super.onTouchEvent(event);

switch (event.getAction()) {

case MotionEvent.ACTION_DOWN:

mEventX = event.getX();

mEventY = event.getY();

mPath.moveTo(mEventX, mEventY);

break;

case MotionEvent.ACTION_MOVE:

float endX = (event.getX() - mEventX) / 2 + mEventX;

float endY = (event.getY() - mEventY) / 2 + mEventY;

//画二阶贝塞尔曲线

mPath.quadTo(mEventX, mEventY, endX, endY);

mEventX = event.getX();

mEventY = event.getY();

break;

}

invalidate();

return true; //消费事件

}

}

 类似资料: