Xfermodes的擴充套件應用- 影象擦除和還原效果
阿新 • • 發佈:2019-02-09
最近在學習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
-
view plaincopy to clipboardprint?
-
private void initBmpMask()
-
{
-
if(mImgDesRect
!= null)
-
{
-
int w = (int)
mImgDesRect.width();
-
int h = (int)
mImgDesRect.height();
-
if(mEraseMaskBitmap
== null)
-
{
-
mEraseMaskBitmap
= Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); //初始化一塊和顯示圖片大小相同的bitmap
-
mEraseMaskBitmap.eraseColor(Color.TRANSPARENT);//設定為透明
-
}
-
}
-
if(mEraseMaskBitmap
!= null)
-
mCanvas =
new Canvas(mEraseMaskBitmap); //得到要操作的mask
- }
初始
-
化畫筆樣式等:
-
view plaincopy to clipboardprint?
-
private void initErasePaint(){
-
mErasePaint = new Paint();
-
mErasePaint.setAntiAlias(true);
-
mErasePaint.setDither(true);
-
mErasePaint.setColor(0xFF000000);
-
mErasePaint.setStyle(Paint.Style.STROKE);
-
mErasePaint.setStrokeJoin(Paint.Join.ROUND);
-
mErasePaint.setStrokeCap(Paint.Cap.ROUND);
-
mErasePaint.setStrokeWidth(20);
- }
響應觸屏訊息在mask上畫圖:
-
view plaincopy to clipboardprint?
-
public boolean onTouchEvent(MotionEvent event) {
-
int action = event.getAction();
-
float x = event.getX() - mImgDesRect.left;
-
float y = event.getY() - mImgDesRect.top;
-
switch (action) {
-
case MotionEvent.ACTION_DOWN:
-
mErasePath.reset();
-
mErasePath.moveTo(x, y);
-
mX = x;
-
mY = y;
-
invalidate();
-
break;
-
case MotionEvent.ACTION_MOVE:
-
float dx = Math.abs(x - mX);
-
float dy = Math.abs(y - mY);
-
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
-
mErasePath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
-
mX = x;
-
mY = y;
-
// commit the path to offscreen
-
mCanvas.drawPath(mErasePath, mErasePaint);
-
}
-
invalidate(); //refresh
-
break;
-
case MotionEvent.ACTION_UP:
-
mErasePath.lineTo(mX, mY);
-
mCanvas.drawPath(mErasePath, mErasePaint);
-
mErasePath.reset();
-
invalidate();
-
break;
-
}
-
return true;
- }
-
view plaincopy to clipboardprint?
-
public void switchEraseMode(boolean bErase){
-
if(mErasePaint == null)
-
initErasePaint();
-
if(bErase)
-
mErasePaint.setXfermode(null);
-
else
-
mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));//清除樣式
- }
在OnDraw中,把原圖和mask通過XOR樣式畫到canvas上,就可以看到擦除的效果啦:
-
view plaincopy to clipboardprint?
-
protected void onDraw(Canvas canvas) {
-
super.onDraw(canvas);
-
if(mImgBitmap != null)
-
{
-
Paint paint = new Paint();
-
int sc = canvas.saveLayer(mImgDesRect.left, mImgDesRect.top, mImgDesRect.right, mImgDesRect.bottom, 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);
-
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR));
-
canvas.drawBitmap(mImgBitmap, new Rect(0, 0, mImgBitmap.getWidth(), mImgBitmap.getHeight()), mImgDesRect, null);
-
canvas.drawBitmap(mEraseMaskBitmap, new Rect(0, 0, mEraseMaskBitmap.getWidth(), mEraseMaskBitmap.getHeight()), mImgDesRect, paint);
-
paint.setXfermode(null);
-
canvas.restoreToCount(sc);
-
}
- }
好了,顯示上擦除和“反擦”效果就完成了。
例程上傳了,可以這裡下載:http://download.csdn.net/source/3240693
裡面順便加上了把擦除效果儲存下來的,/sdcard/out.png
注:為了視覺效果,例子里加上了一張背景圖,讓擦除後透明效果明顯點。不過儲存時這背景圖是不會和原圖一起儲存的。(太懶了。。。)