Bitmap

一、Bitmap簡介

Bitmap是位圖文件尽棕,擴(kuò)展名可以是.bmp或者.dib喳挑。

位圖是Windows標(biāo)準(zhǔn)格式圖形文件,它將圖像定義為由點(像素)組成滔悉,每個點可以由多種色彩表示伊诵,包括2,4氧敢,8日戈,16,24和32位色彩孙乖。

位圖文件的圖像效果好浙炼,但是是非壓縮格式的,需要占用較大存儲空間唯袄,不利于在網(wǎng)絡(luò)上傳送弯屈。jpg/png格式恰好彌補(bǔ)了位圖文件的缺點。

二恋拷、字節(jié)換算

計算機(jī)中的信息都是二進(jìn)制的0和1來表示资厉,其中每一個0或1都被稱為一個位,容量是B表示字節(jié)Byte蔬顾,傳輸速度是b表示bit(位)宴偿;
K-千 M-兆 G-吉咖 T-太拉

8bit(位)=1Byte(字節(jié))-->1B=8b
1024字節(jié)(1024B=1024Byte) --》一千字節(jié)(1KB)
1024千字節(jié)(1024 KB)--》一兆字節(jié)(1MB)
1024兆字節(jié)(1024MB)--》一吉字節(jié)(1GB)
1024吉字節(jié)(1024GB)--》一太字節(jié)(1TB)

Kb:千個位
KB:千個字節(jié),一般用來表示文件的大小單位
bps(b/s)是bits per second的縮寫诀豁,表示比特/秒
1KB=1024B=1024*8b
1kB=1000B=8000b
1Kb=1kb=1000b

k代表kilo窄刘,千的意思,也就是1000舷胜,而B就是字節(jié)的意思娩践,ps就是每秒的意思,那么連起來Bps是byte per second的縮寫烹骨,表示字節(jié)/秒翻伺;那kBps就是1000Bps就是一千字節(jié)每秒;

三沮焕、Bitmap計算

圖片是由像素組成的吨岭,要計算一張圖片的大小,需要知道3個參數(shù):圖片的長峦树,圖片的寬未妹,每個像素占用的內(nèi)存大小簿废。

3.1計算公式

圖片占用的內(nèi)存大小=圖片長x圖片寬x每個像素占用的內(nèi)存大小

API在19(包括)以上的使用bitmap.getAllocationByteCount()(返回byte)
API在12(包括)以上的使用
bitmap.getByteCount()(返回byte)
更低版本的使用
bitmap.getRowBytes() * bitmap.getHeight()(返回byte)

3.1.1 每個像素占用的內(nèi)存大小

Android中,每個像素占用的內(nèi)存大小是由Bitmap.Config來決定的络它,它有4中配置:


image.png

ARGB_8888:ARGB分別代表的是透明度,紅色,綠色,藍(lán)色,每個值分別用8bit來記錄,也就是一個像素會占用4byte,共32bit.
ARGB_4444:ARGB的是每個值分別用4bit來記錄,一個像素會占用2byte,共16bit.
RGB_565:R=5bit,G=6bit,B=5bit族檬,不存在透明度,每個像素會占用2byte,共16bit.
ALPHA_8:該像素只保存透明度,會占用1byte,共8bit.
在實際應(yīng)用中而言,建議使用ARGB_8888以及RGB_565。
如果你不需要透明度,那么就選擇RGB_565,可以減少一半的內(nèi)存占用.

影響B(tài)itmapFactory.decodeStream()生成的Bitmap的大小是Bitmap.Config化戳,Bitmap.Config不同单料,讀取出來的大小也不一樣。

例如:
一張圖片在windows中看到圖片文件大小是102k(這是壓縮之后的文件)点楼;通過BitmapFactory.decodeStream()方法轉(zhuǎn)成bitmap卻要分配750k的內(nèi)存(因為此時將壓縮文件解壓成內(nèi)存中的bitmap文件扫尖,這是適合顯示的格式,解壓之后掠廓,圖像所占空間變大)换怖;直接用FileOutputStream把inputStream寫入文件,文件大小是102k(這是將文件讀到內(nèi)存中蟀瞧,沒有做解碼操作沉颂,有原樣寫文件,所以大小也沒有變化)

四悦污、Bitmap回收

在安卓3.0以前Bitmap是存放在堆中的铸屉,我們只要回收堆內(nèi)存即可
在安卓3.0以后Bitmap是存放在內(nèi)存中的,我們需要回收native層和Java層的內(nèi)存
官方建議我們3.0以后使用recycle方法進(jìn)行回收切端,該方法也可以不主動調(diào)用彻坛,因為垃圾回收器會自動收集不可用的Bitmap對象進(jìn)行回收
recycle方法會判斷Bitmap在不可用的情況下,將發(fā)送指令到垃圾回收器踏枣,讓其回收native層和Java層的內(nèi)存昌屉,則Bitmap進(jìn)入dead狀態(tài)
recycle方法是不可逆的,如果再次調(diào)用getPixels()等方法茵瀑,則獲取不到想要的結(jié)果

五间驮、壓縮

圖片有三種存在形式:硬盤上是file,網(wǎng)絡(luò)傳輸是stream瘾婿,內(nèi)存中是stream或bitmap

bitmap:Android系統(tǒng)中的圖像格式蜻牢,通常只在內(nèi)存中存在烤咧,系統(tǒng)用于顯示圖像偏陪。bitmap是沒有壓縮的圖像,適合顯示煮嫌,不適合存儲笛谦,因為占用餓過多的存儲空間。

文件:存在硬盤/flash上的文件昌阿,通常是使用了某種壓縮方式饥脑,如jpeg/png恳邀。jpeg進(jìn)行了壓縮,適合存儲灶轰,不能直接顯示谣沸,需要解碼之后才能顯示。

5.1壓縮分類

圖片壓縮分為尺寸壓縮和質(zhì)量壓縮

5.1.1尺寸壓縮(采樣率壓縮)

減小了圖片的像素笋颤,所以它直接對bitmap產(chǎn)生了影響乳附,最終的file也是相對的變小了。主要影響內(nèi)存伴澄。

inSampleSize表示縮略圖大小為原始圖片大小的幾分之一赋除,即如果這個值為2,則取出的縮略圖的寬和高都是原始圖片的1/2非凌, 圖片大小就為原始大小的1/4

5.1.2質(zhì)量壓縮

原理:在保持像素的前提下改變圖片的位深及透明度等举农,來達(dá)到壓縮圖片的目的,bitmap圖片的大小不會改變敞嗡,bytes.length是隨著quality變小而變小的颁糟。

質(zhì)量只對file有影響,可以把一個file轉(zhuǎn)成bitmap在轉(zhuǎn)成file秸妥,或者直接將一個bitmap轉(zhuǎn)成file滚停,這個最終的file是被壓縮過的,但是中間的bitmap并沒有被壓縮(或者說幾乎沒有被壓縮);
因為bitmap在內(nèi)存中的大小是按像素點計算的粥惧,也就是width*height键畴,對于質(zhì)量壓縮,并不會改變圖片的像素突雪,所以就算質(zhì)量被壓縮起惕,但是bitmap在內(nèi)存的占有率還是沒變小,但是變成file時咏删,它確實變小了惹想。
這樣適合去傳遞二進(jìn)制的圖片數(shù)據(jù)。

5.2壓縮代碼

/**
 * 質(zhì)量壓縮督函,一直到小于maxsize
 */
public static Bitmap qualityCompressImage(Bitmap image, int maxSize) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        //質(zhì)量壓縮方法嘀粱,這里100表示不壓縮,把壓縮后的數(shù)據(jù)存放到baos中
        if (image == null) {
            return null;
        }
        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        int options = 100;
        //循環(huán)判斷如果壓縮后圖片是否大于maxSizekb,大于繼續(xù)壓縮
        while (baos.toByteArray().length / 1024 > maxSize) {
            //重置baos即清空baos
            baos.reset();
            //這里壓縮options%辰狡,把壓縮后的數(shù)據(jù)存放到baos中
            image.compress(Bitmap.CompressFormat.JPEG, options, baos);
            options -= 10;
            if (options < 0) {
                break;
            }
        }
        //把壓縮后的數(shù)據(jù)baos存放到ByteArrayInputStream中
        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
        //把ByteArrayInputStream數(shù)據(jù)生成圖片
        return BitmapFactory.decodeStream(isBm);
    }

   /**
     * 圖片按比例大小壓縮方法
     *
     * @param image (根據(jù)Bitmap圖片壓縮)
     * @return
     */
    public static Bitmap compressScale(Bitmap image, int maxSize) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        // 判斷如果圖片大于1M,進(jìn)行壓縮避免在生成圖片(BitmapFactory.decodeStream)時溢出
        if (baos.toByteArray().length / 1024 > 1024) {
            // 重置baos即清空baos
            baos.reset();
            // 這里壓縮80%锋叨,把壓縮后的數(shù)據(jù)存放到baos中
            image.compress(Bitmap.CompressFormat.JPEG, 80, baos);
        }
        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
        BitmapFactory.Options newOpts = new BitmapFactory.Options();
        // 開始讀入圖片,此時把options.inJustDecodeBounds 設(shè)回true
        newOpts.inJustDecodeBounds = true;
        Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);//此時bitmap返回空宛篇,可以避免bitmap的內(nèi)存分配只拿到bitmap的寬高及MimeType
        newOpts.inJustDecodeBounds = false;
        int w = newOpts.outWidth;
        int h = newOpts.outHeight;
        float hh = 800f;
        float ww = 480f;
        // 縮放比娃磺。由于是固定比例縮放,只用高或者寬其中一個數(shù)據(jù)進(jìn)行計算即可
        // be=1表示不縮放
        int be = 1;
        // 如果寬度大的話根據(jù)寬度固定大小縮放
        if (w > h && w > ww) {
            be = Math.round((float) newOpts.outWidth / ww);
            // 如果高度高的話根據(jù)高度固定大小縮放
        } else if (w < h && h > hh) {
            be = Math.round((float) newOpts.outHeight / hh);
        }
        if (be <= 0) {
            be = 1;
        }
        // 設(shè)置縮放比例
        newOpts.inSampleSize = be;//寬高都為原來的1/be
        // newOpts.inPreferredConfig = Config.RGB_565;//降低圖片從ARGB888到RGB565
        // 重新讀入圖片叫倍,注意此時已經(jīng)把options.inJustDecodeBounds 設(shè)回false了
        isBm = new ByteArrayInputStream(baos.toByteArray());
        bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);
        // 壓縮好比例大小后再進(jìn)行質(zhì)量壓縮
        return qualityCompressImage(bitmap, maxSize);
    }

參考:
(12條消息) android 根據(jù)圖片url獲取bitmap或者drawable偷卧,然后再進(jìn)行壓縮處理_碼在飛博客-CSDN博客
Android中的Bitmap的詳細(xì)介紹Android腳本之家 (jb51.net)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末豺瘤,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子听诸,更是在濱河造成了極大的恐慌坐求,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件晌梨,死亡現(xiàn)場離奇詭異瞻赶,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)派任,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進(jìn)店門砸逊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人掌逛,你說我怎么就攤上這事师逸。” “怎么了豆混?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵篓像,是天一觀的道長。 經(jīng)常有香客問我皿伺,道長员辩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任鸵鸥,我火速辦了婚禮奠滑,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘妒穴。我一直安慰自己宋税,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布讼油。 她就那樣靜靜地躺著杰赛,像睡著了一般。 火紅的嫁衣襯著肌膚如雪矮台。 梳的紋絲不亂的頭發(fā)上乏屯,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天,我揣著相機(jī)與錄音瘦赫,去河邊找鬼辰晕。 笑死,一個胖子當(dāng)著我的面吹牛耸彪,可吹牛的內(nèi)容都是我干的伞芹。 我是一名探鬼主播忘苛,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼蝉娜,長吁一口氣:“原來是場噩夢啊……” “哼唱较!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起召川,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤南缓,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后荧呐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體汉形,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年倍阐,在試婚紗的時候發(fā)現(xiàn)自己被綠了概疆。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡峰搪,死狀恐怖岔冀,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情概耻,我是刑警寧澤使套,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站鞠柄,受9級特大地震影響侦高,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜厌杜,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一奉呛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧夯尽,春花似錦侧馅、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至肺孤,卻和暖如春罗晕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背赠堵。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工小渊, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人茫叭。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓酬屉,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子呐萨,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容