安卓Bitmap的優(yōu)化處理

1 . 為了處理安卓中Bitmap圖片尺寸過(guò)大,導(dǎo)致內(nèi)存OOM,我們一般會(huì)對(duì)Bitmap處理一下,一般處理分為兩步。

  • 第一步,獲取原始Bitmap的尺寸信息,然后我們?cè)O(shè)置一些相關(guān)配置,來(lái)盡量壓縮圖片
//這個(gè)函數(shù)就是相關(guān)配置Bitmap信息
BitmapFactory.Options options = new BitmapFactory.Options();
//這個(gè)表示,我們?cè)趧?chuàng)建bitmap時(shí),只獲取相關(guān)參數(shù),不生成bitmap對(duì)象
options.inJustDecodeBounds = true;
//設(shè)置圖片色彩模式,也有RGB_565,ARGB_8888表示每個(gè)像素占4個(gè)字節(jié),RGB_565表示每個(gè)像素占2個(gè)字節(jié)
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
//對(duì)圖片寬高進(jìn)行壓縮,如果值為2,則表示圖片寬高分別為1/2,像素則減少了原始的1/4
//一般來(lái)說(shuō)這個(gè)samplesize可以有我們自己計(jì)算
options.inSampleSize = 2;

下面是一個(gè)完整的代碼,只計(jì)算配置信息,不生成bitmap

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
options.inPreferredConfig = Bitmap.Config.RGB_565;
//執(zhí)行這個(gè)方法,我們獲取到了option相關(guān)參數(shù)
BitmapFactory.decodeResource(getResources(), R.drawable.unnamed, options);
//計(jì)算samplesize ,根據(jù)你想要設(shè)置的寬高和原始圖片比較,
//當(dāng)然你也可以隨便設(shè)置,2,3,4都行
int sampleSize = calculateSampleSize(options, 400, 400);

 private int calculateSampleSize(BitmapFactory.Options options, int reqW, int reqH) {
        int sampleSize = 1;
        int real_h = options.outHeight;
        int real_w = options.outWidth;
        if (real_h > reqH || real_w > reqW) {

            int sam_h = Math.round((float) real_w / (float) real_h);
            int sam_w = Math.round((float) real_w / (float) reqW);

            sampleSize = Math.min(sam_h, sam_w);

        }

        return sampleSize;
    }


  • 第二部,將上面計(jì)算優(yōu)化過(guò)的Option參數(shù),傳入到Bitmap的創(chuàng)建函數(shù),獲取優(yōu)化后的Bitmap對(duì)象
options.inJustDecodeBounds=false;
options.inSampleSize = sampleSize;
options.inPreferredConfig = Bitmap.Config.RGB_565;

Bitmap real = BitmapFactory.decodeResource(getResources(), R.drawable.unnamed, options);

2 . bitmpa在內(nèi)存中計(jì)算,分兩種情況

  • 情況一BitmapFactory.decodeResource()

我們這里放一張?jiān)枷袼?20*405的圖片分別到到mipmap xhdpi文件夾中和mipmap xxhdpi

  BitmapFactory.Options options = new BitmapFactory.Options();
  Bitmap real = BitmapFactory.decodeResource(getResources(), R.mipmap.unnamed, options);

1.inDensity 取決于文件夾也就是xxhdpi還是xhdpi像素密度。取決于TypedValue,可以看下BitmapFactory.decodeResource方法源碼。
2.inTargetDensity 取決于手機(jī)屏幕密度。
3.底層源碼中源碼會(huì)對(duì)bitmap進(jìn)行縮放,縮放系數(shù)就是=inTargetDensity/inDensity,

  1. 像素字節(jié)數(shù)取決于BitmapFactory.Options.Config.ARGB***的設(shè)置,ARGB_8888表示每個(gè)像素占4個(gè)字節(jié),RGB_565占2個(gè)字節(jié)
  2. 所以最終bitmap在內(nèi)存中大小為 size = (原始寬)x(原始高)x(inTargetDensity/inDensity)x(inTargetDensity/inDensity)x像素字節(jié)數(shù)
 Log.d(TAG, "ffff: density = " + options.inDensity + "  target = " + options.inTargetDensity + "" +
                " size = " + real.getByteCount() + "  w= " + real.getWidth() + "  h = " + real.getHeight());

 /xhdpi:  density = 320  target = 420 size = 2010960  w= 945  h = 532
 /xxhdpi: density = 480  target = 420 size = 892080  w= 630  h = 354
  • 情況二 BitmapFactory.decodeStream()
    我們從assets文件夾照片加載圖片,也可以從手機(jī)外部存儲(chǔ)加載,以文件流的形式導(dǎo)入
    1.分析點(diǎn)進(jìn)去看BitmapFactory.decodeStream源碼可知,并由沒(méi)對(duì)Options.inTargetDensity和Options.inDensity進(jìn)行賦值,默認(rèn)都為0
    2.像素字節(jié)數(shù)取決于BitmapFactory.Options.Config.ARGB***的設(shè)置,ARGB_8888表示每個(gè)像素占4個(gè)字節(jié),RGB_565占2個(gè)字節(jié)
    3.所以此時(shí)bitmap在內(nèi)存中占據(jù)的大小=(原始寬)x(原始高)x像素字節(jié)數(shù)
  BitmapFactory.Options options = new BitmapFactory.Options();
        try {
            InputStream bitmap=getAssets().open("unnamed.jpg");
            Bitmap real=BitmapFactory.decodeStream(bitmap);

            Log.d(TAG, "ffff: density = " + options.inDensity + "  target = " + options.inTargetDensity + "" +
                    " size = " + real.getByteCount() + "  w= " + real.getWidth() + "  h = " + real.getHeight());


            //打印信息: density = 0  target = 0 size = 1166400  w= 720  h = 405

        } catch (IOException e) {
            e.printStackTrace();
        }

3 . bitmpa.getByteCount vs bitmpa.getAllocationByteCount區(qū)別

  • 這兩個(gè)方法都是計(jì)算bitmap占據(jù)內(nèi)存大小
  • getAllocationByteCount這個(gè)方法Added in API level 19 ,默認(rèn)情況這兩個(gè)返回結(jié)果相同,所以我們SD大于19時(shí),計(jì)算Bitmap大小最好用這個(gè)方法

假設(shè)內(nèi)存已經(jīng)存在bitmap1 ,大小1234,此時(shí)我有新建了一個(gè)bitmap2 其實(shí)就是對(duì)bitmap1縮小了一倍。
這時(shí)因?yàn)榘沧恳呀?jīng)支持對(duì)Bitmap的復(fù)用,完全沒(méi)必要重新去在建立一個(gè)bitmap對(duì)象,浪費(fèi)性能重新計(jì)算和編碼bitmap
我們直接復(fù)用bitmap1,在進(jìn)行處理復(fù)用處理之后,此時(shí)Bitmap2對(duì)象的大小getByteCount 可能等于500,但是getAllocationByteCount一定等于1234

參考

細(xì)說(shuō)Bitmap

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容