Android中常用的位圖操作

一、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代碼如下:

[代碼]java代碼:

01 //View轉換爲Bitmap
02     public void getDrawingCache(final ImageView sourceImageView, final ImageView destImageView) {
03           
04         new Handler().postDelayed(new Runnable() {
05               
06             @Override
07             public void run() {
08                 // TODO Auto-generated method stub
09                 //開啓bitmap緩存
10                 sourceImageView.setDrawingCacheEnabled(true);
11                 //獲取bitmap緩存
12                 Bitmap mBitmap = sourceImageView.getDrawingCache();
13                 //顯示 bitmap
14                 destImageView.setImageBitmap(mBitmap);
15                   
16 //              Bitmap mBitmap = sourceImageView.getDrawingCache();
17 //              Drawable drawable = (Drawable) new BitmapDrawable(mBitmap);
18 //              destImageView.setImageDrawable(drawable);
19                   
20                 new Handler().postDelayed(new Runnable() {
21                       
22                     @Override
23                     public void run() {
24                         // TODO Auto-generated method stub
25                         //不再顯示bitmap緩存
26                         //destImageView.setImageBitmap(null);
27                         destImageView.setImageResource(R.drawable.pet);
28                           
29                         //使用這句話而不是用上一句話是錯誤的,空指針調用
30                         //destImageView.setBackgroundDrawable(null);
31                           
32                         //關閉bitmap緩存
33                         sourceImageView.setDrawingCacheEnabled(false);
34                         //釋放bitmap緩存資源
35                         sourceImageView.destroyDrawingCache();
36                     }
37                 }, DELAY_TIME);
38             }
39         }, DELAY_TIME);
40     }
41   
42         mImageView1.setImageResource(R.drawable.android);
43         mImageView2.setImageResource(R.drawable.pet);
44         getDrawingCache(mImageView1, mImageView2);

        運行效果如下:

 
圖7-3  Demo運行效果圖1

 
圖7-4  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代碼如下:

[代碼]java代碼:

01 //圖片圓角處理
02 public Bitmap getRoundedBitmap() {
03     Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.frame);
04     //創建新的位圖
05     Bitmap bgBitmap = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), Config.ARGB_8888);
06     //把創建的位圖作爲畫板
07     Canvas mCanvas = new Canvas(bgBitmap);
08       
09     Paint mPaint = new Paint();
10     Rect mRect = new Rect(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
11     RectF mRectF = new RectF(mRect);
12     //設置圓角半徑爲20
13     float roundPx = 15;
14     mPaint.setAntiAlias(true);
15     //先繪製圓角矩形
16     mCanvas.drawRoundRect(mRectF, roundPx, roundPx, mPaint);
17       
18     //設置圖像的疊加模式
19     mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
20     //繪製圖像
21     mCanvas.drawBitmap(mBitmap, mRect, mRect, mPaint);
22       
23     return bgBitmap;
24 }

        效果如下圖所示:

 
圖7-5  圖片圓角處理

三、圖片灰化處理

        在Android中可以通過ColorMatrix類實現圖像處理軟件中的濾鏡效果,通過ColorMatrix類可以對位圖中的每個像素進行變換處理,達到特殊的濾鏡效果,下面通過一個例子來介紹如何通過ColorMatrix對圖像進行灰化處理,Java代碼如下:

[代碼]java代碼:

01 //圖片灰化處理
02     public Bitmap getGrayBitmap() {
03         Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.android);
04         Bitmap mGrayBitmap = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), Config.ARGB_8888);
05         Canvas mCanvas = new Canvas(mGrayBitmap);
06         Paint mPaint = new Paint();
07           
08         //創建顏色變換矩陣
09         ColorMatrix mColorMatrix = new ColorMatrix();
10         //設置灰度影響範圍
11         mColorMatrix.setSaturation(0);
12         //創建顏色過濾矩陣
13         ColorMatrixColorFilter mColorFilter = new ColorMatrixColorFilter(mColorMatrix);
14         //設置畫筆的顏色過濾矩陣
15         mPaint.setColorFilter(mColorFilter);
16         //使用處理後的畫筆繪製圖像
17         mCanvas.drawBitmap(mBitmap, 0, 0, mPaint);
18           
19         return mGrayBitmap;     
20     }

        效果如下圖所示:

 
圖7-6  圖片灰化處理

四、提取圖像Alpha位圖

        Android中的ARGB_8888類型的位圖由Alpha(透明度)、Red(紅)、Green(綠)、Blue(藍)四部分組成,其中Alpha部分也就是常說的Alpha通道,它控制圖像的透明度。在Android中Bitmap類提供了extractAlpha()方法,可以把位圖中的Alpha部分提取出來作爲一個新的位圖,然後與填充顏色後的Paint結合重新繪製一個新圖像。下面通過一個例子來說明Bitmap類的extractAlpha()方法的使用,Java代碼如下:

[代碼]java代碼:

01 //提取圖像Alpha位圖
02 public Bitmap getAlphaBitmap() {
03     BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.enemy_infantry_ninja);
04     Bitmap mBitmap = mBitmapDrawable.getBitmap();
05       
06     //BitmapDrawable的getIntrinsicWidth()方法,Bitmap的getWidth()方法
07     //注意這兩個方法的區別
08     //Bitmap mAlphaBitmap = Bitmap.createBitmap(mBitmapDrawable.getIntrinsicWidth(), mBitmapDrawable.getIntrinsicHeight(), Config.ARGB_8888);
09     Bitmap mAlphaBitmap = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), Config.ARGB_8888);
10       
11     Canvas mCanvas = new Canvas(mAlphaBitmap);
12     Paint mPaint = new Paint();
13       
14     mPaint.setColor(Color.BLUE);
15     //從原位圖中提取只包含alpha的位圖
16     Bitmap alphaBitmap = mBitmap.extractAlpha();
17     //在畫布上(mAlphaBitmap)繪製alpha位圖
18     mCanvas.drawBitmap(alphaBitmap, 0, 0, mPaint);
19       
20     return mAlphaBitmap;
21 }

 
圖7-7  提取圖像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代碼如下:

[代碼]java代碼:

01 //getScaleBitmap
02     public Bitmap getScaleBitmap() {
03         BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.pet);
04         Bitmap mBitmap = mBitmapDrawable.getBitmap();
05         int width = mBitmap.getWidth();
06         int height = mBitmap.getHeight();
07           
08         Matrix matrix = new Matrix();
09         matrix.preScale(0.75f, 0.75f);
10         Bitmap mScaleBitmap = Bitmap.createBitmap(mBitmap, 0, 0, width, height, matrix, true);
11           
12         return mScaleBitmap;
13     }

        效果如下圖所示:

 
圖7-8  圖像縮放

2)圖片旋轉

        使用Matrix類preRotate或者postRotate可以對圖像進行旋轉操作,它只有一個參數表示旋轉的角度,下面使用preRotate對圖像順時針旋轉30度,Java代碼如下:

[代碼]java代碼:

01 //getRotatedBitmap
02     public Bitmap getRotatedBitmap() {
03         BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.pet);
04         Bitmap mBitmap = mBitmapDrawable.getBitmap();
05         int width = mBitmap.getWidth();
06         int height = mBitmap.getHeight();
07           
08         Matrix matrix = new Matrix();
09         matrix.preRotate(45);
10         Bitmap mRotateBitmap = Bitmap.createBitmap(mBitmap, 0, 0, width, height, matrix, true);
11           
12         return mRotateBitmap;
13     }

        效果如下圖所示:

 
圖7-9  圖片旋轉

3)圖像傾斜

        使用Matrix類preSkew或者postSkew可以對圖像進行傾斜操作,它的兩個參數分別爲x和y座標傾斜度,下面使用preSkew對圖像進行傾斜變換,Java代碼如下:

[代碼]java代碼:

01 //getScrewBitmap
02 public Bitmap getScrewBitmap() {
03     BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.pet);
04     Bitmap mBitmap = mBitmapDrawable.getBitmap();
05     int width = mBitmap.getWidth();
06     int height = mBitmap.getHeight();
07       
08     Matrix matrix = new Matrix();
09     matrix.preSkew(1.0f, 0.15f);
10     Bitmap mScrewBitmap = Bitmap.createBitmap(mBitmap, 0, 0, width, height, matrix, true);
11       
12     return mScrewBitmap;
13 }

        效果如下圖所示:

 
圖7-10  圖像傾斜

4)圖像倒影

        爲圖像添加倒影效果之後,圖像看起來會有立體感,更有真實感,在Android中使用Matrix類可以很容易實現圖像的倒影效果。主要是Matrix的preScale方法的使用,給它設置負數縮放比例,圖像就會進行反轉。然後通過設置Shader添加漸變效果。Java代碼如下:

[代碼]java代碼:

01 //getReflectedBitmap
02     private Bitmap getReflectedBitmap() {
03         BitmapDrawable mBitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.pet);
04         Bitmap mBitmap = mBitmapDrawable.getBitmap();
05         int width = mBitmap.getWidth();
06         int height = mBitmap.getHeight();
07           
08         Matrix matrix = new Matrix();
09         // 圖片縮放,x軸變爲原來的1倍,y軸爲-1倍,實現圖片的反轉
10         matrix.preScale(1, -1);
11           
12         //創建反轉後的圖片Bitmap對象,圖片高是原圖的一半。
13         //Bitmap mInverseBitmap = Bitmap.createBitmap(mBitmap, 0, height/2, width, height/2, matrix, false);
14         //創建標準的Bitmap對象,寬和原圖一致,高是原圖的1.5倍。
15         //注意兩種createBitmap的不同
16         //Bitmap mReflectedBitmap = Bitmap.createBitmap(width, height*3/2, Config.ARGB_8888);
17           
18         Bitmap mInverseBitmap = Bitmap.createBitmap(mBitmap, 0, 0, width, height, matrix, false);
19         Bitmap mReflectedBitmap = Bitmap.createBitmap(width, height*2, Config.ARGB_8888);
20           
21         // 把新建的位圖作爲畫板
22         Canvas mCanvas = new Canvas(mReflectedBitmap);
23         //繪製圖片
24         mCanvas.drawBitmap(mBitmap, 0, 0, null);
25         mCanvas.drawBitmap(mInverseBitmap, 0, height, null);
26           
27         //添加倒影的漸變效果
28         Paint mPaint = new Paint();
29         Shader mShader = new LinearGradient(0, height, 0, mReflectedBitmap.getHeight(), 0x70ffffff, 0x00ffffff, TileMode.MIRROR);
30         mPaint.setShader(mShader);
31         //設置疊加模式
32         mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
33         //繪製遮罩效果
34         mCanvas.drawRect(0, height, width, mReflectedBitmap.getHeight(), mPaint);
35           
36         return mReflectedBitmap;
37     }

        效果如下圖所示:

 
圖7-11  圖像倒影

5)圖像剪切

        如果只需要圖像的一部分,就必須對圖像進行剪切處理,在原圖像上選擇一個剪切區域,使用PorterDuffXfermode圖像疊加規則,就可以把指定的圖像區域剪切下來,下面通過三個步驟來說明如果對圖像進行剪切操作。 

        第一步,創建一個新位圖作爲畫板,然後把原圖像畫到新位圖上面,Java代碼如下:

[代碼]java代碼:

01 BitmapDrawable bd = (BitmapDrawable) getResources().getDrawable(
02         R.drawable.beauty);
03 Bitmap bitmap = bd.getBitmap();
04 int w = bitmap.getWidth();
05 int h = bitmap.getHeight();
06 Bitmap bm = Bitmap.createBitmap(w, h, Config.ARGB_8888);
07 Canvas canvas = new Canvas(bm);
08 Paint mPaint = new Paint();
09 mPaint.setAntiAlias(true);
10 mPaint.setStyle(Style.STROKE);
11 canvas.drawBitmap(bitmap, 0, 0, mPaint);

        效果如下圖所示:

 
圖7-12  第一步效果圖

        第二步,繪製一個剪切區域,比如要剪切人物的臉部區域,需要在指定的位置繪製一個圓角矩形區域,代碼中的座標是在調試中獲得,在其他分辨率下會有所不同,Java代碼如下:

[代碼]java代碼:

01 int deltX = 76;
02 int deltY = 98;
03 DashPathEffect dashStyle = new DashPathEffect(new float[] { 10, 55, 5 }, 2);//創建虛線邊框樣式
04 RectF faceRect = new RectF(0, 0, 88, 106);
05 float [] faceCornerii = new float[] {30,30,30,30,75,75,75,75};
06 Paint mPaint = new Paint();//創建畫筆
07 mPaint.setColor(0xFF6F8DD5);
08 mPaint.setStrokeWidth(6);
09 mPaint.setPathEffect(dashStyle);
10 Path clip = new Path();//創建路徑
11 clip.reset();
12 clip.addRoundRect(faceRect, faceCornerii, Direction.CW);//添加圓角矩形路徑
13 canvas.save();//保存畫布
14 canvas.translate(deltX, deltY);
15 canvas.clipPath(clip, Region.Op.DIFFERENCE);
16 canvas.drawColor(0xDF222222);
17 canvas.drawPath(clip, mPaint);//繪製路徑
18 canvas.restore();

        效果如下圖所示:

 
圖7-13  第二步效果

        第三步,從原圖像上獲取指定區域的圖像,並繪製到屏幕上,java代碼如下:

[代碼]java代碼:

1 Rect srcRect = new Rect(0, 0, 88, 106);
2 srcRect.offset(deltX, deltY);
3 PaintFlagsDrawFilter dfd = new PaintFlagsDrawFilter(Paint.ANTI_ALIAS_FLAG,
4 Paint.FILTER_BITMAP_FLAG);
5 canvas.setDrawFilter(dfd);
6 canvas.clipPath(clip);//使用路徑剪切畫布
7 canvas.drawBitmap(bitmap, srcRect, faceRect, mPaint);

        效果如下圖所示:

 
圖7-13  第三部效果圖

6)圖像合成

        如果要爲圖片添加水印,或者把幾張小圖片拼接成大圖片時,就需要利用圖像合成的方法,在前面實例代碼中已經使用了這種方法,就是創建新位圖作爲畫板,然後在對應的位置上繪製其他圖像。
        讀者可以參考本章Demo中的getCompoundedBitmap方法,這裏不做過多說明。

Demo源代碼下載:Bitmap_test.rar
發佈了24 篇原創文章 · 獲贊 6 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章