• (转载)Xfermodes的扩展应用 图像擦除和还原效果


    最近在学习Android图形API,看到sdk中demo里的Xfermodes实例,于是结合之前学的做了一个简单的图像擦除和还原的效果,感觉比较好玩,分享下作为TestRoid第一篇^^。

    Sdk中自带的例子如图所示,

    是几种不同的Xfermodes效果,这些效果很显而易见,无非是一个黄色圆(Dst)和蓝色矩形(Src)的显示。比如SrcOver就是蓝色矩形显示在黄色圆前面; SrcIn就是两个图形交集显示为Src也就是蓝色矩形的那部分。我主要是用里面的Xor效果来实现这里的例子,PorterDuff.Mode.XOR,即两块非透明区域重叠部分显示为透明。

    如果单是做图像擦除的效果也就用不到这个东西咯,所以嘛,重点是在还原的效果。因此这个例子的思路是,建立一块与原图大小相同的mask bitmap,然后在这块mask上进行操作,这样就不会影响原图,这里我用了触摸画线的例子在mask上画点东西,然后通过Xermodes中的XOR模式与原图进行合成,得到我们想要看到的效果。是不是有点Photoshop的味道啦,hoho。

    原理图在这,随手画的,呵呵

    废话不多说直接上效果图(OK,这个是用模拟器截得,有点卡=.=):

    下面是一些代码片段:

    初始化mask

    1. private void initBmpMask()  
    2. {  
    3.     if(mImgDesRect != null)  
    4.     {  
    5.         int w = (int) mImgDesRect.width();  
    6.         int h = (int) mImgDesRect.height();  
    7.         if(mEraseMaskBitmap == null)  
    8.         {  
    9.             mEraseMaskBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); //初始化一块和显示图片大小相同的bitmap  
    10.             mEraseMaskBitmap.eraseColor(Color.TRANSPARENT);//设置为透明  
    11.         }  
    12.     }  
    13.   
    14.     if(mEraseMaskBitmap != null)  
    15.         mCanvas = new Canvas(mEraseMaskBitmap);  //得到要操作的mask  
    16. }  

    初始化画笔样式等:

    1. private void initErasePaint(){  
    2.     mErasePaint = new Paint();  
    3.     mErasePaint.setAntiAlias(true);  
    4.     mErasePaint.setDither(true);  
    5.     mErasePaint.setColor(0xFF000000);  
    6.     mErasePaint.setStyle(Paint.Style.STROKE);  
    7.     mErasePaint.setStrokeJoin(Paint.Join.ROUND);  
    8.     mErasePaint.setStrokeCap(Paint.Cap.ROUND);  
    9.     mErasePaint.setStrokeWidth(20);  
    10. }  

    响应触屏消息在mask上画图:

    [c-sharp] view plaincopy
    1. public boolean onTouchEvent(MotionEvent event) {  
    2.     int action = event.getAction();  
    3.     float x = event.getX() - mImgDesRect.left;  
    4.     float y = event.getY() - mImgDesRect.top;  
    5.     switch (action) {  
    6.     case MotionEvent.ACTION_DOWN:  
    7.         mErasePath.reset();  
    8.         mErasePath.moveTo(x, y);  
    9.         mX = x;  
    10.         mY = y;  
    11.         invalidate();  
    12.         break;  
    13.     case MotionEvent.ACTION_MOVE:  
    14.          float dx = Math.abs(x - mX);  
    15.          float dy = Math.abs(y - mY);  
    16.          if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {  
    17.              mErasePath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);  
    18.              mX = x;  
    19.              mY = y;  
    20.              // commit the path to offscreen  
    21.              mCanvas.drawPath(mErasePath, mErasePaint);  
    22.          }  
    23.         invalidate(); //refresh  
    24.         break;  
    25.     case MotionEvent.ACTION_UP:  
    26.         mErasePath.lineTo(mX, mY);  
    27.         mCanvas.drawPath(mErasePath, mErasePaint);  
    28.         mErasePath.reset();  
    29.         invalidate();  
    30.         break;  
    31.     }  
    32.     return true;  
    33. }  

    切换擦除(erase)和还原(unerase)功能,只要改变Paint的Xfermode:

    1. public void switchEraseMode(boolean bErase){  
    2.     if(mErasePaint == null)  
    3.         initErasePaint();  
    4.       
    5.     if(bErase)  
    6.         mErasePaint.setXfermode(null);  
    7.     else  
    8.         mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));//清除样式  
    9. }  

    在OnDraw中,把原图和mask通过XOR样式画到canvas上,就可以看到擦除的效果啦:

    1. protected void onDraw(Canvas canvas) {  
    2.     super.onDraw(canvas);  
    3.   
    4.     if(mImgBitmap != null)  
    5.     {  
    6.         Paint paint = new Paint();  
    7.         int sc = canvas.saveLayer(mImgDesRect.left, mImgDesRect.top, mImgDesRect.right, mImgDesRect.bottom, null,     
    8.                 Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG     
    9.                         | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG     
    10.                         | Canvas.FULL_COLOR_LAYER_SAVE_FLAG     
    11.                         | Canvas.CLIP_TO_LAYER_SAVE_FLAG);     
    12.         paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR));  
    13.         canvas.drawBitmap(mImgBitmap, new Rect(0, 0, mImgBitmap.getWidth(), mImgBitmap.getHeight()), mImgDesRect, null);      
    14.         canvas.drawBitmap(mEraseMaskBitmap, new Rect(0, 0, mEraseMaskBitmap.getWidth(), mEraseMaskBitmap.getHeight()), mImgDesRect, paint);  
    15.         paint.setXfermode(null);  
    16.         canvas.restoreToCount(sc);    
    17.     }  
    18. }  

    好了,显示上擦除和“反擦”效果就完成了。

    例程上传了,可以这里下载:http://download.csdn.net/source/3240693

    里面顺便加上了把擦除效果保存下来的,/sdcard/out.png

    注:为了视觉效果,例子里加上了一张背景图,让擦除后透明效果明显点。不过保存时这背景图是不会和原图一起保存的。(太懒了。。。)

    例子是边学边做的,比较粗糙,欢迎交流,Thx~

  • 相关阅读:
    趁热打铁(如何改bug)
    element el-input的autofocus失效问题解决
    为什么要将图片转为base64格式
    学习jdk1.8的Lambda和Stream
    (隐式参数)java8的方法引用之重新认识java的this关键字
    记一次惊奇面试,希望能为广大求职中的javaer提供一点经验。
    单机版ZooKeeper的安装教程
    两个对象值转换的方法(BeanUtils.copyProperties与JSONObject.parseObject对比)
    SpringBoot监控管理之Admin监管使用
    安利一个十分实用的IDEA插件--RestfulToolkit
  • 原文地址:https://www.cnblogs.com/greywolf/p/2682717.html
Copyright © 2020-2023  润新知