轉(zhuǎn):關(guān)于android中圖片裁剪以及PorterDuffXfermode的使用經(jīng)驗(yàn)小結(jié)
原文:關(guān)于android中圖片裁剪以及PorterDuffXfermode的使用經(jīng)驗(yàn)小結(jié)
1.關(guān)于圖片”裁剪”出現(xiàn)鋸齒的問題
使用canvas
的clipXxx
函數(shù),可以獲取只顯露出某一區(qū)域的圖形,但是有鋸齒,即使paint
使用了setAntiAlias(true)
函數(shù)依然無法消除鋸齒問題。
解決方案:
使用shader
方案,即:
paint.setShader(mBitmapShader);
canvas.drawCircle(mCenterX, mCenterY, mRadius, paint);
其中mBitmapShader的聲明與實(shí)現(xiàn)是:
BitmapShader mBitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
//如果要實(shí)現(xiàn)位置變換等,可以添加如下代碼:
mBitmapShader.setLocalMatrix(matrix);
具體的實(shí)現(xiàn),可見AvatarImageView項(xiàng)目中,多字裁剪的實(shí)現(xiàn)方式。
2.PorterDuffXfermode實(shí)現(xiàn)方式
PorterDuffXfermode
主要用于獲取兩張圖片取“并集/交集”等的效果。這里的取“交集/并集”是根據(jù)圖片A和圖片B的某個(gè)像素點(diǎn)的顏色值來確定的。
假設(shè)代碼的實(shí)現(xiàn)為如下方式:
- 首先,畫出A-des。這里的A-des不一定必須是
bitmap
,可以是path
等。 - 其次,設(shè)置
paint
的Xfermode
為
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
- 最后,畫出B-src。與第一步中的A-des相似,這里的B-src不一定必須是
bitmap
,可以是path
等。
根據(jù)上面的三個(gè)步驟,分析繪出的圖的某一個(gè)像素點(diǎn)的顏色值情況:
- 如果在
(x,y)
像素點(diǎn)處,A的顏色值為透明或者沒有設(shè)定,而B的不為0,那么此點(diǎn)的顏色值為0x00000000
。因?yàn)锳為0了,而SRC_IN
的效果就是最后要顯示的圖片取交集,并且后畫的顯示在交集上,而交集為0(底部顏色為0,可以認(rèn)為最后顏色的透明度為兩者相乘),所以就將B圖變成透明的了。如果A的透明度為0.5,那么SRC_IN
后的圖片的相當(dāng)于B*0.5透明度。 - 最后生成的圖像,是對(duì)兩個(gè)圖像的每一個(gè)像素點(diǎn)分別計(jì)算交集獲取的結(jié)果,與圖像的“區(qū)域”無關(guān)。
舉例說明:
仿微信聊天中帶有三角凸起的圖片的代碼片段:
public static Bitmap canvasTriangle(Bitmap bitmapimg, int direct) {
Bitmap output = Bitmap.createBitmap(bitmapimg.getWidth(),
bitmapimg.getHeight(), Bitmap.Config.ARGB_4444);
Canvas canvas = new Canvas(output);
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmapimg.getWidth(),
bitmapimg.getHeight());
// paint.setStrokeWidth(30);
// paint.setStyle(Paint.Style.STROKE);
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(0x66000000);
//可以使用canvas.drawRect() + canvas.drawPath()等方式多個(gè)區(qū)域合并后進(jìn)行繪制
//path只是用來繪制像素的透明度的。如果paint的透明度為0,那么相當(dāng)于沒有畫任何東西,如果paint的透明度為0.3,那么最后的圖片的透明度為0.3
Path path = new Path();
path.moveTo(0, 0);
path.lineTo(bitmapimg.getWidth() - 15, 0);
path.lineTo(bitmapimg.getWidth() - 15, 10);
path.lineTo(bitmapimg.getWidth(), 20);
path.lineTo(bitmapimg.getWidth() - 15, 30);
path.lineTo(bitmapimg.getWidth() - 15, bitmapimg.getHeight());
path.lineTo(0, bitmapimg.getHeight());
path.close();
canvas.drawPath(path, paint);//(DES)
//兩層繪制交集。顯示上層
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmapimg, rect, rect, paint);//(SRC)
return output;
}