關(guān)于bitmap一些常見問題大小壓縮等

雖說從事android開發(fā)多年,但是一直處于不求甚解的過程,只是積累了工作年限,但實(shí)際的工作經(jīng)驗(yàn)并未見長,這不在日常開發(fā)中會(huì)經(jīng)常遇到的bitmap的相關(guān)問題,每次都得百度一番慚愧慚愧呀!

首先在實(shí)際應(yīng)用中,會(huì)遇到各種概念,有時(shí)總是傻傻的分不清楚衷掷,索性又百度了一番結(jié)合源碼來個(gè)小小的總結(jié)吧齿坷。

與大小相關(guān)的概念
  • 圖片實(shí)際大小
  • 圖片占用內(nèi)存空間大小
原始圖片

在tinyPNG網(wǎng)站上壓縮之后的圖片
占用內(nèi)存空間顯示

一張圖片占用內(nèi)存空間大小是多少?

我們可以看到2個(gè)圖片的分辯率都是1500*2560,一個(gè)是2.73 MB,一個(gè)是583 KB,在經(jīng)過BitmapFactory.decodeResource (禁止縮放)之后得到bitmap,再通過Bitmap.getAllocationByteCount獲取占用內(nèi)存空間大小竟然是一樣的,讓人疑惑些阅?

Bitmap類中有2個(gè)方法getAllocationByteCountgetByteCount:

getAllocationByteCount 根據(jù)文檔的意思即占用內(nèi)存空間大小,在沒有其他操作的情況下默認(rèn)與getByteCount取值一樣,那么也就是說默認(rèn)這個(gè)值一樣,大小為getRowBytes() * getHeight()再深入一些,會(huì)發(fā)現(xiàn)getRowBytes涉及到了C++代碼,暫且不說,可以參考其他文檔

image-20200910173344850

getRowBytes代碼沒找到,C++不懂,不過這個(gè)取值實(shí)際就是= 寬 * 4 * 高,這個(gè)是在沒有任何縮放的情況下計(jì)算的 剪决。

  • 作一個(gè)說明如果圖片來源是File次员、URL 或者 Assets目錄歧匈,通過BitmapFactory得到的圖片則是沒有縮放的,其占用內(nèi)存空間大小就是等于 寬 * 4 * 高;

  • 如果圖片來源資源目錄xxhdpi(480dpi) 垒酬、xxxhdpi(640dpi)等其他目錄 ,則在經(jīng)過·BitmapFactory解析得到bitmap的時(shí)候 會(huì)經(jīng)過縮放,縮放比為設(shè)備的DPI與資源目錄對(duì)應(yīng)的DPI進(jìn)行對(duì)比,也就是我們經(jīng)常遇過的現(xiàn)象 如手機(jī)設(shè)備的density為480,

    • 這個(gè)時(shí)候若把圖片放在xxhdpi里面,解析得到的bitmap然后取其寬高,這個(gè)取值跟實(shí)際的一樣,

    • 這個(gè)時(shí)候若將圖片放到xhdpi里面,則得到的bitmap的寬高都會(huì)變大,圖片放大了

    • 這個(gè)時(shí)候若將圖片放到xxhdpi里面,剛得到bitmap的寬高都會(huì)變小,圖片縮小了

    在種場(chǎng)景之下,獲取的的bitmap所占用的內(nèi)存空間則為 寬 x scale x 4 x 高 x scale

與圖片壓縮相關(guān)
  • 質(zhì)量壓縮 compress
  • 鄰近采樣壓縮 options.inSampleSize=2
  • 雙線性采樣 matrix.setScale(0.5f, 0.5f);
  • 還有一些其他策略但涉及到底層算法之類的,暫時(shí)還搞不懂

具體可以參考上篇文章里面推薦的鏈接

Android中圖片壓縮分析(下)

LuBan 仿微信朋友圈壓縮策略

魯班壓縮,這個(gè)工具類庫代碼不多,1.1.8版本壓縮核心方法其實(shí)也就是先采樣再質(zhì)量壓縮 ,這樣可以適用于一般的場(chǎng)景之下, 由于這個(gè)類庫長期未進(jìn)行更新,遺留許多問題需要改進(jìn),但我們可以借鑒其原理,根據(jù)實(shí)際情況加一改進(jìn)。

 File compress() throws IOException {

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = computeSize();//計(jì)算采樣率
        Bitmap tagBitmap = BitmapFactory.decodeStream(srcImg.open(), null, options);
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        if (Checker.SINGLE.isJPG(srcImg.open())) {
            //旋轉(zhuǎn)圖片
            tagBitmap = rotatingImage(tagBitmap,Checker.SINGLE.getOrientation(srcImg.open()));
        }
        //是否保留透明通道 保留PNG無損壓縮 JPEG質(zhì)量60%
     tagBitmap.compress(focusAlpha ? Bitmap.CompressFormat.PNG :     Bitmap.CompressFormat.JPEG, 60, stream);

        tagBitmap.recycle();

        FileOutputStream fos = new FileOutputStream(tagImg);
        fos.write(stream.toByteArray());
        fos.flush();
        fos.close();
        stream.close();
        return tagImg;
 }
  private int computeSize() {
        //%2==1的話 加1  是為了方便計(jì)算取整吧
        srcWidth = srcWidth % 2 == 1 ? srcWidth + 1 : srcWidth;
        srcHeight = srcHeight % 2 == 1 ? srcHeight + 1 : srcHeight;

        int longSide = Math.max(srcWidth, srcHeight);
        int shortSide = Math.min(srcWidth, srcHeight);
        //先計(jì)算一下寬高比   拍照寬高比 16:9=1:0.5625
        float scale = ((float) shortSide / longSide);
      //這些取值不知道作者是根據(jù)什么推斷出來的勘究,但現(xiàn)在從微信聊天記錄中保存的圖片大小似乎是1080*1440
        if (scale <= 1 && scale > 0.5625) {
            if (longSide < 1664) {
                return 1;
            } else if (longSide < 4990) { //1024*4 = 4096
                return 2;
            } else if (longSide > 4990 && longSide < 10240) {
                return 4;
            } else {
                return longSide / 1280 == 0 ? 1 : longSide / 1280;
            }
        } else if (scale <= 0.5625 && scale > 0.5) {
            return longSide / 1280 == 0 ? 1 : longSide / 1280;
        } else {
            return (int) Math.ceil(longSide / (1280.0 / scale));
        }
    }
保存圖片大小的問題

在對(duì)bitmap壓縮之后矮湘,有時(shí)我們會(huì)將圖片保存到本地,這個(gè)時(shí)候有時(shí)會(huì)發(fā)現(xiàn)實(shí)際保存的圖片大小 與壓縮之后計(jì)算的預(yù)計(jì)保存的圖片大小不一致的問題?

InputStream inputStream1 = getResources().openRawResource(R.mipmap.china_map_xxhdpi);
//這個(gè)大小 基本與硬盤中的顯示大小一樣,如果略有差別應(yīng)該是kb按照1000或者1024計(jì)算的原因
KLog.d(TAG, "==china map 原始大小" + inputStream1.available() / default_size + "kb");

Drawable drawable = getResources().getDrawable(R.mipmap.china_map_xxhdpi);
Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
KLog.d(TAG, "占用內(nèi)存大小 getAllocationByteCount===" + bitmap.getAllocationByteCount() / default_size + " kb");

ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
KLog.d(TAG, "==before=baos大小===最高質(zhì)量壓縮的大小" + baos.toByteArray().length / default_size + " kb");

int quality = 95;
boolean flag = true;
while (baos.toByteArray().length / default_size > 100 && flag) {
    baos.reset();   
    bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos);
    quality -= 5;
    if (quality <= 0) {
        flag = false;
    }

}
KLog.d(TAG, "==after=baos大小===控制100以內(nèi)-----" + baos.toByteArray().length / default_size + " kb");
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(baos.toByteArray());
KLog.d(TAG, "byteArrayInputStream==1024===" + byteArrayInputStream.available() / default_size + " kb");
KLog.d(TAG, "byteArrayInputStream==1000===" + byteArrayInputStream.available() / 1000 + " kb");
    ...省略
//圖片大小 與計(jì)算大小致
String filepath = dirpath + File.separator + name + ".jpg";
KLog.d(filepath);
FileOutputStream fos = new FileOutputStream(new File(filepath));
fos.write(baos.toByteArray());
fos.flush();
fos.close();

ByteArrayOutputStream baosResult = new ByteArrayOutputStream();
resultBitmap.compress(Bitmap.CompressFormat.JPEG, 100, baosResult);
KLog.d(TAG, "===baosResult==resultBitmap==" + baosResult.toByteArray().length / default_size + " kb");

//經(jīng)測(cè)試保存的圖片確實(shí) 變大 了
String filepath2 = dirpath + File.separator + name + "_result_" + baosResult.toByteArray().length / default_size + ".jpg";
KLog.d(filepath2);
FileOutputStream fos2 = new FileOutputStream(new File(filepath2));
fos2.write(baosResult.toByteArray());
fos2.flush();
fos2.close();

image-20200910190503664

image-20200910191137723

所以說當(dāng)壓縮圖片到目標(biāo)大小后,不能再經(jīng)過其他操作,直接使用流保存到本地這個(gè)時(shí)候大小就與計(jì)算大小一樣,如果再經(jīng)過轉(zhuǎn)換大小就可能出現(xiàn)變化口糕。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末缅阳,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子景描,更是在濱河造成了極大的恐慌十办,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件伏伯,死亡現(xiàn)場(chǎng)離奇詭異橘洞,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)说搅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門炸枣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人弄唧,你說我怎么就攤上這事适肠。” “怎么了候引?”我有些...
    開封第一講書人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵侯养,是天一觀的道長。 經(jīng)常有香客問我澄干,道長逛揩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任麸俘,我火速辦了婚禮辩稽,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘从媚。我一直安慰自己逞泄,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開白布拜效。 她就那樣靜靜地躺著喷众,像睡著了一般。 火紅的嫁衣襯著肌膚如雪紧憾。 梳的紋絲不亂的頭發(fā)上到千,一...
    開封第一講書人閱讀 51,155評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音赴穗,去河邊找鬼父阻。 笑死愈涩,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的加矛。 我是一名探鬼主播履婉,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼斟览!你這毒婦竟也來了毁腿?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤苛茂,失蹤者是張志新(化名)和其女友劉穎已烤,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體妓羊,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡胯究,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了躁绸。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片裕循。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖净刮,靈堂內(nèi)的尸體忽然破棺而出剥哑,到底是詐尸還是另有隱情,我是刑警寧澤淹父,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布株婴,位于F島的核電站,受9級(jí)特大地震影響暑认,放射性物質(zhì)發(fā)生泄漏困介。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一蘸际、第九天 我趴在偏房一處隱蔽的房頂上張望逻翁。 院中可真熱鬧,春花似錦捡鱼、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至溶浴,卻和暖如春乍迄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背士败。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來泰國打工闯两, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留褥伴,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓漾狼,卻偏偏與公主長得像重慢,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子逊躁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353