一、View轉換為Bitmap
在Android中所有的控件都是View的直接子類或者間接子類,通過它們可以組成豐富的UI界面。在窗口顯示的時候Android會把這些控件都加載到內存中,形成一個以ViewRoot為根節點的控件樹,然后由根節點開始逐級把控件繪制到屏幕上。
可以通過調用控件的setDrawingCacheEnabled(true)方法,開啟繪圖緩存功能,在繪制View的時候把圖像緩存起來,然后通過getDrawingCache()方法獲取這個緩存的Bitmap。需要注意的是,當不再使用這個Bitmap時,需要調用destroyDrawingCache()方法,釋放Bitmap資源。由於在繪制View到屏幕時緩存圖像會降低控件繪制的效率,因此只會在需要使用View的圖像緩存的時候才調用setDrawingCacheEnabled(true)方法開啟圖像緩存功能,當不再使用圖像緩存時需要調用setDrawingCacheEnabled(false) 關閉圖像緩存功能。
這種方法在支持拖拽類型的應用中經常見到,在Android系統的Launcher應用中也使用了這種方法,當用戶拖拽應用的快捷圖標時,獲取到控件對應的Bitmap,然后操作這個Bitmap隨着手指移動。
下面通過一段代碼來說明如何獲取View對應的Bitmap。在代碼中使用了兩個ImageView並給它們都設置了顯示的圖片資源,然后把第一個ImageView對應的bitmap顯示到第二個ImageView中。由於在Activity的onCreate方法中調用這個方法,當執行Activity的onCreate方法時,控件還沒有准備好,所以需要使用Handler進行延遲操作,Java代碼如下:
- //View轉換為Bitmap
- public void getDrawingCache(final ImageView sourceImageView, final ImageView destImageView) {
- new Handler().postDelayed(new Runnable() {
- @Override
- public void run() {
- // TODO Auto-generated method stub
- //開啟bitmap緩存
- sourceImageView.setDrawingCacheEnabled(true);
- //獲取bitmap緩存
- Bitmap mBitmap = sourceImageView.getDrawingCache();
- //顯示 bitmap
- destImageView.setImageBitmap(mBitmap);
- // Bitmap mBitmap = sourceImageView.getDrawingCache();
- // Drawable drawable = (Drawable) new BitmapDrawable(mBitmap);
- // destImageView.setImageDrawable(drawable);
- new Handler().postDelayed(new Runnable() {
- @Override
- public void run() {
- // TODO Auto-generated method stub
- //不再顯示bitmap緩存
- //destImageView.setImageBitmap(null);
- destImageView.setImageResource(R.drawable.pet);
- //使用這句話而不是用上一句話是錯誤的,空指針調用
- //destImageView.setBackgroundDrawable(null);
- //關閉bitmap緩存
- sourceImageView.setDrawingCacheEnabled(false);
- //釋放bitmap緩存資源
- sourceImageView.destroyDrawingCache();
- }
- }, DELAY_TIME);
- }
- }, DELAY_TIME);
- }
- mImageView1.setImageResource(R.drawable.android);
- mImageView2.setImageResource(R.drawable.pet);
- getDrawingCache(mImageView1, mImageView2);
運行效果如下:

Demo運行效果圖1
Demo運行效果圖2
二、圖片圓角處理在Android中可以很容通過圖像疊加的規則為圖片添加圓角效果。正常情況下,在已有的圖像上繪圖時將會在其上面添加一層新的圖形。如果繪圖時使用的Paint是完全不透明的,那么它將完全遮擋住下面的圖像,如果Paint是部分透明的,那么它將會對重疊部分圖像的顏色疊加處理。通過PorterDuffXfermode規則可以設置繪制圖像時的疊加規則。PorterDuffXfermode是非常強大的轉換模式,使用它可以設置圖像疊加的Porter-Duff規則,來控制Paint如何與Canvas上已有的圖像進行疊加。下面列舉了常用的12條Porter-Duff規則及其表示的含義:
PorterDuff.Mode.CLEAR 清除畫布上圖像
PorterDuff.Mode.SRC 顯示上層圖像
PorterDuff.Mode.DST 顯示下層圖像
PorterDuff.Mode.SRC_OVER上下層圖像都顯示,下層居上顯示
PorterDuff.Mode.DST_OVER 上下層都顯示,下層居上顯示
PorterDuff.Mode.SRC_IN 取兩層圖像交集部分,只顯示上層圖像
PorterDuff.Mode.DST_IN 取兩層圖像交集部分,只顯示下層圖像
PorterDuff.Mode.SRC_OUT 取上層圖像非交集部分
PorterDuff.Mode.DST_OUT 取下層圖像非交集部分
PorterDuff.Mode.SRC_ATOP 取下層圖像非交集部分與上層圖像交集部分
PorterDuff.Mode.DST_ATOP 取上層圖像非交集部分與下層圖像交集部分
PorterDuff.Mode.XOR 取兩層圖像的非交集部分
下面使用PorterDuff.Mode.SRC_IN規則來給圖片添加圓角效果,主要的思路是先繪制一個圓角矩形,然后在上面繪制圖像,取圖像與圓角矩形的交集部分,只保留圖像。Java代碼如下:
- //圖片圓角處理
- public Bitmap getRoundedBitmap() {
- Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.frame);
- //創建新的位圖
- Bitmap bgBitmap = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), Config.ARGB_8888);
- //把創建的位圖作為畫板
- Canvas mCanvas = new Canvas(bgBitmap);
- Paint mPaint = new Paint();
- Rect mRect = new Rect(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
- RectF mRectF = new RectF(mRect);
- //設置圓角半徑為20
- float roundPx = 15;
- mPaint.setAntiAlias(true);
- //先繪制圓角矩形
- mCanvas.drawRoundRect(mRectF, roundPx, roundPx, mPaint);
- //設置圖像的疊加模式
- mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
- //繪制圖像
- mCanvas.drawBitmap(mBitmap, mRect, mRect, mPaint);
- return bgBitmap;
- }
效果如下圖所示:

圖片圓角處理
三、圖片灰化處理
在Android中可以通過ColorMatrix類實現圖像處理軟件中的濾鏡效果,通過ColorMatrix類可以對位圖中的每個像素進行變換處理,達到特殊的濾鏡效果,下面通過一個例子來介紹如何通過ColorMatrix對圖像進行灰化處理,Java代碼如下:
- //圖片灰化處理
- public Bitmap getGrayBitmap() {
- Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.android);
- Bitmap mGrayBitmap = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), Config.ARGB_8888);
- Canvas mCanvas = new Canvas(mGrayBitmap);
- Paint mPaint = new Paint();
- //創建顏色變換矩陣
- ColorMatrix mColorMatrix = new ColorMatrix();
- //設置灰度影響范圍
- mColorMatrix.setSaturation(0);
- //創建顏色過濾矩陣
- ColorMatrixColorFilter mColorFilter = new ColorMatrixColorFilter(mColorMatrix);
- //設置畫筆的顏色過濾矩陣
- mPaint.setColorFilter(mColorFilter);
- //使用處理后的畫筆繪制圖像
- mCanvas.drawBitmap(mBitmap, 0, 0, mPaint);
- return mGrayBitmap;
- }
效果如下圖所示:
圖片灰化處理
四、提取圖像Alpha位圖
Android中的ARGB_8888類型的位圖由Alpha(透明度)、Red(紅)、Green(綠)、Blue(藍)四部分組成,其中Alpha部分也就是常說的Alpha通道,它控制圖像的透明度。在Android中Bitmap類提供了extractAlpha()方法,可以把位圖中的Alpha部分提取出來作為一個新的位圖,然后與填充顏色后的Paint結合重新繪制一個新圖像。下面通過一個例子來說明Bitmap類的extractAlpha()方法的使用,Java代碼如下:
- //提取圖像Alpha位圖
- public Bitmap getAlphaBitmap() {
- BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.enemy_infantry_ninja);
- Bitmap mBitmap = mBitmapDrawable.getBitmap();
- //BitmapDrawable的getIntrinsicWidth()方法,Bitmap的getWidth()方法
- //注意這兩個方法的區別
- //Bitmap mAlphaBitmap = Bitmap.createBitmap(mBitmapDrawable.getIntrinsicWidth(), mBitmapDrawable.getIntrinsicHeight(), Config.ARGB_8888);
- Bitmap mAlphaBitmap = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), Config.ARGB_8888);
- Canvas mCanvas = new Canvas(mAlphaBitmap);
- Paint mPaint = new Paint();
- mPaint.setColor(Color.BLUE);
- //從原位圖中提取只包含alpha的位圖
- Bitmap alphaBitmap = mBitmap.extractAlpha();
- //在畫布上(mAlphaBitmap)繪制alpha位圖
- mCanvas.drawBitmap(alphaBitmap, 0, 0, mPaint);
- return mAlphaBitmap;
- }
提取圖像Alpha位圖
其中最后一幅圖片是把原圖片四個邊距縮小兩個dp,然后與Alpha位圖一起繪制的結果,讀者可以參考本章Demo中的getStrokeBitmap()方法。五、圖像變換
Android開發框架提供了一個坐標變換矩陣Matrix類,它可以與Bitmap類的createBitmap方法結合使用,對圖像進行縮放、旋轉、扭曲等變換處理。圖像變換操作就是對坐標變換矩陣進行矩陣乘法運算,Matrix類中提供了一些簡便的方法如preScale、postScale、preRotate、postRotate、preSkrew、postSkrew、preTranslate、postTranslate等封裝了矩陣的運算,它們與Bitmap類的createBitmap方法結合使用可以很容易地對圖像進行縮放、旋轉、扭曲、平移操作。
1)圖像縮放
使用Matrix類preScale或者postScale可以對圖像進行縮放操作,它的兩個參數分別為x和y坐標縮放比例,下面使用preScale對圖像進行放大0.75倍,Java代碼如下:
//getScaleBitmap public Bitmap getScaleBitmap() { BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.pet); Bitmap mBitmap = mBitmapDrawable.getBitmap(); int width = mBitmap.getWidth(); int height = mBitmap.getHeight(); Matrix matrix = new Matrix(); matrix.preScale(0.75f, 0.75f); Bitmap mScaleBitmap = Bitmap.createBitmap(mBitmap, 0, 0, width, height, matrix, true); return mScaleBitmap; }
效果如下圖所示:
圖像縮放
2)圖片旋轉使用Matrix類preRotate或者postRotate可以對圖像進行旋轉操作,它只有一個參數表示旋轉的角度,下面使用preRotate對圖像順時針旋轉30度,Java代碼如下:
- //getRotatedBitmap
- public Bitmap getRotatedBitmap() {
- BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.pet);
- Bitmap mBitmap = mBitmapDrawable.getBitmap();
- int width = mBitmap.getWidth();
- int height = mBitmap.getHeight();
- Matrix matrix = new Matrix();
- matrix.preRotate(45);
- Bitmap mRotateBitmap = Bitmap.createBitmap(mBitmap, 0, 0, width, height, matrix, true);
- return mRotateBitmap;
- }
效果如下圖所示:
圖片旋轉
3)圖像傾斜
使用Matrix類preSkew或者postSkew可以對圖像進行傾斜操作,它的兩個參數分別為x和y坐標傾斜度,下面使用preSkew對圖像進行傾斜變換,Java代碼如下:
- //getScrewBitmap
- public Bitmap getScrewBitmap() {
- BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.pet);
- Bitmap mBitmap = mBitmapDrawable.getBitmap();
- int width = mBitmap.getWidth();
- int height = mBitmap.getHeight();
- Matrix matrix = new Matrix();
- matrix.preSkew(1.0f, 0.15f);
- Bitmap mScrewBitmap = Bitmap.createBitmap(mBitmap, 0, 0, width, height, matrix, true);
- return mScrewBitmap;
- }
圖像傾斜
4)圖像倒影
為圖像添加倒影效果之后,圖像看起來會有立體感,更有真實感,在Android中使用Matrix類可以很容易實現圖像的倒影效果。主要是Matrix的preScale方法的使用,給它設置負數縮放比例,圖像就會進行反轉。然后通過設置Shader添加漸變效果。Java代碼如下:
- //getReflectedBitmap
- private Bitmap getReflectedBitmap() {
- BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.pet);
- Bitmap mBitmap = mBitmapDrawable.getBitmap();
- int width = mBitmap.getWidth();
- int height = mBitmap.getHeight();
- Matrix matrix = new Matrix();
- // 圖片縮放,x軸變為原來的1倍,y軸為-1倍,實現圖片的反轉
- matrix.preScale(1, -1);
- //創建反轉后的圖片Bitmap對象,圖片高是原圖的一半。
- //Bitmap mInverseBitmap = Bitmap.createBitmap(mBitmap, 0, height/2, width, height/2, matrix, false);
- //創建標准的Bitmap對象,寬和原圖一致,高是原圖的1.5倍。
- //注意兩種createBitmap的不同
- //Bitmap mReflectedBitmap = Bitmap.createBitmap(width, height*3/2, Config.ARGB_8888);
- Bitmap mInverseBitmap = Bitmap.createBitmap(mBitmap, 0, 0, width, height, matrix, false);
- Bitmap mReflectedBitmap = Bitmap.createBitmap(width, height*2, Config.ARGB_8888);
- // 把新建的位圖作為畫板
- Canvas mCanvas = new Canvas(mReflectedBitmap);
- //繪制圖片
- mCanvas.drawBitmap(mBitmap, 0, 0, null);
- mCanvas.drawBitmap(mInverseBitmap, 0, height, null);
- //添加倒影的漸變效果
- Paint mPaint = new Paint();
- Shader mShader = new LinearGradient(0, height, 0, mReflectedBitmap.getHeight(), 0x70ffffff, 0x00ffffff, TileMode.MIRROR);
- mPaint.setShader(mShader);
- //設置疊加模式
- mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
- //繪制遮罩效果
- mCanvas.drawRect(0, height, width, mReflectedBitmap.getHeight(), mPaint);
- return mReflectedBitmap;
- }
效果如下圖所示:
圖像倒影
如果只需要圖像的一部分,就必須對圖像進行剪切處理,在原圖像上選擇一個剪切區域,使用PorterDuffXfermode圖像疊加規則,就可以把指定的圖像區域剪切下來,下面通過三個步驟來說明如果對圖像進行剪切操作。
第一步,創建一個新位圖作為畫板,然后把原圖像畫到新位圖上面,Java代碼如下:
- BitmapDrawable bd = (BitmapDrawable) getResources().getDrawable(
- R.drawable.beauty);
- Bitmap bitmap = bd.getBitmap();
- int w = bitmap.getWidth();
- int h = bitmap.getHeight();
- Bitmap bm = Bitmap.createBitmap(w, h, Config.ARGB_8888);
- Canvas canvas = new Canvas(bm);
- Paint mPaint = new Paint();
- mPaint.setAntiAlias(true);
- mPaint.setStyle(Style.STROKE);
- canvas.drawBitmap(bitmap, 0, 0, mPaint);
效果如下圖所示:
第一步效果圖
第二步,繪制一個剪切區域,比如要剪切人物的臉部區域,需要在指定的位置繪制一個圓角矩形區域,代碼中的坐標是在調試中獲得,在其他分辨率下會有所不同,Java代碼如下:
- int deltX = 76;
- int deltY = 98;
- DashPathEffect dashStyle = new DashPathEffect(new float[] { 10, 5, 5, 5 }, 2);//創建虛線邊框樣式
- RectF faceRect = new RectF(0, 0, 88, 106);
- float [] faceCornerii = new float[] {30,30,30,30,75,75,75,75};
- Paint mPaint = new Paint();//創建畫筆
- mPaint.setColor(0xFF6F8DD5);
- mPaint.setStrokeWidth(6);
- mPaint.setPathEffect(dashStyle);
- Path clip = new Path();//創建路徑
- clip.reset();
- clip.addRoundRect(faceRect, faceCornerii, Direction.CW);//添加圓角矩形路徑
- canvas.save();//保存畫布
- canvas.translate(deltX, deltY);
- canvas.clipPath(clip, Region.Op.DIFFERENCE);
- canvas.drawColor(0xDF222222);
- canvas.drawPath(clip, mPaint);//繪制路徑
- canvas.restore();
效果如下圖所示:
第二步效果
第三步,從原圖像上獲取指定區域的圖像,並繪制到屏幕上,java代碼如下:
- Rect srcRect = new Rect(0, 0, 88, 106);
- srcRect.offset(deltX, deltY);
- PaintFlagsDrawFilter dfd = new PaintFlagsDrawFilter(Paint.ANTI_ALIAS_FLAG,
- Paint.FILTER_BITMAP_FLAG);
- canvas.setDrawFilter(dfd);
- canvas.clipPath(clip);//使用路徑剪切畫布
- canvas.drawBitmap(bitmap, srcRect, faceRect, mPaint);
效果如下圖所示:

第三部效果圖
6)圖像合成
如果要為圖片添加水印,或者把幾張小圖片拼接成大圖片時,就需要利用圖像合成的方法,在前面實例代碼中已經使用了這種方法,就是創建新位圖作為畫板,然后在對應的位置上繪制其他圖像