一、bitmap 圖片格式介紹
android中圖片是以bitmap形式存在的,那么bitmap所占內存,直接影響到了應用所占內存大小,首先要知道bitmap所占內存大小計算方式:
bitmap內存大小 = 圖片長度 x 圖片寬度 x 一個像素點占用的字節數
以下是圖片的壓縮格式:
其中,A代表透明度;R代表紅色;G代表綠色;B代表藍色。
- ALPHA_8 表示8位Alpha位圖,即A=8,一個像素點占用1個字節,它沒有顏色,只有透明度
- ARGB_4444 表示16位ARGB位圖,即A=4,R=4,G=4,B=4,一個像素點占4+4+4+4=16位,2個字節
- ARGB_8888 表示32位ARGB位圖,即A=8,R=8,G=8,B=8,一個像素點占8+8+8+8=32位,4個字節
- RGB_565 表示16位RGB位圖,即R=5,G=6,B=5,它沒有透明度,一個像素點占5+6+5=16位,2個字節
內部相關函數介紹:http://blog.csdn.net/xxxzhi/article/details/51607765
顯示bitmap: http://blog.csdn.net/ymangu666/article/details/37729109
二、生成Bitmap對象:
1. 從drawable資源文件中生成Bitmap對象:可以通過Option設置生成bitmap的屬性
BitmapFactory.Options options = new BitmapFactory.Options(); options.inPreferredConfig = Bitmap.Config.RGB_565; options.inScaled = false; Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.kb455,options);
注: 如果資源只放在drawable目錄下,沒有在hdpi等文件夾中,獲取的bitmap文件會非常大,超過原始圖片的大小,很可能出現OOM。
一種辦法是將資源文件放在各個 dpi目錄下 二、可以設置為options.inscaled = false,生成的bitmap與圖片大小一致。
還可以通過其它渠道生成bitmap如inputstream,代碼見“四”中的例子。
這里需要注意的是 Option.inJustDecodeBounds 這個變量,官方的解釋:
If set to true, the decoder will return null (no bitmap), but the out… fields will still be set, allowing the caller to query the bitmap without having to allocate the memory for its pixels.
當只是需要來獲取圖片的寬高而不創建一個 bitmap對象時需要設置為 true,這時系統不會分配 bitmap的內存。如下是官方的例子:
BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(getResources(), R.id.myimage, options); int imageHeight = options.outHeight; int imageWidth = options.outWidth; String imageType = options.outMimeType;
三、圖片壓縮(不改變圖片寬高)
下面代碼通過while循環將圖片壓縮到topLimit(KB)之下,但是該種方法有個缺點,如果topLimit很小,但是原始的Bitmap
又很大,當options減小到負值時任然不能達到目標大小之下。(http://www.jianshu.com/p/0ab8fde08bcf)
public static byte[] compressQualityBitmap(Bitmap bitmap, int topLimit) { if(bitmap != null && topLimit > 0) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); int options = 100; bitmap.compress(CompressFormat.JPEG, options, baos); while(baos.toByteArray().length > topLimit * 1024) { baos.reset(); options -= 5; bitmap.compress(CompressFormat.JPEG, options, baos); } byte[] bitmapArray = baos.toByteArray(); try { baos.close(); baos = null; } catch (IOException var14) { ; } finally { if(baos != null) { try { baos.close(); baos = null; } catch (IOException var13) { ; } } return bitmapArray; } } else { return null; } }
1、下面函數是在保持像素的前提下改變圖片的位深及透明度等,來達到壓縮圖片的目的,這也是為什么該方法叫質量壓縮方法。圖片的長,寬,像素都不變,bitmap所占內存大小是不會變的,但是壓縮到byte數組baos的長度會逐漸的變小。
bitmap.compress(CompressFormat.JPEG, options, baos);
2、需要如果是bit.compress(CompressFormat.PNG, quality, baos);這樣的png格式,quality就沒有作用了,bytes.length不會變化,因為png圖片是無損的,不能進行壓縮。
3、該方法壓縮並不能無限制的壓縮,當壓縮到一定程度后,baos的長度變不再變化。
改變圖片的格式:
第一章中列出了四種格式的Config,可以將ARGB_8888格式轉換為 RGB_565存儲空間可以減少為原來的一半,而不改變圖片的寬高。
四、圖片縮放(改變圖片寬高)
1、bitmap采樣率壓縮:在BitmapFactory.decodexxxx() 設置 options.inSampleSize 大小來縮放圖片例如: 為2時,縮放為原來寬高的一半。
public static Bitmap compressBoundsBitmap(Context context, Uri uri, int targetWidth, int targetHeight) { InputStream input = null; Bitmap bitmap = null; try { input = context.getContentResolver().openInputStream(uri); Options options = new Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeStream(input, (Rect)null, options); input.close(); int originalWidth = options.outWidth; int originalHeight = options.outHeight; if(originalWidth != -1 && originalHeight != -1) { boolean be1 = true; int widthBe = 1; if(originalWidth > targetWidth) { widthBe = originalWidth / targetWidth; } int heightBe = 1; if(originalHeight > targetHeight) { heightBe = originalHeight / targetHeight; } int be2 = widthBe > heightBe?heightBe:widthBe; if(be2 <= 0) { be2 = 1; } options.inJustDecodeBounds = false; options.inSampleSize = be2; input = context.getContentResolver().openInputStream(uri); bitmap = BitmapFactory.decodeStream(input, (Rect)null, options); input.close(); input = null; } else { Object be = null; } } catch (FileNotFoundException var23) { ; } catch (IOException var24) { ; } finally { if(input != null) { try { input.close(); } catch (IOException var22) { ; } } return bitmap; } }
優點:效率較高,解析速度快
缺點:采樣率inSampleSize的取值只能是2的次方數(例如:inSampleSize=15,實際取值為8;inSampleSize=17,實際取值為16;實際取值會往2的次方結算),因此該方法不能精確的指定圖片的大小
2.通過Matrix縮放圖片(不推薦)

/** * 圖片的縮放方法 * * @param bitmap :源圖片資源 * @param maxSize :圖片允許最大空間 單位:KB * @return */ public static Bitmap getZoomImage(Bitmap bitmap, double maxSize) { if (null == bitmap) { return null; } if (bitmap.isRecycled()) { return null; } // 單位:從 Byte 換算成 KB double currentSize = bitmapToByteArray(bitmap, false).length / 1024; // 判斷bitmap占用空間是否大於允許最大空間,如果大於則壓縮,小於則不壓縮 while (currentSize > maxSize) { // 計算bitmap的大小是maxSize的多少倍 double multiple = currentSize / maxSize; // 開始壓縮:將寬帶和高度壓縮掉對應的平方根倍 // 1.保持新的寬度和高度,與bitmap原來的寬高比率一致 // 2.壓縮后達到了最大大小對應的新bitmap,顯示效果最好 bitmap = getZoomImage(bitmap, bitmap.getWidth() / Math.sqrt(multiple), bitmap.getHeight() / Math.sqrt(multiple)); currentSize = bitmapToByteArray(bitmap, false).length / 1024; } return bitmap; } /** * 圖片的縮放方法 * * @param orgBitmap :源圖片資源 * @param newWidth :縮放后寬度 * @param newHeight :縮放后高度 * @return */ public static Bitmap getZoomImage(Bitmap orgBitmap, double newWidth, double newHeight) { if (null == orgBitmap) { return null; } if (orgBitmap.isRecycled()) { return null; } if (newWidth <= 0 || newHeight <= 0) { return null; } // 獲取圖片的寬和高 float width = orgBitmap.getWidth(); float height = orgBitmap.getHeight(); // 創建操作圖片的matrix對象 Matrix matrix = new Matrix(); // 計算寬高縮放率 float scaleWidth = ((float) newWidth) / width; float scaleHeight = ((float) newHeight) / height; // 縮放圖片動作 matrix.postScale(scaleWidth, scaleHeight); Bitmap bitmap = Bitmap.createBitmap(orgBitmap, 0, 0, (int) width, (int) height, matrix, true); return bitmap; } /** * bitmap轉換成byte數組 * * @param bitmap * @param needRecycle * @return */ public static byte[] bitmapToByteArray(Bitmap bitmap, boolean needRecycle) { if (null == bitmap) { return null; } if (bitmap.isRecycled()) { return null; } ByteArrayOutputStream output = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.PNG, 100, output); if (needRecycle) { bitmap.recycle(); } byte[] result = output.toByteArray(); try { output.close(); } catch (Exception e) { Log.e(TAG, e.toString()); } return result; }
優點:可以精確地指定圖片的縮放大小
缺點:是在原bitmap的基礎之上生成的,占內存,效率低.
3/ThumbnailUtils 類進行
將bitmap轉換為byte方法:
public static byte[] BitmapToByte(Bitmap bitmap) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); bitmap.compress(CompressFormat.PNG, 80, baos);//其中80參數表示要壓縮的比例 return baos.toByteArray(); }
參考:http://blog.csdn.net/harryweasley/article/details/51955467