Android图像处理——Paint之Xfermode

转载请注明出处:http://blog.csdn.net/allen315410/article/details/45077165

上篇博客中,我将我对Paint的ColorFilter相关的几个子类以及用法做了总结,其中最常用的ColorMatrixColorFilter值得我们多学习学习,通过定义一个color值的4*5的矩阵,来设置Paint的各种各样的变色效果。此外,还有PorterDuffColorFilter,其实用的并不是很多,但是PorterDuffColorFilter中使用的几个概念尤其重要,我们要好好了解一下,PorterDuff是老外发明的一直图形混合模式,并且Android 的API中为我们提供了18种不同的混合模式算法,我们平时在开发的时候需要了解这些模式分别代表的含义和用法,就是灵活的运用这些模式随意混合出我们需要的图像效果。

Xfermode

Xfermode具体怎么翻译,说实话,我也不知道,我习惯叫它图片混合模式,随便了,管它叫什么,不妨碍我们使用它。关于Xfermode的说明,可以在Google文档中找到这样的描述:Xfermode是在绘图通道中自定义“传输模式”的基类。静态函数创建可以调用或者返回任意作为模式枚举指定的预定义子类实例。当Xfermode分配给Paint,然后绘制对象与Paint就具备了所添加的xfermode。读起来比较拗口,下面直接看Xfermode的源码:

public class Xfermode {

    protected void finalize() throws Throwable {
        try {
            finalizer(native_instance);
        } finally {
            super.finalize();
        }
    }

    private static native void finalizer(long native_instance);

    long native_instance;
}

看,Xfermode就这么点代码,经验告诉我们,其下必有子类,擦,变元芳了~~~

查看一下文档发现Xfermode确实有AvoidXfermode、PixelXorXfermode、PorterDuffXfermode,下面来继续学习一下3个子类的用法。

AvoidXfermode

看这个子类之前告诉大家一个不幸的消息,AvoidXfermode不支持硬件加速,在高于API16的机器上不会适用,如果想测试这个子类,1,可以关闭手机的硬件加速模块;2,在AndroidManifest.xml中Application节点上设置硬件加速为false。

android:hardwareAccelerated="false"

在Android Studio下点击查看一下AvoidXfermode的构造方法:

public AvoidXfermode(int opColor, int tolerance, Mode mode)

AvoidXfermode的构造方法也特别简单,一共接收3个参数:第一个参数opColor是一个16进制的带透明度通道的颜色值,如0X12345678。第二个参数tolerance表示容差值,什么是容差值呢?可以理解成一个表示“精确”和“模糊”的概念,下面会解释一下。第三个参数是AvoidXfermode的模式,AvoidXfermode的模式一共有两种:AvoidXfermode.Mode.TARGET和AvoidXfermode.Mode.AVOID。

AvoidXfermode.Mode.TARGET

在该模式下Android会判断画布上的颜色是否会有跟opColor不一样的颜色,比如我opColor是红色,那么在TARGET模式下就会去判断我们的画布上是否有存在红色的地方,如果有,则把该区域“染”上一层我们画笔定义的颜色,否则不“染”色,而tolerance容差值则表示画布上的像素和我们定义的红色之间的差别该是多少的时候才去“染”的,比如当前画布有一个像素的色值是(200, 20, 13),而我们的红色值为(255, 0, 0),当tolerance容差值为255时,即便(200, 20, 13)并不等于红色值也会被“染”色,容差值越大“染”色范围越广反之则反,空说无凭我们来看看具体的实现和效果:

public class CustomView3 extends View {

    private Paint mPaint;
    private Bitmap mBitmap;
    private Context mContext;
    private int x, y, w, h;
    private AvoidXfermode avoidXfermode;

    public CustomView3(Context context) {
        this(context, null);
    }

    public CustomView3(Context context, AttributeSet attrs) {
        super(context, attrs);
        mContext = context;
        initRes();
        initPaint();

    }

    private void initRes() {
        //加载bitmap
        mBitmap = BitmapFactory.decodeResource(mContext.getResources(), R.mipmap.image);
        //获取bitmap的展示起始布局
        x = ScreenUtil.getScreenW(mContext) / 2 - mBitmap.getWidth() / 2;
        y = ScreenUtil.getScreenH(mContext) / 2 - mBitmap.getHeight() / 2;
        w = ScreenUtil.getScreenW(mContext) / 2 + mBitmap.getWidth() / 2;
        h = ScreenUtil.getScreenH(mContext) / 2 + mBitmap.getHeight() / 2;
    }

    private void initPaint() {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        avoidXfermode = new AvoidXfermode(0XFFFFFFFF, 0, AvoidXfermode.Mode.TARGET);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawBitmap(mBitmap, x, y, mPaint);
        mPaint.setARGB(255, 211, 53, 243);
        mPaint.setXfermode(avoidXfermode);
        canvas.drawRect(x, y, w, h, mPaint);
    }
}

下面来运行看效果,首先确定一下开启的模拟器是API16以下的,或者Application节点下设置了关闭“硬件加速”:

AvoidXfermode(0XFFFFFFFF, 0, AvoidXfermode.Mode.TARGET):

大家可以看到,在我们的模式为TARGET容差值为0的时候此时只有当图片中像色颜色值为0XFFFFFFFF的地方才会被染色,而其他地方不会有改变

下面我们来修改一下容差值,将容差值改成255:

AvoidXfermode(0XFFFFFFFF, 255, AvoidXfermode.Mode.TARGET)

而当容差值为255的时候只要是跟0XFFFFFFFF有点接近的地方都会被染色

AvoidXfermode.Mode.AVOID

则与TARGET恰恰相反,TARGET是我们指定的颜色是否与画布的颜色一样,而AVOID是我们指定的颜色是否与画布不一样,其他的都与TARGET类似

AvoidXfermode(0XFFFFFFFF, 0, AvoidXfermode.Mode.AVOID):

当模式为AVOID容差值为0时,只有当图片中像素颜色值与0XFFFFFFFF完全不一样的地方才会被染色

AvoidXfermode(0XFFFFFFFF, 255, AvoidXfermode.Mode.AVOID):

当容差值为255时,只要与0XFFFFFFFF稍微有点不一样的地方就会被染色

那么这玩意究竟有什么用呢?比如说当我们只想在白色的区域画点东西或者想把白色区域的地方替换为另一张图片的时候就可以采取这种方式!

PixelXorXfermode

PixelXorXfermode是Xfermode下的另外一种图像混排模式,该类特别简单,不过呢,也很不幸的,在API16中已经过时了。我们来做一个简单的了解,先看PixelXorXfermode的构造方法:

public PixelXorXfermode(int opColor) 

构造方法很简单,只要传递一个16进制带透明通道的颜色值即可,那么这个参数有什么用呢?我在Google文档中,找到了这样的一个算法:实际上PixelXorXfermode内部是按照“opColor ^ src ^ dst”这个异或算法运算的,得到一个不透明的(alpha = 255)的色彩值,设置到图像中,下面我们接着上面用到的图片Demo写个PixelXorXfermode的Demo:

public class CustomView3 extends View {

    private Paint mPaint;
    private Bitmap mBitmap;
    private Context mContext;
    private int x, y, w, h;
    private PixelXorXfermode pixelXorXfermode;

    public CustomView3(Context context) {
        this(context, null);
    }

    public CustomView3(Context context, AttributeSet attrs) {
        super(context, attrs);
        mContext = context;
        initRes();
        initPaint();

    }

    private void initRes() {
        //加载bitmap
        mBitmap = BitmapFactory.decodeResource(mContext.getResources(), R.mipmap.image);
        //获取bitmap的展示起始布局
        x = ScreenUtil.getScreenW(mContext) / 2 - mBitmap.getWidth() / 2;
        y = ScreenUtil.getScreenH(mContext) / 2 - mBitmap.getHeight() / 2;
        w = ScreenUtil.getScreenW(mContext) / 2 + mBitmap.getWidth() / 2;
        h = ScreenUtil.getScreenH(mContext) / 2 + mBitmap.getHeight() / 2;
    }

    private void initPaint() {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        pixelXorXfermode = new PixelXorXfermode(0XFFFF0000);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        //先绘制Bitmap,src
        canvas.drawBitmap(mBitmap, x, y, mPaint);
        //随便设置一个纯色测试
        mPaint.setARGB(255, 211, 53, 243);
        //设置Xfermode
        mPaint.setXfermode(pixelXorXfermode);
        //在bitmap上混排一个纯色的矩形(dst)
        canvas.drawRect(x, y, w, h, mPaint);
    }
}

混排后的图像是:

PixelXorXfermode在底层已经取出src,dst每个像素点与opColor进行了opColor ^ src ^ dst运算了,结果输出就是上图所示的那样!好了,我只学这么多了,因为它已经过时了,同样上面的AvoidXfermode也是,过时了,了解即可。下面是对Xfermode的第三个子类,也是唯一一个还没有过时的,非常重要的子类PorterDuffXfermode的学习。

PorterDuffXfermode

同样PorterDuffXfermode也是Xfermode的子类,我们先看看它的构造方法:

public PorterDuffXfermode(PorterDuff.Mode mode)

PorterDuffXfermode的构造方法很简单,构造方法中需要传递一个PorterDuff.Mode参数,关于PorterDuff.Mode,我们在上篇博客中已经学习完了,其实跟ColorFilter的子类PorterDuffColorFilter的混排模式是一样的。Android系统一共提供了18种混排模式,在模拟器的ApiDemos/Graphics/XferModes,有张效果图:

这张图可以很形象的说明图片各种混排模式下的效果。其中Src代表原图,Dst代表目标图,两张图片使用不同的混排方式后,得到的图像是如上图所示的。PorterDuff.Mode也提供了18种混排模式已经算法,其中比上图多了ADD和OVERLAY两种模式:

其中Sa全称为Source alpha表示源图的Alpha通道;Sc全称为Source color表示源图的颜色;Da全称为Destination alpha表示目标图的Alpha通道;Dc全称为Destination color表示目标图的颜色,[...,..]前半部分计算的是结果图像的Alpha通道值,“,”后半部分计算的是结果图像的颜色值。图像混排后是依靠这两个值来重新计算ARGB值的,具体计算算法,抱歉,我也不知道,不过不要紧,不了解计算算法也不影响我们程序员写程序的。我们只要对照上面的apiDemo中提供的图片就能推测出混排后的结果的,下面将会对照ApiDemos/Graphics/XferModes的程序进行修改,来测试各个模块的效果,测试程序如下:

public class XfermodeView extends View {

    //PorterDuff模式常量 可以在此更改不同的模式测试
    private static final PorterDuff.Mode MODE = PorterDuff.Mode.CLEAR;
    private PorterDuffXfermode porterDuffXfermode;
    private int screenW, screenH; //屏幕宽高
    private Bitmap srcBitmap, dstBitmap;
    //源图和目标图宽高
    private int width = 120;
    private int height = 120;

    public XfermodeView(Context context) {
        this(context, null);
    }

    public XfermodeView(Context context, AttributeSet attrs) {
        super(context, attrs);
        screenW = ScreenUtil.getScreenW((Activity) context);
        screenH = ScreenUtil.getScreenH((Activity) context);
        //创建一个PorterDuffXfermode对象
        porterDuffXfermode = new PorterDuffXfermode(MODE);
        //创建原图和目标图
        srcBitmap = makeSrc(width, height);
        dstBitmap = makeDst(width, height);
    }

    //创建一个圆形bitmap,作为dst图
    private 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;
    }

    // 创建一个矩形bitmap,作为src图
    private 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) {
        Paint paint = new Paint();
        paint.setFilterBitmap(false);
        paint.setStyle(Paint.Style.FILL);
        //绘制“src”蓝色矩形原图
        canvas.drawBitmap(srcBitmap, screenW / 8 - width / 4, screenH / 12 - height / 4, paint);
        //绘制“dst”黄色圆形原图
        canvas.drawBitmap(dstBitmap, screenW / 2, screenH / 12, paint);

        //创建一个图层,在图层上演示图形混合后的效果
        int sc = canvas.saveLayer(0, 0, screenW, screenH, 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);

        //先绘制“dst”黄色圆形
        canvas.drawBitmap(dstBitmap, screenW / 4, screenH / 3, paint);
        //设置Paint的Xfermode
        paint.setXfermode(porterDuffXfermode);
        canvas.drawBitmap(srcBitmap, screenW / 4, screenH / 3, paint);
        paint.setXfermode(null);
        // 还原画布
        canvas.restoreToCount(sc);
    }
}

为了方便观察,需要将Activity_main.xml的背景色设置为黑色。

1.PorterDuff.Mode.CLEAR。中文描述:所绘制源图像不会提交到画布上。

private static final PorterDuff.Mode MODE = PorterDuff.Mode.CLEAR;

2.PorterDuff.Mode.SRC。中文描述:只显示源图像。

private static final PorterDuff.Mode MODE = PorterDuff.Mode.SRC;

3.PorterDuff.Mode.DST。中文描述:只显示目标图像。

private static final PorterDuff.Mode MODE = PorterDuff.Mode.DST;

4.PorterDuff.Mode.SRC_OVER。中文描述:正常绘制显示,源图像居上显示。

private static final PorterDuff.Mode MODE = PorterDuff.Mode.SRC_OVER;

5.PorterDuff.Mode.DST_OVER。中文描述: 上下层都显示。目标图像居上显示。

private static final PorterDuff.Mode MODE = PorterDuff.Mode.DST_OVER;

6.PorterDuff.Mode.SRC_IN。中文描述: 取两层绘制交集中的源图像。

private static final PorterDuff.Mode MODE = PorterDuff.Mode.SRC_IN;

7.PorterDuff.Mode.DST_IN。中文描述:取两层绘制交集中的目标图像。

private static final PorterDuff.Mode MODE = PorterDuff.Mode.DST_IN;

8.PorterDuff.Mode.SRC_OUT。中文描述:只在源图像和目标图像不相交的地方绘制源图像。

private static final PorterDuff.Mode MODE = PorterDuff.Mode.SRC_OUT;

9.PorterDuff.Mode.DST_OUT。中文描述:只在源图像和目标图像不相交的地方绘制目标图像。

private static final PorterDuff.Mode MODE = PorterDuff.Mode.DST_OUT;

10.PorterDuff.Mode.SRC_ATOP。中文描述:在源图像和目标图像相交的地方绘制源图像,在不相交的地方绘制目标图像。

private static final PorterDuff.Mode MODE = PorterDuff.Mode.SRC_ATOP;

11.PorterDuff.Mode.DST_ATOP。中文描述:在源图像和目标图像相交的地方绘制目标图像而在不相交的地方绘制源图像。

private static final PorterDuff.Mode MODE = PorterDuff.Mode.DST_ATOP;

12.PorterDuff.Mode.XOR。中文描述:异或:去除两图层交集部分

private static final PorterDuff.Mode MODE = PorterDuff.Mode.XOR;

13.PorterDuff.Mode.DARKEN。中文描述:取两图层全部区域,交集部分颜色加深

private static final PorterDuff.Mode MODE = PorterDuff.Mode.DARKEN;

14.PorterDuff.Mode.LIGHTEN。中文描述:取两图层全部,点亮交集部分颜色

private static final PorterDuff.Mode MODE = PorterDuff.Mode.LIGHTEN;

15.PorterDuff.Mode.MULTIPLY。中文描述:取两图层交集部分叠加后颜色

private static final PorterDuff.Mode MODE = PorterDuff.Mode.MULTIPLY;

16.PorterDuff.Mode.SCREEN。中文描述:滤色。

private static final PorterDuff.Mode MODE = PorterDuff.Mode.SCREEN;

以下是android中新加的两种模式:

17.ADD。中文描述:饱和度相加。

private static final PorterDuff.Mode MODE = PorterDuff.Mode.ADD;

18.OVERLAY。中文描述:叠加

private static final PorterDuff.Mode MODE = PorterDuff.Mode.OVERLAY;

源码请在这里下载,ps:源码在Android Studio中构建。

时间: 2024-11-05 01:03:29

Android图像处理——Paint之Xfermode的相关文章

Android图像处理——Paint之ColorFilter

转载请注明出处:http://blog.csdn.net/allen315410/article/details/45059989 平时在Android开发中,一般不太可能频繁使用到Paint--画笔.但是在某些特殊的情况下,例如 自定义控件(继承View)的时候,有时候就需要请出画笔在画布(Canvas,将下篇文章中讲述Canvas)上像"画"出我们想要的元素.然而,很多开发人员对画笔Paint的了解知之甚少,包括我自己在内,所以在今天在这里总结一下Paint的在Android图像处

Android图像处理(二)--Paint,Canvas,ColorMatrix详细

android开发中可能经常会用到这些东西; 一.介绍 Paint:画笔 Canvas:画布 Matrix:变换矩阵 Paint 根据我们要画的类型,我们可以选择不同的笔,比如大气磅礴的山水画,我们可以选择大头的毛笔:细腻入微的肖像画我们可以选择尖头的铅笔.并且根据我们想要的效果,我们在绘画的时候,还会选择不同的颜料或不同颜色的笔: 那么在程序中,Paint 就足以满足以上所有的需要,我们可以根据我们自己的需要去自行设置我们画笔的属性,首先来看看都能设置哪些属性: Public Construc

[Android] 图像处理软件整合之处理ColorMatrix和Intend传递路径显示图像

    经过几门考试之后,终于有时间整合下自己的Anroid项目"随手拍"的图像处理部分了,主要是结合前面几篇文章讲解的各种android图像处理技术和PopupWindow布局,图像初步整合效果如下.由于该软件目前还未答辩,所以结束后会共享所有的源代码,可能需要一个月后吧,抱歉~               在"随手拍"中点击发布,有添加图片按钮,点击出现"选择本地图片"和"照相截拆选择",显示图片至另一个处理界面,底部五个

android 图像处理(黑白,模糊,浮雕,圆角,镜像,底片,油画,灰白,加旧,哈哈镜,放大镜)

转载文章请注明出处:http://blog.csdn.net/dangxw_/article/details/25063673 前些天在github上得到一个关于图像处理的源码(地址找不到了),挺全面,闲了分享一下.感谢开源. 对于图片的反转,倾斜,缩放之类的操作就不提了,网上太多了.大多都是用的Matrix现成方法. 原图: 一:圆角处理 效果: 代码: public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, float round

24.Android之Paint和canvas简单应用学习

在Android中需要通过graphics类来显示2D图形,graphics中包括了Canvas(画布).Paint(画笔).Color(颜色).Bitmap(图像)等常用的类.graphics具有绘制点.线.颜色.2D几何图形.图像处理等功能. 1.Paint(画笔)类 要绘制图形,首先得调整画笔,按照自己的开发需要设置画笔的相关属性.Pain类的常用属性设置方法如下: setAntiAlias(); //设置画笔的锯齿效果 setColor(); //设置画笔的颜色 setARGB(); /

【转】(转)【Android】Paint的效果研究

转自:http://wpf814533631.iteye.com/blog/1847661 (转)[Android]Paint的效果研究 博客分类: android 在Paint中有很多的属性可以设置,比如可以设置阴影,颜色过滤等等,这些会产生不同的奇妙效果,今天就对各种属性探索一下. 方法一: 1 //设置绘制的颜色,a代表透明度,r,g,b代表颜色值. 2 setARGB(int a,int r,int g,int b); 这个不多说了,还有两个类似的方法,将设置alpha和rgb分割开来了

android图像处理系列之三--图片色调饱和度、色相、亮度处理

原图: 处理后: 下面贴代码: 一.图片处理层: [java] view plaincopy package com.jacp.tone.view; import java.util.ArrayList; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.ColorMatrix; import android

Android绘图机制与处理技巧(二)——Android图像处理之色彩特效处理

Android对于图片处理,最常使用到的数据结构是位图--Bitmap,它包含了一张图片所有的数据.整个图片都是由点阵和颜色值组成的,所谓点阵就是一个包含像素的矩阵,每一个元素对应着图片的一个像素.而颜色值--ARGB,分别对应透明图.红.绿.蓝这四个通道分量,它们共同决定了每个像素点显示的颜色. 色彩矩阵分析 在色彩处理中,通常使用以下三个角度来描述一个图像. 色调--物体传播的颜色 饱和度--颜色的纯度,从0(灰)到100%(饱和)来进行描述 亮度--颜色的相对明暗程度 而在Android中

android图像处理系列之四--给图片添加边框(上)

图片处理时,有时需要为图片加一些边框,下面介绍一种为图片添加简单边框的方法. 基本思路是:将边框图片裁剪成八张小图片(图片大小最好一致,不然后面处理会很麻烦),分别对应左上角,左边,左下角,下边,右下角,右边,右上角,上边,其中左右上下只需要一个有效长度,就像重写水平进度条一样,只需要一个有效的长度,然后平铺,就达到了最后想要的效果,不错,左右上下边采用的也是这样的思路.也可以将八张图片组合在一起,然后读取整张图片,用代码裁剪,下面会给出相应的代码.下面的代码主要是给出第一种方法,后一种给出代码