初识Xfermode

官方介绍:
           Xfermode是被用来在绘图管道中实现自定义“传输模式”的对象的基类,可以通过调用子类的构造函数且传入Mode(混合模式,下面会说到)

这个类只有一个基类,可能有哥们说:不对,我看的是三个子类;好!官方API让你死心:

这里写图片描述

其他2个类早被移除了!所以接下来我们说说PorterDuffXfermode这个类。


PorterDuffXfermode:

          专门实现Paint的传输模式。有关可用的alpha合成和混合模式的更多信息,请参阅PorterDuff.Mode枚举的文档

这个类的结构很简单,只有一个带有枚举参数的构造方法:

public class PorterDuffXfermode extends Xfermode {
    /**
     * Create an xfermode that uses the specified porter-duff mode.
     *
     * @param mode           The porter-duff mode that is applied
     */
    public PorterDuffXfermode(PorterDuff.Mode mode) {
        porterDuffMode = mode.nativeInt;
    }
}

所以我们的重点就是去了解构造函数中的枚举模式,我们先看下PorterDuff.Mode:


Porter-Duff:

          这个类的名字是对托马斯·波特(Thomas Porter)和汤姆·达夫(Tom Duff)贡献的敬意,也就是这两个人姓氏作为该类的命名,在他们1984年发表的题为“合成数字图像”,在这篇文章中,作者描述了12个合成算法,这些算法管理如何把源图像绘制到目标图像以及呈现的颜色。

“合成数字图像”于1984年7月在Computer Graphics第18卷第3号上发表。

因为波特和达夫的工作仅仅关注源图像和目标图像的alpha通道的影响,原始文件中描述的12个算法在这里被称为alpha合成模式。

这个类还提供了几种混合模式,它们类似地定义了源图像和目标图像的结果,但没有被限制到alpha通道。 这些混合模式不是Porter和Duff定义的,但是为了方便起见,已经包含在这个类中。

以上是来自官网的翻译和个人对Xfermode相关类的理解,若有错误,请指出,不胜感激!


PorterDuff.Mode:

上面,我们提到了PorterDuff.Mode枚举分为两种, alpha合成模式和混合模式,有兴趣的可以去看官网:PorterDuff.Mode(自备梯子),我建议大家最好去自己实现以下这18种模式,这样有利于我们加深理解,我们看下有哪18种模式呢:

public enum Mode {

        CLEAR       (0),

        SRC         (1),

        DST         (2),

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

下面我们挨个去绘制出以上18种模式效果:

注意:在开始绘制前,需要关闭硬件加速,因为有的模式不支持硬件加速,而硬件加速默认开启,你可以在清单文件中关掉:

<Application     android:hardwareAccelerated="false"/>

或则在自定义view中:

 setLayerType(View.LAYER_TYPE_SOFTWARE, null);

你可以尝试下,CLEAR模式下,不关闭硬件加速就不会显示正常效果。

我们按照官网标准(这里是官方截图):
这里写图片描述

分别绘制一张蓝色矩形的源图像、一张红色圆形的目标图像,先绘制目标图像,再绘制源图像,也就是说先绘制红色圆形图像,再绘制蓝色矩形图像,背景是灰色。

SRC模式:

这里写图片描述

说明:只显示源图

CLEAR模式:

这里写图片描述

说明:都未显示,灰色是背景

DST模式:

这里写图片描述

说明:只显示目标图

SRC_OVER模式:

这里写图片描述

说明:源图绘制在目标图的上层

DST_OVER模式:

这里写图片描述

说明:目标图绘制在源图的上层

SRC_IN模式:

这里写图片描述

说明:显示目标图与源图的交集,且只显示源图部分

DST_IN模式:

这里写图片描述

说明:显示目标图与源图的交集,且只显示目标图部分

SRC_OUT模式:

这里写图片描述

说明:保留不包括目标图的源图

DST_OUT模式:

这里写图片描述

说明:保留未被源图覆盖的目标图

SRC_ATOP模式:

这里写图片描述

说明:丢弃不包含的源图

DST_ATOP模式:

这里写图片描述

说明:丢弃未被源图覆盖的目标图

XOR模式:

这里写图片描述

说明:去除源图和目标图的交集

DARKEN模式:

这里写图片描述

说明:保留源像素和目标像素,且交集颜色改变

LIGHTEN模式:
这里写图片描述

说明:保留源图和目标图,且交集颜色改变

MULTIPLY模式:

这里写图片描述

说明:将源像素和目标像素相乘<官方>

SCREEN模式:

这里写图片描述

说明:添加源像素和目标像素,然后减去乘以目标的源像素<官方>

ADD模式:

这里写图片描述

说明:将源像素添加到目标像素并使结果饱和<官方>

OVERLAY模式:

这里写图片描述

说明:取决于目标颜色,将源和目标相乘或屏蔽<官方>


以上就是18种模式混合后的效果,下面贴下实现的代码:

public class PorterDuffModeView extends View {
    Paint paint;
    public PorterDuffModeView(Context context) {
//        super(context);
        this(context, null);
    }

    public PorterDuffModeView(Context context, @Nullable AttributeSet attrs) {
//        super(context, attrs);
        this(context, attrs, 0);
        paint = new Paint();
        //几种混合规则在GPU硬件加速下不起效,如果你觉得混合模式没有正确使用,
        // 可以让调用View.setLayerType(View.LAYER_TYPE_SOFTWARE, null)方法
//        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
    }

    public PorterDuffModeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //离屏缓存
        canvas.drawColor(Color.GRAY);
       int sc=  canvas.saveLayer(0f, 0f, getWidth(), getHeight(), null, Canvas.ALL_SAVE_FLAG);
        canvas.drawBitmap(getBitmapDest(getWidth(),getHeight()), 0, 0, paint);
        //这里设置模式,共18种
         paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.OVERLAY));
        canvas.drawBitmap(getBitmapSrc(getWidth(),getHeight()), 0, 0, paint);

        // 还原混合模式
        paint.setXfermode(null);

        // 还原画布
        canvas.restoreToCount(sc);
    }

    /**
     *  目标图像 红色圆
     * @param width
     * @param height
     * @return
     */
   public static Bitmap getBitmapDest(int width, int height) {

        Bitmap bitmap = Bitmap.createBitmap(width, height,
                Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(Color.parseColor("#E91E63"));
        canvas.drawCircle(width/2 , height / 2, Math.min(width / 4, height / 4), paint);
        return bitmap;
    }

    /**
     *  目标图像 蓝色矩形
     * @param width
     * @param height
     * @return
     */
    public static Bitmap getBitmapSrc(int width, int height) {
        Bitmap bitmap = Bitmap.createBitmap(width, height,
                Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(Color.parseColor("#2196F3"));
        canvas.drawRect(new RectF(0,0.5f*height,0.5f*width,height),paint);
        return bitmap;
    }




}

代码在github,可以clone看下效果!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值