Android中Bitmap,byte[],Drawable相互轉化

一、Drawable就是一個可畫的對象,其多是一張位圖(BitmapDrawable),也多是一個圖形(ShapeDrawable),還有多是一個圖層(LayerDrawable),咱們根據畫圖的需求,建立相應的可畫對象
二、Canvas畫布,繪圖的目的區域,用於繪圖
三、Bitmap位圖,用於圖的處理
四、Matrix矩陣

不少Android開發者可能發現,將Bitmap轉爲字節數組可能文件大小和原始圖片差別很大,代碼以下php

1. 字節數組data保存Bitmap對象轉爲字節數組,處理代碼:android

BitmapFactory.decodeByteArray(data, 0, data.length);canvas

2. 而第二種方法處理代碼:數組

ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
data2 = baos.toByteArray();post

這裏其實很好理解,第二種方法使用了Bitmap的compress方法,通常用於保存一個Bitmap對象,轉爲字節輸出流,可是compress目前編碼由兩種,好比JPG,通常處理照片和PNG,PNG通常處理帶Alpha透明通道的圖片,後面的第二個參數是清晰度,通常100是最高,0是最低,這個值越大圖片越清晰,同時文件體積越大,JPG和PNG都是壓縮的圖片,因此和原始的直接經過BitmapFactory.decodeByteArray解碼後的大小會有很大的不一樣。測試

2、Bitmap

一、從資源中獲取Bitmap

1 Resources res = getResources(); 2 Bitmap bmp = BitmapFactory.decodeResource(res, R.drawable.icon);


二、Bitmap → byte[]

1publicbyte[] Bitmap2Bytes(Bitmap bm) { 2 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 3 bm.compress(Bitmap.CompressFormat.PNG, 100, baos); 4return baos.toByteArray(); 5 }


三、byte[] → Bitmap

1public Bitmap Bytes2Bimap(byte[] b) { 2if (b.length != 0) { 3return BitmapFactory.decodeByteArray(b, 0, b.length); 4 } else { 5returnnull; 6 } 7 }

四、Bitmap縮放

 1publicstatic Bitmap zoomBitmap(Bitmap bitmap, int width, int height) { 2int w = bitmap.getWidth(); 3int h = bitmap.getHeight(); 4 Matrix matrix = new Matrix(); 5float scaleWidth = ((float) width / w); 6float scaleHeight = ((float) height / h); 7 matrix.postScale(scaleWidth, scaleHeight); 8 Bitmap newbmp = Bitmap.createBitmap(bitmap, 0, 0, w, h, matrix, true); 9return newbmp; 10 }

五、將Drawable轉化爲Bitmap

 1publicstatic Bitmap drawableToBitmap(Drawable drawable) { 2// 取 drawable 的長寬 3int w = drawable.getIntrinsicWidth(); 4int h = drawable.getIntrinsicHeight(); 5 6// 取 drawable 的顏色格式 7 Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 8 : Bitmap.Config.RGB_565; 9// 創建對應 bitmap 10 Bitmap bitmap = Bitmap.createBitmap(w, h, config); 11// 創建對應 bitmap 的畫布 12 Canvas canvas = new Canvas(bitmap); 13 drawable.setBounds(0, 0, w, h); 14// 把 drawable 內容畫到畫布中 15 drawable.draw(canvas); 16return bitmap; 17 }

六、得到圓角圖片

 1publicstatic Bitmap getRoundedCornerBitmap(Bitmap bitmap, float roundPx) { 2int w = bitmap.getWidth(); 3int h = bitmap.getHeight(); 4 Bitmap output = Bitmap.createBitmap(w, h, Config.ARGB_8888); 5 Canvas canvas = new Canvas(output); 6finalint color = 0xff424242; 7final Paint paint = new Paint(); 8final Rect rect = new Rect(0, 0, w, h); 9final RectF rectF = new RectF(rect); 10 paint.setAntiAlias(true); 11 canvas.drawARGB(0, 0, 0, 0); 12 paint.setColor(color); 13 canvas.drawRoundRect(rectF, roundPx, roundPx, paint); 14 paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); 15 canvas.drawBitmap(bitmap, rect, rect, paint); 16 17return output; 18 }

七、得到帶倒影的圖片


 1publicstatic Bitmap createReflectionImageWithOrigin(Bitmap bitmap) { 2finalint reflectionGap = 4; 3int w = bitmap.getWidth(); 4int h = bitmap.getHeight(); 5 6 Matrix matrix = new Matrix(); 7 matrix.preScale(1, -1); 8 9 Bitmap reflectionImage = Bitmap.createBitmap(bitmap, 0, h / 2, w, 10 h / 2, matrix, false); 11 12 Bitmap bitmapWithReflection = Bitmap.createBitmap(w, (h + h / 2), 13 Config.ARGB_8888); 14 15 Canvas canvas = new Canvas(bitmapWithReflection); 16 canvas.drawBitmap(bitmap, 0, 0, null); 17 Paint deafalutPaint = new Paint(); 18 canvas.drawRect(0, h, w, h + reflectionGap, deafalutPaint); 19 20 canvas.drawBitmap(reflectionImage, 0, h + reflectionGap, null); 21 22 Paint paint = new Paint(); 23 LinearGradient shader = new LinearGradient(0, bitmap.getHeight(), 0, 24 bitmapWithReflection.getHeight() + reflectionGap, 0x70ffffff, 25 0x00ffffff, TileMode.CLAMP); 26 paint.setShader(shader); 27// Set the Transfer mode to be porter duff and destination in 28 paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN)); 29// Draw a rectangle using the paint with our linear gradient 30 canvas.drawRect(0, h, w, bitmapWithReflection.getHeight() 31 + reflectionGap, paint); 32 33return bitmapWithReflection; 34 }

3、Drawable

一、Bitmap轉換成Drawable

1 Bitmap bm=xxx; //xxx根據你的狀況獲取 2 BitmapDrawable bd= new BitmapDrawable(getResource(), bm); 3 由於BtimapDrawable是Drawable的子類,最終直接使用bd對象便可。

二、Drawable縮放


 1publicstatic Drawable zoomDrawable(Drawable drawable, int w, int h) { 2int width = drawable.getIntrinsicWidth(); 3int height = drawable.getIntrinsicHeight(); 4// drawable轉換成bitmap 5 Bitmap oldbmp = drawableToBitmap(drawable); 6// 建立操做圖片用的Matrix對象 7 Matrix matrix = new Matrix(); 8// 計算縮放比例 9float sx = ((float) w / width); 10float sy = ((float) h / height); 11// 設置縮放比例 12 matrix.postScale(sx, sy); 13// 創建新的bitmap,其內容是對原bitmap的縮放後的圖 14 Bitmap newbmp = Bitmap.createBitmap(oldbmp, 0, 0, width, height, 15 matrix, true); 16returnnew BitmapDrawable(newbmp); 17 }
android BitMap回收
2012-06-26 11:12

第一種方法--及時回收bitmap內存:編碼

通常而言,回收bitmap內存能夠用到如下代碼spa

if(bitmap != null && !bitmap.isRecycled()){
bitmap.recycle();
bitmap = null;
}
System.gc();
bitmap.recycle()方法用於回收該bitmap所佔用的內存,接着將bitmap置空,最後,別忘了用System.gc()調用一下系統的垃圾回收器。code

在這裏要聲明一下,bitmap能夠有多個(覺得着能夠有多個if語句),但System.gc()最好只有一個(因此我將它寫在了if語句外),由於System.gc()orm

每次調用都要將整個內存掃描一遍,於是若是屢次調用的話會影響程序運行的速度。爲了程序的效率,我將它放在了全部回收語句以後,

這樣已經起到了它的效果,還節約的時間。

回收bitmap已經知道了,那麼「及時」怎麼理解呢?

根據個人實際經驗,bitmap發揮做用的地方要麼在View裏,要麼在Activity裏(固然確定有其餘區域,可是原理都是相似的),

回收bitmap的地方最好寫在這些區域剛剛不使用bitmap了的時刻。

好比說View若是使用了bitmap,就應該在這個View再也不繪製了的時候回收,或者是在跳轉到的下一個區域的代碼中回收;

再好比說SurfaceView,就應該在onSurfaceDestroyed這個方法中回收;

同理,若是Activity使用了bitmap,就能夠在onStop或者onDestroy方法中回收......

結合以上的共同點,「及時回收」的原理就是在使用了bitmap的區域結束時或結束後回收。


第二種方法--壓縮圖片:

這個方法固然很簡單了,就是使圖片體積大小變小,

能夠有兩種方式:

一種是使圖片質量下降(分辨率不變),

另外一種是使圖片分辨率下降(分辨率改變)。

總之,使圖片大小變小就好了。

實踐證實,使圖片質量下降(分辨率不變)能夠大幅度地減少體積,並且質量的差別肉眼看上去並不明顯。

我剛開始使用的就是這兩種方法,原理很簡單,但是,個人BUG發生雖然沒那麼頻繁了,可是它依然存在!!

後來通過幾天的努力與嘗試,結合我項目的一些具體狀況,我終於解決了這個使人頭痛的BUG,可是事實卻有點出乎個人意料。

當我使用了上述兩種方法BUG依然還沒解決的時候,我開始懷疑,bitmap超過8M會報錯,可如今我把前先後後的bitmap都回收了,

不可能還有8M了,那爲何還會報錯呢?

終於我發現了這個緣由:當內存中已經被一些bitmap使用過以後,不管被回收與否,它都會變得特別「敏感」,這個時候,

若是bitmap忽然要佔用大量的內存,即便和以前已經剩下的內存加起來不到8M,系統也會報錯,緣由是它變「敏感」了!

我不知道這個用底層原理如何解釋比較好,可是我想「敏感」這個詞應該能夠很形象地進行解釋。

因而,爲了順應內存的「敏感性」,我將那個須要同時裝載多個大致積bitmap的地方進行了修改,用到了如下方法:

//壓縮,用於節省BITMAP內存空間--解決BUG的關鍵步驟
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inSampleSize = 2; //這個的值壓縮的倍數(2的整數倍),數值越小,壓縮率越小,圖片越清晰

//返回原圖解碼以後的bitmap對象
bitmap = BitmapFactory.decodeResource(Context, ResourcesId, opts);
即先將圖片縮小一倍,再將這縮小了一倍的圖片做爲bitmap存入內存,這樣一來,它佔用的bitmap內存大大減少。

後來經測試,BUG果真解決了。圖片縮小一倍後,順應了內存的「敏感性」,也就不會再報錯了。

以上方法應該足以解決大多數bitmap內存溢出問題,可是具體狀況仍是要具體分析。

相關文章
相關標籤/搜索