ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Android Paint应用二PorterDuffXfermode

2019-06-28 20:48:42  阅读:492  来源: 互联网

标签:交集 Bitmap Paint PorterDuff PorterDuffXfermode Android 绘制 Mode


这一篇学习Paint的图层混合模式,即mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
PorterDuff.Mode 中提供了18中混合模式

        CLEAR       (0),
        SRC         (1),
        DST         (2),
             /**注释1
         * <p>
         *     <img src="{@docRoot}reference/android/images/graphics/composite_SRC_OVER.png" />
         *     <figcaption>The source pixels are drawn over the destination pixels.</figcaption>
         * </p>
         * <p>\(\alpha_{out} = \alpha_{src} + (1 - \alpha_{src}) * \alpha_{dst}\)</p>
         * <p>\(C_{out} = C_{src} + (1 - \alpha_{src}) * C_{dst}\)</p>
         */
        SRC_OVER    (3),
        DST_OVER    (4),
        SRC_IN      (5),
        DST_IN      (6),
        SRC_OUT     (7),
        DST_OUT     (8),
        SRC_ATOP    (9),      
        DST_ATOP    (10),
        XOR         (11),
        DARKEN      (16),
        LIGHTEN     (17),
        MULTIPLY    (13),
        SCREEN      (14),
        ADD         (12),
        OVERLAY     (15);

以SRC_OVER为例,它的计算规则是这样的(见注释1):
alpha通道值=原图像的alpha值+(1-原图像的alpha值)*目标图像的alpha值
C 颜色通道值 = 原图像的颜色C值+(1-原图像的颜色C值)*目标图像的颜色C值

那么这18种模式是如何进行混合的呢,这里有两点点需要注意,就是src源图像的区域以及dst目标图像的区域,图层混合模式是作用在两者相交的区域,图层混合模式的效果是作用于src源图像的区域,
PorterDuff.Mode.CLEAR 所绘制的图形不会提交到画布上
PorterDuff.Mode.SRC 显示上层图形
PorterDuff.Mode.DST 显示下层图形
PorterDuff.Mode.SRC_OVER 正常绘制,上下层绘制叠盖
PorterDuff.Mode.DST_OVER 正常绘制,下层居上
PorterDuff.Mode.SRC_IN 取两层交集区域,显示上层
PorterDuff.Mode.DST_IN 取两层交集区域,显示下层
PorterDuff.Mode.SRC_OUT 绘制上层非交集部分,交集部分透明
PorterDuff.Mode.DST_OUT 绘制下层非交集部分,交集部分透明
PorterDuff.Mode.SRC_ATOP 绘制上层交集部分与下层非交集部分
PorterDuff.Mode.DST_ATOP 绘制下层交集部分与上层非交集部分
PorterDuff.Mode.XOR 去除上下层交集区域,绘制非交集区域
PorterDuff.Mode.DARKEN 绘制上下层全部区域,交集部分颜色加深
PorterDuff.Mode.LIGHTEN 绘制上下层全部区域,交集部分颜色点亮
PorterDuff.Mode.MULTIPLY 绘制交集区域,交集部分颜色叠加
PorterDuff.Mode.SCREEN 绘制上下层全部区域,交集部分滤色
PorterDuff.Mode.ADD 绘制上下层全部区域,交集部分饱和度相加
PorterDuff.Mode.OVERLAY 绘制上下层全部区域,交集部分叠加
看一下效果图
在这里插入图片描述
这里的效果图和Google官方的效果图不大一样,这里我们贴一下部分代码

  @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;
        //sModes 图层混合集合
        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);
            int sc = canvas.saveLayer(x, y, x + W, y + H, null, Canvas.ALL_SAVE_FLAG);
            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;
            }
        }
    }
        // 画圆一个完成的圆
    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;
    }

以一张图来说明上述代码的绘制区域
在这里插入图片描述

红色区域表示绘制的src图像,灰色是dst图像的绘制区域,在该区域内绘制了绿色的圆,也就是dst图像,两者的交集区域就是黄色部分

下面看一下Google提供的图层混合示例
在这里插入图片描述
onDraw方法里的实现都是一样的,这里我们看一下绘制图形的创建部分

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

在这里插入图片描述
Google的示例中,src、dst图像的绘制区域是充满宽高

无论是src图像,还是dst图像,两者的绘制区域都是填充整个区域,因为两者绘制的区域不同,导致调用图层混合模式后,出现不同的效果。

这里我们以PorterDuff.Mode.DST_ATOP 为例,下层表示效果图中的圆,上层表示方框,它表示绘制下层交集部分与上层非交集部分,在第一种效果图中,绘制下层交集部分,也就是黄色圆与蓝色方框的交集部分,然后绘制上层非交集部分,由于两者绘制的交集区域只有图中的粉色部分,而图层的混合模式只作用于src即蓝色方框,所以出现第一种效果在这里插入图片描述

而在Google的演示代码中,上下层的绘制区域不同,DST_ATOP绘制下层交集部分与上层非交集部分,也就是绘制了交集部分的圆,再绘制非交集部分的方框,故而出现第二种效果
在这里插入图片描述

在图层混合绘制中,有几点需要注意:
1)先绘制的称其为dst,也就是下层图像,后绘制的称其为src,也就是上层图像
2)在绘制开始即使用图层混合模式前,先调用 canvas.saveLayer 进行离屛绘制,绘制完成后调用 canvas.restoreToCount
3)注意src和dst的绘制矩形区域,区域不同会出现不同的效果
4)有需要是需关闭硬件加速setLayerType(View.LAYER_TYPE_SOFTWARE, null)

标签:交集,Bitmap,Paint,PorterDuff,PorterDuffXfermode,Android,绘制,Mode
来源: https://blog.csdn.net/lp598876762/article/details/94013581

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有