Android BitMap图片压缩
? ? ? ? ?最近在網(wǎng)上看了一些關(guān)于圖片壓縮的博客,自己也動(dòng)手實(shí)驗(yàn)了一遍,也算事對圖片壓縮有了一個(gè)了解,打算寫個(gè)博客記錄一下。文末附上參考鏈接。
? ? ? ? ?Android中涉及到圖片的話一般都會(huì)用到BitMap類和BitmapFactory類。而本文講述的圖片壓縮也都是通過這兩個(gè)類來實(shí)現(xiàn)的。Android中,圖片占用內(nèi)存大小計(jì)算公式:圖片寬度 * 圖片高度 * 圖片每一個(gè)像素占用的字節(jié)數(shù)。所以圖片占用內(nèi)存的大小(或者說壓縮),就是通過改變這三個(gè)值來改變的。
? ? ? ? ?1、質(zhì)量壓縮
? ? ? ? ? ? ? 這種方法,它是通過改變圖片的位深和透明度來實(shí)現(xiàn)圖片壓縮的。它不會(huì)改變圖片的大小,也不會(huì)改變圖片占用的內(nèi)存空間。它改變的是圖片對應(yīng)的BitMap對象的length屬性值。下面是實(shí)現(xiàn)代碼:
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);}? ? ? ? 上述代碼重點(diǎn)是compress方法的使用,下面是它的API的形式。
//按指定的圖片格式以及畫質(zhì),將圖片轉(zhuǎn)換為輸出流。 public boolean compress(CompressFormat format, int quality, OutputStream stream)? ? ? ? 這個(gè)方法接收一個(gè)圖片格式參數(shù)(format),畫質(zhì)參數(shù)(quality)還有一個(gè)輸出流(stream)。圖片格式參數(shù)有JPEG、PNG和WEBP,畫質(zhì)參數(shù)是[0,100]區(qū)間。使用這個(gè)方法壓縮圖片的時(shí)候,我們主要是想把圖片對應(yīng)的BitMap對象的length屬性變小,以應(yīng)對一些對圖片大小有限制的情況。而這里就需要注意,當(dāng)圖片格式參數(shù)為Bitmap.CompressFormat.PNG的時(shí)候,是無法改變這個(gè)length屬性值的,因?yàn)镻NG格式是無損的。畫質(zhì)參數(shù)為100的時(shí)候,length屬性值也不變,表示不壓縮。
? ? ? ? ?對于上面代碼,還可以學(xué)習(xí)到的知識(shí)點(diǎn)是:BitMap轉(zhuǎn)換成字節(jié)數(shù)組(使用ByteArrayOutputStream類)及字節(jié)數(shù)組轉(zhuǎn)換成BitMap(使用decodeByteArray方法)
? ? ? ?2、采樣率壓縮
? ? ? ? ? ?這種方法是通過改變BitmapFactory.Options的inSampleSize屬性值來改變圖片的大小的。通過它的代碼注釋可以知道,它是用來記錄圖片壓縮倍數(shù)的,如果它的值是4,那么它的寬高最后都變成原來的1/4,根據(jù)前面圖片占用內(nèi)存大小公式,最終它占用內(nèi)存大小就變成原來的1/16。這里我設(shè)置它的值為2,則最后占用內(nèi)存大小為原來的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、縮放法壓縮
? ? ? ? 這種方法通過給給定一個(gè)矩陣來對圖片進(jìn)行壓縮,通過查看createBitMap的源碼發(fā)現(xiàn),最終也是改變圖片的寬高實(shí)現(xiàn)的。
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格式壓縮
? ? ? ? ? ?前面說到,圖片占用內(nèi)存大小公式是:圖片寬度 * 圖片高度 * 圖片每一個(gè)像素占用的字節(jié)數(shù)。而上面的兩種方法都是通過改變圖片的寬高來實(shí)現(xiàn)壓縮的,接著講解的這種方法就是通過改變圖片每一個(gè)像素占用的字節(jié)數(shù)來改變圖片占用內(nèi)存空間。
? ? ? ? ? 先來了解一下,圖片常用的壓縮格式:
| ALPHA_8 | 一個(gè)像素點(diǎn)占用1個(gè)字節(jié),它沒有顏色,只有透明度 |
| ARGB_4444 | 一個(gè)像素點(diǎn)占用2個(gè)字節(jié) |
| ARGB_8888 | 一個(gè)像素點(diǎn)占用4個(gè)字節(jié) |
| RGB_565 | 一個(gè)像素點(diǎn)占用2個(gè)字節(jié),它沒有透明度 |
代碼如下:
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;}? ? ? ? 實(shí)現(xiàn)這種方式的方法是通過更改BitmapFactory.Options的inPreferredConfig值。默認(rèn)情況下,Android使用ARGB_8888格式。實(shí)驗(yàn)中,除了ARGB_4444格式,看到的現(xiàn)象是一個(gè)黑色的圖片區(qū)域,沒有顯示外,其他格式圖片正常顯示,內(nèi)存大小以ARGB_8888格式為準(zhǔn)的話,其他格式都縮小相應(yīng)倍數(shù)。
? ? ? ? 注意:由于ARGB_4444的畫質(zhì)慘不忍睹,一般假如對圖片沒有透明度要求的話,可以改成RGB_565,相比ARGB_8888將節(jié)省一半的內(nèi)存開銷。
? ? ? ?上面的代碼我加了一些日志打印,主要是為了驗(yàn)證,執(zhí)行完BitmapFactory.decodeResource方法之后,會(huì)對options的一些屬性進(jìn)行賦值,所以在某些情況下,會(huì)使用這種方式來獲取圖片的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);}? ? ? ? ? ? ?這種方法通過給定期望的圖片寬高來進(jìn)行圖片的壓縮。注意圖片大小改動(dòng)太大會(huì)導(dǎo)致圖片的畫質(zhì)變得很差。
?
? ? ? 總結(jié)
? ? ? ? ? ?第一種方法,質(zhì)量壓縮。不改變圖片的大小,不改變內(nèi)存占用空間。但會(huì)改變圖片對于的Bitmap對象的字節(jié)length值。
? ? ? ? ? ?第二種方法,采樣率壓縮。通過改變圖片的寬高來改變圖片大小及占用的內(nèi)存空間。使用BitmapFactory類來實(shí)現(xiàn)。
? ? ? ? ? ?第三種方法,縮放法壓縮。通過給定一個(gè)具體的矩陣來改變圖片大小及占用的內(nèi)存空間。使用BitMap類實(shí)現(xiàn)。
? ? ? ? ? ?第四種方法,RGB_565格式壓縮。通過改變圖片每一個(gè)像素占用的字節(jié)數(shù)來改變圖片大小及占用內(nèi)存空間。
? ? ? ? ? ?第五種方法,createScaleBitMap壓縮。通過給定期望的圖片寬高來改變圖片的大小及占用內(nèi)存空間。
? ? ? ? ? 以上五種方法只是針對Android運(yùn)行加載的Bitmap占用內(nèi)存來說,壓縮后的Bitmap存儲(chǔ)到SD卡中,占用的內(nèi)存空間并不一樣。App開發(fā)過程中,如果需要對內(nèi)存做優(yōu)化,可以從這方面入手。
?
參考鏈接:
? ? ? ? ? ? ? ?bitmap的六種壓縮方式,Android圖片壓縮
? ? ? ? ? ? ? ?Android Bitmap的常用壓縮方式
? ? ? ? ? ? ??Android圖片緩存之Bitmap詳解
? ? ? ? ? ??
?
?
總結(jié)
以上是生活随笔為你收集整理的Android BitMap图片压缩的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OpenCV C++案例实战六《绿幕视频
- 下一篇: Android百度地图雷达效果,地图导航