android7.0之前瞬项,Bitmap.compress不支持哈夫曼壓縮算法蔗蹋,壓縮效率不高,因此引入libTurboJpeg庫來改善壓縮效率囱淋。
安卓底層使用Skia作為它的圖片處理引擎猪杭,通過對(duì)libjpeg進(jìn)行封裝,來進(jìn)行壓縮圖片妥衣。然而在libjpeg進(jìn)行壓縮圖片時(shí)皂吮,有一個(gè)參數(shù)戒傻,叫optimize_coding,默認(rèn)為FALSE涮较。關(guān)于這個(gè)參數(shù)稠鼻,官方的解釋是,如果設(shè)置為TRUE狂票,在壓縮過程中候齿,會(huì)計(jì)算哈夫曼表,這會(huì)顯著消耗空間和時(shí)間闺属。
然而這是對(duì)于十幾年前的設(shè)備而言的慌盯,現(xiàn)在的設(shè)備來做這個(gè)計(jì)算完全沒有壓力。因此掂器,只有在安卓7.0之后亚皂,才支持了哈夫曼算法。
開發(fā)時(shí)国瓮,把Java層的Bitmap傳遞到native層灭必,然后使用AndroidBitmap
API 取出圖像所有的argb數(shù)據(jù),接著可以舍棄a通道信息乃摹,只保留rgb信息到一個(gè)新的uint_8數(shù)組中禁漓,將這個(gè)數(shù)組作為參數(shù)傳入jpeg-turbo庫中,開啟哈夫曼編碼孵睬,就可以保存到一個(gè)新的路徑中播歼。
參考鏈接:http://www.reibang.com/p/32ff62bc33d5?from=timeline
1 哈夫曼樹
- 先統(tǒng)計(jì)各個(gè)元素(像素點(diǎn)顏色)出現(xiàn)的次數(shù),按照遞增排序掰读,得到一個(gè)數(shù)組秘狞,
- 取最小的兩個(gè),按照左小右大的原則蹈集,作為兩個(gè)葉子結(jié)點(diǎn)烁试,
- 計(jì)算兩個(gè)葉子結(jié)點(diǎn)的數(shù)值之和,放入數(shù)組中拢肆,同時(shí)刪除之前的兩個(gè)元素减响,再重新排序,
- 重復(fù)步驟2,3
- 數(shù)組為空時(shí)善榛,哈夫曼樹構(gòu)造完畢
- 從根節(jié)點(diǎn)開始,在路徑上左邊0右邊1的規(guī)則呻畸,得到所有元素節(jié)點(diǎn)的哈夫曼編碼
- 保存哈夫曼編碼的映射表移盆,用元素的哈夫曼編碼替換元素,就可以實(shí)現(xiàn)數(shù)據(jù)長(zhǎng)度的壓縮伤为。
- 解壓縮時(shí)咒循,根據(jù)哈夫曼編碼表逆推出原始數(shù)據(jù)据途。
我們來看看2,6叙甸,8颖医,9,3權(quán)值節(jié)點(diǎn)構(gòu)成哈夫曼樹的過程裆蒸。
初始時(shí)候各個(gè)節(jié)點(diǎn)獨(dú)立熔萧,先將其排序(這里使用優(yōu)先隊(duì)列),然后選兩個(gè)最小節(jié)點(diǎn)(拋出)生成一個(gè)新的節(jié)點(diǎn)僚祷,再將其加入優(yōu)先隊(duì)列中佛致,此次操作完成后優(yōu)先隊(duì)列中有5,6辙谜,8俺榆,9節(jié)點(diǎn)
重復(fù)上面操作,這次結(jié)束 隊(duì)列中有11装哆,8罐脊,9節(jié)點(diǎn)(排序后8,9蜕琴,11)
如果隊(duì)列為空萍桌,那么返回節(jié)點(diǎn),并且這個(gè)節(jié)點(diǎn)為整個(gè)哈夫曼樹根節(jié)點(diǎn)root奸绷。
否則繼續(xù)加入隊(duì)列進(jìn)行排序梗夸。重復(fù)上述操作,直到隊(duì)列為空号醉。
哈夫曼編碼
先統(tǒng)計(jì)字符出現(xiàn)的次數(shù)反症,然后將這個(gè)次數(shù)當(dāng)成權(quán)值按照上面介紹的方法構(gòu)造一棵哈夫曼樹,然后樹的根不存畔派,往左為0往右為1每個(gè)葉子節(jié)點(diǎn)得到的二進(jìn)制數(shù)字就是它的編碼铅碍,這樣頻率高的字符在上面更短在整個(gè)二進(jìn)制存儲(chǔ)中也更節(jié)省空間。