Android学习记录045_PorterDuff

本文详细介绍了Android图形绘制中PorterDuff.Mode的16种模式,包括DST、DST_IN、DST_OUT、DST_ATOP等,并通过代码示例展示了每种模式下源像素与目标像素的混合效果,帮助理解其在图形叠加时的行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、PorterDuff.Mode

1.1 PorterDuff.Mode.DST
/**
* The source pixels are discarded, leaving the destination intact.
*/ 
private void test01(Canvas canvas) {
        canvas.drawColor(Color.TRANSPARENT);
        RectF rectF = new RectF(0, 0, 350, 350);
        canvas.saveLayer(rectF, mPaint);
        canvas.drawColor(Color.parseColor("#FFff0000"));
        /**
         *  什么时候调用setXfermode方法很重要
         *  DST:[Da, Dc]
         *  此时DST是画布新建的layer层
         */
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST));
        //0x7F00FF00
        canvas.drawBitmap(srcBmp, 0, 0, mPaint);
        canvas.restore();
     	//混合过后,混合区域中有颜色的结果值是0xffff0000
    }
1.2 PorterDuff.Mode.DST_IN
/**
*Keeps the destination pixels that cover source pixels, discards the remaining source and destination pixels.
*/ 
private void test01(Canvas canvas) {
        canvas.drawColor(Color.TRANSPARENT);
        RectF rectF = new RectF(0, 0, 350, 350);
        canvas.saveLayer(rectF, mPaint);
        canvas.drawColor(Color.parseColor("#FFff0000"));
        /**
         *  什么时候调用setXfermode方法很重要
         *  DST_IN:[Sa * Da, Sa * Dc]
         *  此时DST是画布新建的layer层
         */
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        //0x7F00FF00
        canvas.drawBitmap(srcBmp, 0, 0, mPaint);
        canvas.restore();
        //混合过后,混合区域中有颜色的结果值是0x7fff0000
    }
1.3 PorterDuff.Mode.DST_OUT
/**
*
个人认为这个说法有问题,因为跟得到的结果不一致
Keeps the destination pixels that are not covered by source pixels. Discards destination pixels that are covered by source pixels. Discards all source pixels.
*/
private void test01(Canvas canvas) {
        canvas.drawColor(Color.TRANSPARENT);
        RectF rectF = new RectF(0, 0, 350, 350);
        canvas.saveLayer(rectF, mPaint);
        canvas.drawColor(Color.parseColor("#FFff0000"));
        /**
         *  什么时候调用setXfermode方法很重要
         *  DST_OUT:[Da * (1 - Sa), Dc * (1 - Sa)]
         *  此时DST是画布新建的layer层
         */
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
        //0x7F00FF00
        canvas.drawBitmap(srcBmp, 0, 0, mPaint);
        canvas.restore();
        //混合过后,混合区域中有颜色的结果值是0x80ff0000
    }
1.4 PorterDuff.Mode.DST_ATOP
/**
* 
个人认为说法有问题,因为跟结果不一致。
Discards the destination pixels that are not covered by source pixels. Draws remaining destination pixels over source pixels.
*/  
private void test01(Canvas canvas) {
        canvas.drawColor(Color.TRANSPARENT);
        RectF rectF = new RectF(0, 0, 350, 350);
        canvas.saveLayer(rectF, mPaint);
        canvas.drawColor(Color.parseColor("#FFff0000"));
        /**
         *  什么时候调用setXfermode方法很重要
         *  DST_ATOP:[Sa, Sa * Dc + Sc * (1 - Da)]
         *  此时DST是画布新建的layer层
         */
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP));
        //0x7F00FF00
        canvas.drawBitmap(srcBmp, 0, 0, mPaint);
        canvas.restore();
      //混合过后,混合区域中有颜色的结果值是0x7fff0000
    }
1.5 PorterDuff.Mode.SRC
/**
* The source pixels replace the destination pixels
*/ 
private void test01(Canvas canvas) {
        canvas.drawColor(Color.TRANSPARENT);
        RectF rectF = new RectF(0, 0, 350, 350);
        canvas.saveLayer(rectF, mPaint);
        canvas.drawColor(Color.parseColor("#FFff0000"));
        /**
         *  什么时候调用setXfermode方法很重要
         *  SRC:[Sa, Sc]
         *  此时DST是画布新建的layer层
         */
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
        //0x7F00FF00
        canvas.drawBitmap(srcBmp, 0, 0, mPaint);
        canvas.restore();
        //混合过后,混合区域中有颜色的结果值是0x7f00ff00
    }
1.6 PorterDuff.Mode.SRC_IN
/**
* Keeps the source pixels that cover the destination pixels, discards the remaining source and destination pixels.
*/ 
private void test01(Canvas canvas) {
        canvas.drawColor(Color.TRANSPARENT);
        RectF rectF = new RectF(0, 0, 350, 350);
        canvas.saveLayer(rectF, mPaint);
        canvas.drawColor(Color.parseColor("#FFff0000"));
        /**
         *  SRC_IN:[Sa * Da, Sc * Da]
         *  此时DST是画布新建的layer层
         */
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        //0x7F00FF00
        canvas.drawBitmap(srcBmp, 0, 0, mPaint);
        canvas.restore();
     	//混合过后,混合区域中有颜色的结果值是0x7f00ff00
    }
1.7 PorterDuff.Mode.SRC_OUT
/**
* Keeps the source pixels that do not cover destination pixels. Discards source pixels that cover destination pixels. Discards all destination pixels.
*/  
private void test01(Canvas canvas) {
        canvas.drawColor(Color.TRANSPARENT);
        RectF rectF = new RectF(0, 0, 350, 350);
        canvas.saveLayer(rectF, mPaint);
        canvas.drawColor(Color.parseColor("#FFff0000"));
        /**
         *  什么时候调用setXfermode方法很重要
         *  SRC_OUT:[Sa * (1 - Da), Sc * (1 - Da)]
         *  此时DST是画布新建的layer层
         */
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
        //0x7F00FF00
        canvas.drawBitmap(srcBmp, 0, 0, mPaint);
        canvas.restore();
      //混合过后,混合区域中有颜色的结果值是0x00000000
    }
1.8 PorterDuff.Mode.SRC_ATOP
/**
* Discards the source pixels that do not cover destination pixels. Draws remaining source pixels over destination pixels.
*/
private void test01(Canvas canvas) {
        canvas.drawColor(Color.TRANSPARENT);
        RectF rectF = new RectF(0, 0, 350, 350);
        canvas.saveLayer(rectF, mPaint);
        canvas.drawColor(Color.parseColor("#FFff0000"));
        /**
         *  什么时候调用setXfermode方法很重要
         *  SRC_ATOP:[Da, Sc * Da + (1 - Sa) * Dc]
         *  此时DST是画布新建的layer层
         */
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
        //0x7F00FF00
        canvas.drawBitmap(srcBmp, 0, 0, mPaint);
        canvas.restore();
    	//混合过后,混合区域中有颜色的结果值是0xff807f00
    }
1.9 PorterDuff.Mode.SRC_OVER
/**
* The source pixels are drawn over the destination pixels.
*/
private void test01(Canvas canvas) {
        canvas.drawColor(Color.TRANSPARENT);
        RectF rectF = new RectF(0, 0, 350, 350);
        canvas.saveLayer(rectF, mPaint);
        canvas.drawColor(Color.parseColor("#FFff0000"));
        /**
         *  什么时候调用setXfermode方法很重要
         *  SRC_OVER:[Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc]
         *  此时DST是画布新建的layer层
         */
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));
        //0x7F00FF00
        canvas.drawBitmap(srcBmp, 0, 0, mPaint);
        canvas.restore();
    	 //混合过后,混合区域中有颜色的结果值是0xff807f00
    }
1.10 PorterDuff.Mode.XOR
/**
* 
个人认为说法有问题,因为跟结果不一致。
Discards the source and destination pixels where source pixels cover destination pixels. Draws remaining source pixels.
*/ 
private void test01(Canvas canvas) {
        canvas.drawColor(Color.TRANSPARENT);
        RectF rectF = new RectF(0, 0, 350, 350);
        canvas.saveLayer(rectF, mPaint);
        canvas.drawColor(Color.parseColor("#FFff0000"));
        /**
         *  什么时候调用setXfermode方法很重要
         *  XOR:[Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc]
         *  此时DST是画布新建的layer层
         */
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR));
        //0x7F00FF00
        canvas.drawBitmap(srcBmp, 0, 0, mPaint);
        canvas.restore();
      //混合过后,混合区域中有颜色的结果值是0x80ff0000
    }
1.11 PorterDuff.Mode.DARKEN
/**
*Retains the smallest component of the source and destination pixels.
*/
private void test01(Canvas canvas) {
        canvas.drawColor(Color.TRANSPARENT);
        RectF rectF = new RectF(0, 0, 350, 350);
        canvas.saveLayer(rectF, mPaint);
        canvas.drawColor(Color.parseColor("#FFff0000"));
        /**
         *  什么时候调用setXfermode方法很重要
         *  DARKEN:[Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc)]
         *  此时DST是画布新建的layer层
         */
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DARKEN));
        //0x7F00FF00
        canvas.drawBitmap(srcBmp, 0, 0, mPaint);
        canvas.restore();
       //混合过后,混合区域中有颜色的结果值是0xff800000
    }
1.12 PorterDuff.Mode.LIGHTEN
/**
*Retains the largest component of the source and destination pixel.
*/ 
private void test01(Canvas canvas) {
        canvas.drawColor(Color.TRANSPARENT);
        RectF rectF = new RectF(0, 0, 350, 350);
        canvas.saveLayer(rectF, mPaint);
        canvas.drawColor(Color.parseColor("#FFff0000"));
        /**
         *  什么时候调用setXfermode方法很重要
         *  LIGHTEN:[Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)]
         *  此时DST是画布新建的layer层
         */
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN));
        //0x7F00FF00
        canvas.drawBitmap(srcBmp, 0, 0, mPaint);
        canvas.restore();
     	//混合过后,混合区域中有颜色的结果值是0xffff7f00
    }
1.13 PorterDuff.Mode.MULTIPLY
/**
* Multiplies the source and destination pixels.
*/
private void test01(Canvas canvas) {
        canvas.drawColor(Color.TRANSPARENT);
        RectF rectF = new RectF(0, 0, 350, 350);
        canvas.saveLayer(rectF, mPaint);
        canvas.drawColor(Color.parseColor("#FFff0000"));
        /**
         *  什么时候调用setXfermode方法很重要
         *  MULTIPLY:[Sa * Da, Sc * Dc]
         *  此时DST是画布新建的layer层
         */
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
        //0x7F00FF00
        canvas.drawBitmap(srcBmp, 0, 0, mPaint);
        canvas.restore();
    	//混合过后,混合区域中有颜色的结果值是0x7f000000
    }
1.14 PorterDuff.Mode.SCREEN
/**
* Adds the source and destination pixels, then subtracts the source pixels multiplied by the destination.
*/
private void test01(Canvas canvas) {
        canvas.drawColor(Color.TRANSPARENT);
        RectF rectF = new RectF(0, 0, 350, 350);
        canvas.saveLayer(rectF, mPaint);
        canvas.drawColor(Color.parseColor("#FFff0000"));
        /**
         *  什么时候调用setXfermode方法很重要
         *  SCREEN:[Sa + Da - Sa * Da, Sc + Dc - Sc * Dc]
         *  此时DST是画布新建的layer层
         */
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SCREEN));
        //0x7F00FF00
        canvas.drawBitmap(srcBmp, 0, 0, mPaint);
        canvas.restore();
    	//混合过后,混合区域中有颜色的结果值是0xffff7f00
    }
1.15 PorterDuff.Mode.ADD
/**
*Adds the source pixels to the destination pixels and saturates the result.
*/ 
private void test01(Canvas canvas) {
        canvas.drawColor(Color.TRANSPARENT);
        RectF rectF = new RectF(0, 0, 350, 350);
        canvas.saveLayer(rectF, mPaint);
        canvas.drawColor(Color.parseColor("#FFff0000"));
        /**
         *  什么时候调用setXfermode方法很重要
         *  ADD:[max(0,min(Sa+Da,1)),max(0,min(Sc+Dc,1)]
         *  此时DST是画布新建的layer层
         */
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD));
        //0x7F00FF00
        canvas.drawBitmap(srcBmp, 0, 0, mPaint);
        canvas.restore();
     	//混合过后,混合区域中有颜色的结果值是0xffff7f00
    }
1.16 PorterDuff.Mode.OVERLAY
/**
* Multiplies or screens the source and destination depending on the destination color.
*/ 
private void test01(Canvas canvas) {
        canvas.drawColor(Color.TRANSPARENT);
        RectF rectF = new RectF(0, 0, 350, 350);
        canvas.saveLayer(rectF, mPaint);
        canvas.drawColor(Color.parseColor("#FFff0000"));
        /**
         *  什么时候调用setXfermode方法很重要
         *  OVERLAY:
         *  [
         *  Sa+Da-Sa*Da,
         *  当2*Dc<Da时,2*Sc*Dc
         *  否则,Sa*Da-2(Da-Sc)(Sa-Dc)
         *  ]
         *  此时DST是画布新建的layer层
         */
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.OVERLAY));
        //0x7F00FF00
        canvas.drawBitmap(srcBmp, 0, 0, mPaint);
        canvas.restore();
     	//混合过后,混合区域中有颜色的结果值是0xffff0000
    }

二、源代码

package com.example.imagedemo;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;


import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import androidx.annotation.RequiresApi;

public class ViewDemo12 extends View {

    private int width = 350;
    private int height = 350;
    private Bitmap dstBmp;
    private Bitmap srcBmp;
    private Paint mPaint;

    public ViewDemo12(Context context, AttributeSet attrs) {
        super(context, attrs);
        dstBmp = makeDst(width, height);
        srcBmp = makeSrc(width, height);
        mPaint = new Paint();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    Paint paint = new Paint();

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
//        origin(canvas);
        test01(canvas);
        //test02(canvas);
    }

    private void origin(Canvas canvas) {
        //判断是否经过硬件加速
        //Log.e("View","==="+canvas.isHardwareAccelerated());
        //默认画布的颜色
        canvas.drawColor(Color.WHITE);
//        paint.setColor(Color.RED);
//        canvas.drawRect(0,0,400,100,paint);
        RectF rectF = new RectF(0, 0, 350, 350);
        canvas.saveLayer(rectF, mPaint);
        canvas.drawColor(Color.DKGRAY);
        //目标
        // canvas.drawBitmap(dstBmp, 0, 0, mPaint);
        /**
         *
         * DST:[Da, Dc]
         * SRC:[Sa, Sc]
         * DST_OUT:[Da * (1 - Sa), Dc * (1 - Sa)]
         * SRC_OVER:[Sa + (1 - Sa)*Da, Sc + (1 - Sa)*Dc]
         *
         *
         */
        Log.e("View==Blend", "1 PorterDuff.Mode.SRC");
        /**
         * 什么时候调用setXfermode方法很重要
         */
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST));
//        //源
        canvas.drawBitmap(srcBmp, 0, 0, mPaint);
//        //默认是SRC_OVER
//        Log.e("View==Blend","2 PorterDuff.Mode.DST_IN");
//        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        canvas.restore();
    }

    @RequiresApi(api = Build.VERSION_CODES.Q)
    private void test01(Canvas canvas) {
        canvas.drawColor(Color.TRANSPARENT);
        RectF rectF = new RectF(0, 0, 350, 350);
        canvas.saveLayer(rectF, mPaint);
        canvas.drawColor(Color.parseColor("#FFff0000"));
        /**
         *  什么时候调用setXfermode方法很重要
         *  DST:[Da, Dc]
         *  SRC:[Sa, Sc]
         *  SRC_OVER:[Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc]
         *  DST_OVER:[Sa + (1 - Sa)*Da, Rc = Dc + (1 - Da)*Sc]
         *  SRC_IN:[Sa * Da, Sc * Da]
         *  DST_IN:[Sa * Da, Sa * Dc]
         *  SRC_OUT:[Sa * (1 - Da), Sc * (1 - Da)]
         *  DST_OUT:[Da * (1 - Sa), Dc * (1 - Sa)]
         *  SRC_ATOP:[Da, Sc * Da + (1 - Sa) * Dc]
         *  DST_ATOP:[Sa, Sa * Dc + Sc * (1 - Da)]
         *  XOR:[Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc]
         *  DARKEN:[Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc)]
         *  LIGHTEN:[Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)]
         *  MULTIPLY:[Sa * Da, Sc * Dc]
         *  SCREEN:[Sa + Da - Sa * Da, Sc + Dc - Sc * Dc],
         *  ADD:[max(0,min(Sa+Da,1)),max(0,min(Sc+Dc,1)]
         *  OVERLAY:
         *  [
         *  Sa+Da-Sa*Da,
         *  当2*Dc<Da时,2*Sc*Dc
         *  否则,Sa*Da-2(Da-Sc)(Sa-Dc)
         *  ]
         *  此时DST是画布新建的layer层
         */
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        //0x7F00FF00
        canvas.drawBitmap(srcBmp, 0, 0, mPaint);
        canvas.restore();
    }



    private void test02(Canvas canvas) {
        canvas.drawColor(Color.WHITE);
        RectF rectF = new RectF(0, 0, 350, 350);
        canvas.saveLayer(rectF, mPaint);
        canvas.drawColor(Color.DKGRAY);

        //目标
        canvas.drawBitmap(dstBmp, 0, 0, mPaint);
        /**
         *
         * DST:[Da, Dc]
         */
        /**
         * 什么时候调用setXfermode方法很重要
         */
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        canvas.drawBitmap(srcBmp, 0, 0, mPaint);

        mPaint.setXfermode(null);
        canvas.restore();
    }

    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(0xFFFF0000);
        c.drawOval(new RectF(20, 20, 100, 100), p);
        return bm;
    }

    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(0x7F00FF00);
        c.drawRect(0, 0, 250, 250, p);
        return bm;
    }

}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值