1. 程式人生 > >Xfermodes的擴充套件應用- 影象擦除和還原效果

Xfermodes的擴充套件應用- 影象擦除和還原效果

最近在學習Android圖形API,看到sdkdemo裡的Xfermodes例項,於是結合之前學的做了一個簡單的影象擦除和還原的效果,感覺比較好玩,分享下作為TestRoid第一篇^^。
Sdk中自帶的例子如圖所示,
 
是幾種不同的Xfermodes效果,這些效果很顯而易見,無非是一個黃色圓(Dst)和藍色矩形(Src)的顯示。比如SrcOver就是藍色矩形顯示在黃色圓前面;
SrcIn就是兩個圖形交集顯示為Src也就是藍色矩形的那部分。我主要是用裡面的Xor效果來實現這裡的例子,PorterDuff.Mode.XOR,即兩塊非透明區域重疊部分顯示為透明。

如果單是做影象擦除的效果也就用不到這個東西咯,所以嘛,重點是在還原的效果。因此這個例子的思路是,建立一塊與原圖大小相同的

mask bitmap,然後在這塊mask上進行操作,這樣就不會影響原圖,這裡我用了觸控畫線的例子在mask上畫點東西,然後通過Xermodes中的XOR模式與原圖進行合成,得到我們想要看到的效果。是不是有點Photoshop的味道啦,hoho
原理圖在這,隨手畫的,呵呵
 
廢話不多說直接上效果圖(OK,這個是用模擬器截得,有點卡=.=):
 


下面是一些程式碼片段:


初始化mask

  1. view plaincopy to clipboardprint?
  2.     private void initBmpMask()  
  3.     {  
  4.         if(mImgDesRect != null)  
  5.         {  
  6.             int w = (int) mImgDesRect.width();  
  7.             int h = (int) mImgDesRect.height();  
  8.             if(mEraseMaskBitmap == null)  
  9.             {  
  10.                 mEraseMaskBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); //初始化一塊和顯示圖片大小相同的bitmap  
  11.                 mEraseMaskBitmap.eraseColor(Color.TRANSPARENT);//設定為透明  
  12.             }  
  13.         }  
  14.         if(mEraseMaskBitmap != null)  
  15.             mCanvas = new Canvas(mEraseMaskBitmap);  //得到要操作的mask  
  16.     }  
複製程式碼


初始
  1. 化畫筆樣式等:
  2. view plaincopy to clipboardprint?
  3.     private void initErasePaint(){  
  4.         mErasePaint = new Paint();  
  5.         mErasePaint.setAntiAlias(true);  
  6.         mErasePaint.setDither(true);  
  7.         mErasePaint.setColor(0xFF000000);  
  8.         mErasePaint.setStyle(Paint.Style.STROKE);  
  9.         mErasePaint.setStrokeJoin(Paint.Join.ROUND);  
  10.         mErasePaint.setStrokeCap(Paint.Cap.ROUND);  
  11.         mErasePaint.setStrokeWidth(20);  
  12.     }  
複製程式碼

響應觸屏訊息在mask上畫圖:
  1. view plaincopy to clipboardprint?
  2.     public boolean onTouchEvent(MotionEvent event) {  
  3.         int action = event.getAction();  
  4.         float x = event.getX() - mImgDesRect.left;  
  5.         float y = event.getY() - mImgDesRect.top;  
  6.         switch (action) {  
  7.         case MotionEvent.ACTION_DOWN:  
  8.             mErasePath.reset();  
  9.             mErasePath.moveTo(x, y);  
  10.             mX = x;  
  11.             mY = y;  
  12.             invalidate();  
  13.             break;  
  14.         case MotionEvent.ACTION_MOVE:  
  15.              float dx = Math.abs(x - mX);  
  16.              float dy = Math.abs(y - mY);  
  17.              if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {  
  18.                  mErasePath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);  
  19.                  mX = x;  
  20.                  mY = y;  
  21.                  // commit the path to offscreen  
  22.                  mCanvas.drawPath(mErasePath, mErasePaint);  
  23.              }  
  24.             invalidate(); //refresh  
  25.             break;  
  26.         case MotionEvent.ACTION_UP:  
  27.             mErasePath.lineTo(mX, mY);  
  28.             mCanvas.drawPath(mErasePath, mErasePaint);  
  29.             mErasePath.reset();  
  30.             invalidate();  
  31.             break;  
  32.         }  
  33.         return true;  
  34.     }
複製程式碼 切換擦除(erase)和還原(unerase)功能,只要改變PaintXfermode
  1. view plaincopy to clipboardprint?
  2.     public void switchEraseMode(boolean bErase){  
  3.         if(mErasePaint == null)  
  4.             initErasePaint();  
  5.         if(bErase)  
  6.             mErasePaint.setXfermode(null);  
  7.         else  
  8.             mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));//清除樣式  
  9.     }  
複製程式碼

在OnDraw中,把原圖和mask通過XOR樣式畫到canvas上,就可以看到擦除的效果啦:
  1. view plaincopy to clipboardprint?
  2.     protected void onDraw(Canvas canvas) {  
  3.         super.onDraw(canvas);  
  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
注:為了視覺效果,例子里加上了一張背景圖,讓擦除後透明效果明顯點。不過儲存時這背景圖是不會和原圖一起儲存的。(太懶了。。。)