Android BitMap图片压缩
? ? ? ? ?最近在網上看了一些關于圖片壓縮的博客,自己也動手實驗了一遍,也算事對圖片壓縮有了一個了解,打算寫個博客記錄一下。文末附上參考鏈接。
? ? ? ? ?Android中涉及到圖片的話一般都會用到BitMap類和BitmapFactory類。而本文講述的圖片壓縮也都是通過這兩個類來實現的。Android中,圖片占用內存大小計算公式:圖片寬度 * 圖片高度 * 圖片每一個像素占用的字節數。所以圖片占用內存的大小(或者說壓縮),就是通過改變這三個值來改變的。
? ? ? ? ?1、質量壓縮
? ? ? ? ? ? ? 這種方法,它是通過改變圖片的位深和透明度來實現圖片壓縮的。它不會改變圖片的大小,也不會改變圖片占用的內存空間。它改變的是圖片對應的BitMap對象的length屬性值。下面是實現代碼:
private Bitmap compressQuality(Bitmap bitmap){ByteArrayOutputStream bos = new ByteArrayOutputStream();bitmap.compress(Bitmap.CompressFormat.JPEG,100,bos);byte bytes[] = bos.toByteArray();Log.d(TAG, "compressQuality: length = "+bytes.length);return BitmapFactory.decodeByteArray(bytes,0,bytes.length);}? ? ? ? 上述代碼重點是compress方法的使用,下面是它的API的形式。
//按指定的圖片格式以及畫質,將圖片轉換為輸出流。 public boolean compress(CompressFormat format, int quality, OutputStream stream)? ? ? ? 這個方法接收一個圖片格式參數(format),畫質參數(quality)還有一個輸出流(stream)。圖片格式參數有JPEG、PNG和WEBP,畫質參數是[0,100]區間。使用這個方法壓縮圖片的時候,我們主要是想把圖片對應的BitMap對象的length屬性變小,以應對一些對圖片大小有限制的情況。而這里就需要注意,當圖片格式參數為Bitmap.CompressFormat.PNG的時候,是無法改變這個length屬性值的,因為PNG格式是無損的。畫質參數為100的時候,length屬性值也不變,表示不壓縮。
? ? ? ? ?對于上面代碼,還可以學習到的知識點是:BitMap轉換成字節數組(使用ByteArrayOutputStream類)及字節數組轉換成BitMap(使用decodeByteArray方法)
? ? ? ?2、采樣率壓縮
? ? ? ? ? ?這種方法是通過改變BitmapFactory.Options的inSampleSize屬性值來改變圖片的大小的。通過它的代碼注釋可以知道,它是用來記錄圖片壓縮倍數的,如果它的值是4,那么它的寬高最后都變成原來的1/4,根據前面圖片占用內存大小公式,最終它占用內存大小就變成原來的1/16。這里我設置它的值為2,則最后占用內存大小為原來的1/4。
private Bitmap compressSampling(){BitmapFactory.Options options = new BitmapFactory.Options();options.inSampleSize = 2;return BitmapFactory.decodeResource(getResources(),R.mipmap.fengjing,options);}/*** If set to a value > 1, requests the decoder to subsample the original* image, returning a smaller image to save memory. The sample size is* the number of pixels in either dimension that correspond to a single* pixel in the decoded bitmap. For example, inSampleSize == 4 returns* an image that is 1/4 the width/height of the original, and 1/16 the* number of pixels. Any value <= 1 is treated the same as 1. Note: the* decoder uses a final value based on powers of 2, any other value will* be rounded down to the nearest power of 2.*/public int inSampleSize;? ? 3、縮放法壓縮
? ? ? ? 這種方法通過給給定一個矩陣來對圖片進行壓縮,通過查看createBitMap的源碼發現,最終也是改變圖片的寬高實現的。
private Bitmap compressMatrix(Bitmap bitmap){Matrix matrix = new Matrix();matrix.setScale(0.5f,0.5f);return Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),matrix,true);}public static Bitmap createBitmap(@NonNull Bitmap source, int x, int y, int width, int height,@Nullable Matrix m, boolean filter) {//...if (m == null || m.isIdentity()) {bitmap = createBitmap(neww, newh, newConfig, source.hasAlpha());paint = null; // not needed} else {final boolean transformed = !m.rectStaysRect();m.mapRect(deviceR, dstR);neww = Math.round(deviceR.width());newh = Math.round(deviceR.height());//...bitmap = createBitmap(neww, newh, transformedConfig, transformed || source.hasAlpha());//...}return bitmap;}? ? ?4、RGB_565格式壓縮
? ? ? ? ? ?前面說到,圖片占用內存大小公式是:圖片寬度 * 圖片高度 * 圖片每一個像素占用的字節數。而上面的兩種方法都是通過改變圖片的寬高來實現壓縮的,接著講解的這種方法就是通過改變圖片每一個像素占用的字節數來改變圖片占用內存空間。
? ? ? ? ? 先來了解一下,圖片常用的壓縮格式:
| ALPHA_8 | 一個像素點占用1個字節,它沒有顏色,只有透明度 | 
| ARGB_4444 | 一個像素點占用2個字節 | 
| ARGB_8888 | 一個像素點占用4個字節 | 
| RGB_565 | 一個像素點占用2個字節,它沒有透明度 | 
代碼如下:
private Bitmap compressRGB565(){BitmapFactory.Options options = new BitmapFactory.Options();options.inPreferredConfig = Bitmap.Config.ALPHA_8;Log.d(TAG, "compressRGB565: "+options.inSampleSize);Log.d(TAG, "compressRGB565: "+options.inPreferredConfig);Log.d(TAG, "compressRGB565: "+options.inDensity);Log.d(TAG, "compressRGB565: "+options.outWidth);Log.d(TAG, "compressRGB565: "+options.outHeight);Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.fengjing,options);Log.d(TAG, "compressRGB565: -----------------");Log.d(TAG, "compressRGB565: "+options.inSampleSize);Log.d(TAG, "compressRGB565: "+options.inPreferredConfig);Log.d(TAG, "compressRGB565: "+options.inDensity);Log.d(TAG, "compressRGB565: "+options.outWidth);Log.d(TAG, "compressRGB565: "+options.outHeight);return bitmap;}? ? ? ? 實現這種方式的方法是通過更改BitmapFactory.Options的inPreferredConfig值。默認情況下,Android使用ARGB_8888格式。實驗中,除了ARGB_4444格式,看到的現象是一個黑色的圖片區域,沒有顯示外,其他格式圖片正常顯示,內存大小以ARGB_8888格式為準的話,其他格式都縮小相應倍數。
? ? ? ? 注意:由于ARGB_4444的畫質慘不忍睹,一般假如對圖片沒有透明度要求的話,可以改成RGB_565,相比ARGB_8888將節省一半的內存開銷。
? ? ? ?上面的代碼我加了一些日志打印,主要是為了驗證,執行完BitmapFactory.decodeResource方法之后,會對options的一些屬性進行賦值,所以在某些情況下,會使用這種方式來獲取圖片的options信息。
? ? ? ?5、使用createScaleBitMap壓縮
private Bitmap compressScaleBitMap(Bitmap bitmap){int w = bitmap.getWidth();int h = bitmap.getHeight();return Bitmap.createScaledBitmap(bitmap, (int) (w*0.8), (int) (h*0.7),true);}? ? ? ? ? ? ?這種方法通過給定期望的圖片寬高來進行圖片的壓縮。注意圖片大小改動太大會導致圖片的畫質變得很差。
?
? ? ? 總結
? ? ? ? ? ?第一種方法,質量壓縮。不改變圖片的大小,不改變內存占用空間。但會改變圖片對于的Bitmap對象的字節length值。
? ? ? ? ? ?第二種方法,采樣率壓縮。通過改變圖片的寬高來改變圖片大小及占用的內存空間。使用BitmapFactory類來實現。
? ? ? ? ? ?第三種方法,縮放法壓縮。通過給定一個具體的矩陣來改變圖片大小及占用的內存空間。使用BitMap類實現。
? ? ? ? ? ?第四種方法,RGB_565格式壓縮。通過改變圖片每一個像素占用的字節數來改變圖片大小及占用內存空間。
? ? ? ? ? ?第五種方法,createScaleBitMap壓縮。通過給定期望的圖片寬高來改變圖片的大小及占用內存空間。
? ? ? ? ? 以上五種方法只是針對Android運行加載的Bitmap占用內存來說,壓縮后的Bitmap存儲到SD卡中,占用的內存空間并不一樣。App開發過程中,如果需要對內存做優化,可以從這方面入手。
?
參考鏈接:
? ? ? ? ? ? ? ?bitmap的六種壓縮方式,Android圖片壓縮
? ? ? ? ? ? ? ?Android Bitmap的常用壓縮方式
? ? ? ? ? ? ??Android圖片緩存之Bitmap詳解
? ? ? ? ? ??
?
?
總結
以上是生活随笔為你收集整理的Android BitMap图片压缩的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: OpenCV C++案例实战六《绿幕视频
 - 下一篇: SqlServer Tigger