图像混合利器—Xfermode应用

现在来搞一下Xfermode的知识点,先拿出Xfermode的代码研究一下:

private static final Xfermode[] sModes = {
            /** [0, 0] */
            new PorterDuffXfermode(PorterDuff.Mode.CLEAR),//在该区域里什么都不显示 
            /** [Sa, Sc] */
            new PorterDuffXfermode(PorterDuff.Mode.SRC),//在该区域里只显示原图  
            /** [Da, Dc] */
            new PorterDuffXfermode(PorterDuff.Mode.DST),//在该区域里只显示目标图  
            /** [Da, Sc * Da + (1 - Sa) * Dc] */
            new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP),//在该区域显示目标图并且相交部分显示原图  
            /** [Sa, Sa * Dc + Sc * (1 - Da)] */
            new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP),//在该区域显示原图并且相交部分显示目标图  
            /** [Sa * Da, Sc * Da] */
            new PorterDuffXfermode(PorterDuff.Mode.SRC_IN),//在该区域只显示相交区域且显示相交部分的原图  
            /** [Sa * Da, Sa * Dc] */
            new PorterDuffXfermode(PorterDuff.Mode.DST_IN),//在该区域只显示相交区域且显示相交部分的目标图  
            /** [Sa * Da, Sc * Dc] */
            new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY),//在该区域只显示相交区域且显示两种的叠加颜色  
            /** [Sa * (1 - Da), Sc * (1 - Da)] */
            new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT),//在该区域显示非相交部分的原图  
            /** [Da * (1 - Sa), Dc * (1 - Sa)] */
            new PorterDuffXfermode(PorterDuff.Mode.DST_OUT),//在该区域显示非相交部分的目标图  

            /** [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] */
            new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER),//在该区域全部显示且原图在目标图的上方  
            /** [Sa + (1 - Sa)*Da, Rc = Dc + (1 - Da)*Sc] */
            new PorterDuffXfermode(PorterDuff.Mode.DST_OVER),//在该区域全部显示且目标图在原图的上方  
            /** [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc] */
            new PorterDuffXfermode(PorterDuff.Mode.XOR),//在该区域全部显示并且相交部分显示透明 
            /** [Sa + Da - Sa*Da,Sc*(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc)] */
            new PorterDuffXfermode(PorterDuff.Mode.DARKEN),//在该区域全部显示且相交部分的颜色变深  
            /** [Sa + Da - Sa*Da,Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)] */
            new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN),//在该区域全部显示且相交部分的颜色变亮  
            /** [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] */
            new PorterDuffXfermode(PorterDuff.Mode.SCREEN),//在该区域全部显示且相交部分滤掉原图的颜色
            /** Saturate(S + D) */
            new PorterDuffXfermode(PorterDuff.Mode.ADD),//在该区域全部显示且相交部分饱和度相加  
            new PorterDuffXfermode(PorterDuff.Mode.OVERLAY)//在该区域全部显示且相交部分为叠加的颜色  
    };

解释:

         1、Sa代表源alpha值,Da代表目标alpha值,Sc代表源色值,Dc代表目标色值

         2、设置Xfermode的为源图

so 列举几个进行分析:

1、PorterDuff.Mode.CLEAR   /** [0, 0] */

//根据公式可知,不管源图和目标图如何都将置为0,在该区域里什么都不显示


2、PorterDuff.Mode.SRC_ATOP       /** [Da, Sc * Da + (1 - Sa) * Dc] */

(1)当源图不相交部分(Da,Dc都为0):[0,0]则不显示;

(2)当目标图不相交部分(Sa,Sc都为0)  :[Da,Dc]则显示目标图;

(3)源图和目标图相交部分则主要显示目标图


3、PorterDuff.Mode.DST_ATOP    /** [Sa, Sa * Dc + Sc * (1 - Da)] */

//有公式可知,

(1)当源图不相交部分(Da,Dc都为0):[Sa,Sc]则显示源图;

(2)当目标图不相交部分(Sa,Sc都为0)  :[0,0]则不显示;

         (3)源图和目标图相交部分则主要显示源图

4、PorterDuff.Mode.DST_IN   /** [Sa * Da, Sa * Dc] */

 //在该区域只显示相交区域且显示相交部分的目标图

5、PorterDuff.Mode.XOR     /** [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc] */

//有公式可知,

(1)当源图不相交部分(Da,Dc都为0):[Sa,Sc]则显示源图;

(2)当目标图不相交部分(Sa,Sc都为0)  :[Da,Dc]则显示目标图;

 (3)源图和目标图相交部分如果Da和Sa都不为0的情况下则显示透明

具体代码如下:

    // 创建一个圆形图片,m
    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, 2*w/3, 2*h/3), p);
        return bm;
    }

    // 创建一个矩形Bitmap,命名为原图片
    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.GRAY);
            Paint paint = new Paint();
            canvas.drawBitmap(mSrcB, screenW / 8 - W / 4, screenH / 12, paint);
            canvas.drawBitmap(mDstB, screenW / 2, screenH / 12+H/3, 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);
            canvas.drawBitmap(mDstB, screenW / 4, screenH / 3, paint);//圆形
            //设置Paint的Xfermode
            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
            canvas.drawBitmap(mSrcB, screenW / 4, screenH / 3, paint);//矩形
            paint.setXfermode(null);
            //还原画布
            canvas.restoreToCount(sc);
        }
    }

Xfermode应用:

一、实现波动文字

// 存为新图层
        int saveLayerCount = canvas.saveLayer(0, 0, width, height, paint,
                Canvas.ALL_SAVE_FLAG);
        canvas.drawBitmap(dest, bitSrc, bitDest, paint);
        paint.setXfermode(mode);//设置SRC_IN模式,显示相交部分并且相交部分为原图
        canvas.drawRect(dynamicRectF, paint);
        paint.setXfermode(null);
        canvas.restoreToCount(saveLayerCount);</span>
然后通过改变dynamicRecF的位置来实现动画效果
currentTop = currentTop - 1;
        try {
            Thread.sleep((int) (Math.random() * 100));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (dynamicRectF.top <= height / 2) {
            currentTop = height / 2 + dest.getHeight();
        }
        dynamicRectF.top = currentTop;
        dynamicRectF.bottom = currentTop + dest.getHeight();
        postInvalidate();//更新</span>

二、实现圆形头像

步骤:

                *先将一个圆生成一个图片

private Bitmap getCircleBit() {
        Bitmap blank = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(blank);
        Paint paint = new Paint();
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(Color.RED);
        paint.setAntiAlias(true);
        radius = Math.min(getWidth() / 2, getHeight() / 2);
        canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius, paint);
        return blank;
    }</span>
                  *得到ImageView的图片并进行缩放
Drawable drawable = getDrawable();
        //开始对图片进行缩放
        //1得到图片的宽高
        int dW = drawable.getIntrinsicWidth();
        int dH = drawable.getIntrinsicHeight();
        System.out.println("dW:" + dW + "    dH:" + dH);
        float scale = 1.0f;//3得到缩放比例
        //2判断 图片在圆内  圆在图片内
        if (dW <= (2 * radius) || dH <= (2 * radius)) {
            //图片在圆内
            scale = Math.max((2 * radius * 1.0f) / dW, (2 * radius * 1.0f) / dH);
        } else {
            //圆在图片内
            scale = Math.max((2 * radius * 1.0f) / dW, (2 * radius * 1.0f) / dH);
        }
        drawable.setBounds(0, 0, dW, dH);
        ivBitmap = scaleDrawable(drawable, scale);
        circlePaint = new Paint();
        circlePaint.setAntiAlias(true);
        circlePaint.setFilterBitmap(false);
        mode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);
    }

    private Bitmap scaleDrawable(Drawable drawable, float scale) {
        Bitmap blank = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(blank);
        drawable.draw(canvas);
        Matrix matrix = new Matrix();
        matrix.setScale(scale, scale);//根据传递过来的值进行缩放
        Bitmap newBitmap = Bitmap.createBitmap(blank, 0, 0,drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), matrix, false);
        //注意第四个参数和第五个参数要为原始图片的大小
        return newBitmap;
    }</span>
                 *在onDraw方法里面进行显示
@Override
    protected void onDraw(Canvas canvas) {
        //super.onDraw(canvas);//屏蔽掉父类的onDraw方法
        Bitmap blank = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
        Canvas drawCanvas = new Canvas(blank);
        drawCanvas.drawBitmap(ivBitmap, 0, 0, circlePaint);
        circlePaint.setXfermode(mode);
        drawCanvas.drawBitmap(CircleBit, 0, 0, circlePaint);
        circlePaint.setXfermode(null);
        canvas.drawBitmap(blank, 0, 0, null);
    }</span>

三、实现撕美女衣服的功能

实现这种功能有两种思路:1、使用Bitmap.setPixel(x,y,Color.TRANSPARENT)  2、使用Xfermode来实现

1、使用Bitmap.setPixel(x,y,Color.TRANSPARENT)来实现

       Bitmap up_bit = BitmapFactory.decodeResource(getResources(), R.drawable.g7_up);
        Bitmap bottom_bit = BitmapFactory.decodeResource(getResources(), R.drawable.g7_back);
        bottom.setImageBitmap(bottom_bit);
        blank = Bitmap.createBitmap(up_bit.getWidth(), up_bit.getHeight(), Bitmap.Config.ARGB_8888);//创建一个具有透明度的空白图片
        Canvas canvas = new Canvas(blank);//将空白的图片加入画布中
        canvas.drawBitmap(up_bit, 0, 0, null);//画布画出图片
        top.setImageBitmap(blank);
        top.setOnTouchListener(this);//为顶部的控件设置触摸事件
    }
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
                //以触摸点作为中心点,边长为40的矩形区域设置透明
                for (float i = event.getX() - 20; i < event.getX() + 20; i++) {
                    for (float j = event.getY() - 20; j < event.getY() + 20; j++) {
                        if (i >= 0 && i <= blank.getWidth() && j >= 0 && j <= blank.getHeight()) {
                            blank.setPixel((int) i, (int) j, Color.TRANSPARENT);//为图片的点设置透明
                        }
                    }
                }
                top.setImageBitmap(blank);//每次对图片进行了设置都需要将设置后的图片存入ImageView控件中
                break;
        }
        return true;
    }
2、使用Xfermode来实现:
 try {
            g7_up = R.drawable.class.getDeclaredField("g7_up").getInt(this);//利用反射得到resId,这样的好处
            /**
             * 可以通过for循环遍历
             * for(int i = 0 ; i < 100 ; i++){
             *     list.add(R.drawable.class.getDeclaredField(String.format("g%02d_up",i).getInt(this));
             * }
             */
            g7_back = R.drawable.class.getDeclaredField("g7_back").getInt(this);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        Bitmap top_bit = BitmapFactory.decodeResource(getResources(), g7_up);
        Bitmap bottom_bit = BitmapFactory.decodeResource(getResources(), g7_back);
        bottom.setImageBitmap(bottom_bit);

        paint = new Paint();
        paint.setAlpha(0);
        paint.setStyle(Paint.Style.FILL);
        paint.setAntiAlias(true);//用来防止边缘的锯齿
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
         //CLEAR    /** [0, 0] */                       Sa=0时,相交部分透明 可以
         //SRC     /** [Sa, Sc] */                      Sa=0时,相交部分透明  可以
         //SRC_IN  /** [Sa * Da, Sc * Da] */            Sa=0时,相交部分透明 可以
         //SRC_OUT /** [Sa * (1 - Da), Sc * (1 - Da)] */Sa=0时,相交部分透明 可以
         //DST_IN  /** [Sa * Da, Sa * Dc] */            Sa=0时,相交部分透明  可以
         //DST_OUT /** [Da * (1 - Sa), Dc * (1 - Sa)] */Sa=0时,相交部分不透明 不可以
        blank = Bitmap.createBitmap(top_bit.getWidth(), top_bit.getHeight(), Bitmap.Config.ARGB_4444);
        canvas = new Canvas(blank);
        canvas.drawBitmap(top_bit, 0, 0, null);
        top.setImageBitmap(blank);
        top.setOnTouchListener(this);
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
                canvas.drawCircle(event.getX(), event.getY(), 20, paint);
                top.setImageBitmap(blank);//将改变之后的图片传入控件中
                break;
        }
        return true;
    }

四、实现图片倒影的效果

实现步骤:

             *得到倒影图像

Matrix m = new Matrix();
        m.setScale(1, -1);//将图片倒过来
        Bitmap reflectBitmap = Bitmap.createBitmap(srcBitmap, 0, height / 2, srcBitmap.getWidth(), height / 2, m, false);
           *创建空白画布画出源图和倒影图

Bitmap finalBitmap = Bitmap.createBitmap(width, height + height + gapHeight, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(finalBitmap);
        canvas.drawBitmap(srcBitmap, 0, 0, null);//添加原图
        canvas.drawRect(0, height, width, height + gapHeight, new Paint());//在图片和倒影之间添加一个空白的矩形
        canvas.drawBitmap(reflectBitmap, 0, height + gapHeight, null);//添加倒影
        *为倒影添加遮罩层渐变的效果

Paint paint = new Paint();
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));//DST_IN /** [Sa * Da, Sa * Dc] */ 可以看出显示的目标图受原图透明度的影响
        LinearGradient lg = new LinearGradient(0, height, 0, height + height / 2, Color.parseColor("#83FFFFFF"), Color.parseColor("#22FFFFFF"), Shader.TileMode.CLAMP);
        paint.setShader(lg);//为矩形设置渐变
        canvas.drawRect(0, height + gapHeight, width, height + gapHeight + height / 2, paint);
        * 将图片添加到ImageView中

BitmapDrawable bd = new BitmapDrawable(getResources(), finalBitmap);
        bd.setAntiAlias(true);
        RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) iv.getLayoutParams();
        params.width = 300;
        params.height = 400;
        iv.setLayoutParams(params);
        iv.setImageBitmap(bd.getBitmap());

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值