質(zhì)量監(jiān)控-圖片減包

文章鏈接

經(jīng)過多個版本迭代,項目在release配置下的打包體積依舊輕松破百,應(yīng)用體積過大導(dǎo)致的問題包括:

  • 更長的構(gòu)建時間,換個詞就是加班
  • TEXT段體積過大會導(dǎo)致審核失敗
  • 用戶不愿意下載應(yīng)用

通常來說,資源文件能在應(yīng)用體積包中占據(jù)1/3或者更多的體積,相比起代碼(5kb/千行)的平均占用來說,對圖片進行減包是最直接高效的手段,對圖片資源的處理方式包括四種:

  1. 通過請求下載大圖
  2. 使用工具壓縮圖片
  3. 查找刪除重復(fù)圖片
  4. 查找復(fù)用相似圖片

考慮到由于項目開發(fā)分工的問題,方式1需要推動落地,所以本文不討論這種處理方式。其他三種都能通過編寫腳本實現(xiàn)自動化處理

圖片壓縮

圖片壓縮分為有損壓縮無損壓縮兩類,有損壓縮放棄了一部分圖片的質(zhì)量換取更高的壓縮比。網(wǎng)上主流的壓縮工具有tinypng、pngquantImageAlphaImageOptim等,分別采用了一種或者多種壓縮技術(shù)完成圖片壓縮

為什么png能夠無損壓縮

由于png格式的靈活性,同一張圖片可以使用多種方式進行表示,不同方式占用的大小不一樣。一般的軟件會采用效率更高的方式來表示圖片,所以這種情況下png圖片存在巨大的優(yōu)化空間。通常來說,從png文件中能去除的數(shù)據(jù)包括:

  • iTXt、tEXtzTXt這些可以存儲任意文本的數(shù)據(jù)區(qū)段
  • iCCP數(shù)據(jù)區(qū)段存儲的profile等等
  • photoshop導(dǎo)出的png圖片存在大量的額外信息

png圖片有兩種類型的數(shù)據(jù)塊,一種是必不可缺的數(shù)據(jù)塊稱為關(guān)鍵數(shù)據(jù)塊。另一種叫做輔助數(shù)據(jù)塊,png文件格式規(guī)范指定的輔助數(shù)據(jù)塊包括:

  • 背景顏色數(shù)據(jù)塊bKGD
  • 基色和白色數(shù)據(jù)塊cHRM
  • 圖像γ數(shù)據(jù)塊gAMA
  • 圖像直方圖數(shù)據(jù)塊hIST
  • 物理像素尺寸數(shù)據(jù)塊pHYs
  • 樣本有效位數(shù)據(jù)塊sBIT
  • 文本信息數(shù)據(jù)塊tEXt
  • 圖像最后修改時間數(shù)據(jù)塊tIME
  • 圖像透明數(shù)據(jù)塊tRNS
  • 壓縮文本數(shù)據(jù)塊zTXt

其中tEXtzTXt數(shù)據(jù)段中存在的數(shù)據(jù)包括:

關(guān)鍵字
Title 圖像名稱
Author 圖像作者
Description 圖像說明
Copyright 版權(quán)聲明
CreationTime 原圖創(chuàng)作時間
Software 創(chuàng)作圖像使用的軟件
Disclaimer 棄權(quán)
Warning 圖像內(nèi)容警告
Source 創(chuàng)作圖像使用的設(shè)備
Comment 注釋信息

由上可見,輔助數(shù)據(jù)塊在png文件中可能占據(jù)了極大的篇幅,正是這些數(shù)據(jù)塊構(gòu)成了png的無損壓縮條件

tinypng

tinypng采用了一種稱作Quantization的壓縮技術(shù),通過合并圖片中相似的顏色,將24bit的圖片文件壓縮成8bit圖片,同時去除圖片中不必要的元數(shù)據(jù),圖片最高能達(dá)到70%以上的壓縮率。截止文章完成之前,tinypng僅提供了線上壓縮功能,暫未提供工具下載

pngquant

根據(jù)官方介紹,pngquant24bit以上的圖片轉(zhuǎn)換成8bit的保留透明度通道的壓縮圖片,壓縮算法的壓縮比非常顯著,通常都能減少70%的大小。pngquant提供了命令行工具來完成解壓任務(wù):

pngquant --quality=0-100 imagepath

命令行更多調(diào)試參數(shù)可以在官網(wǎng)參閱

ImageAlpha

ImageAlpha是一個macOS系統(tǒng)下的有損圖片壓縮工具,內(nèi)置了pngquant、pngnq-s9等多個壓縮工具,多數(shù)情況下通過將圖片降至8bit來獲取高壓縮比。由于ImageAlpha的可視化界面無法批量處理圖片,直接使用提供的命令工具可以實現(xiàn)批量壓縮圖片:

for file in $(ls $1); do
    imagepath=$1"/"$file
    if [ -d imagepath ]
    then
        /// 路徑為文件夾
    else
        if [[ $file == *.png ]]
        then
            beforeSize=`ls -l $imagepath | awk '{print $5}'`
            /Applications/ImageAlpha.app/Contents/MacOS/pngquant $imagepath
            afterSize=`ls -l ${imagepath/.png/-fs8.png} | awk '{print $5}'`
            
            if [[ $afterSize -lt $beforeSize]]
            then
                mv ${imagepath/.png/-fs8.png} $imagepath
            fi
        fi
    fi
done

使用ImageAlpha需要注意兩點:

  1. 壓縮后的圖片命名會自動添加-fs8后綴,需要使用mv命令實現(xiàn)替換
  2. 有損壓縮會修改關(guān)鍵數(shù)據(jù)塊,可能導(dǎo)致壓縮圖片尺寸增大,需要過濾

在使用有損壓縮時需要注意單張png圖片是可以被多次壓縮的,但這會導(dǎo)致圖片的清晰度和色彩都受到影響,不建議對圖片超過一次以上的有損壓縮

ImageOptim

ImageOptim是介紹的四種工具中唯一的無損壓縮,它采用了包括去除exif信息、重新排列像素存儲方式等手段實現(xiàn)圖片的壓縮。無損代表著一張圖片被ImageOptim壓縮后,后續(xù)無法再次進行壓縮,同時它的壓縮比往往比不上其他的有損壓縮方案,但最大程度上保證了圖片的原始清晰度和色彩

for file in $(ls $1); do
    imagepath=$1"/"$file
    if [ -d imagepath ]
    then
        /// 路徑為文件夾
    else
        if [[ $file == *.png ]]
        then
            /Applications/ImageOptim.app/Contents/MacOS/ImageOptim $imagepath
        fi
    fi
done

ImageOptim同樣存在可視化的工具并且支持批量壓縮圖片

多方案對比

考慮到ImageAlpha幾乎都是使用pngquant作為壓縮工具,因此只列出三種壓縮工具的對比:

原始尺寸 壓縮工具 壓縮后尺寸 壓縮比
319.5KB tinypng 120.5KB 62%
319.5KB ImageAlpha-pngquant 395KB -24%
319.5KB ImageOptim 252KB 21%

測試圖片采用qq聊天截圖生成的pngtinypng壓縮率非常高,而pngquant的表現(xiàn)不盡人意

刪除重復(fù)圖片

通常來說,出現(xiàn)重復(fù)圖片的原因包括模塊間需求開發(fā)沒有打通或是缺少統(tǒng)一的圖片命名規(guī)范。通過圖片MD5摘要是識別重復(fù)圖片的最快方法,以python為例,匹配重復(fù)圖片的代碼如下:

md5list = {}
for file in files:
    if os.path.isdir(file.path):
        continue
        
    md5obj = hashlib.md5()
    fd = open(file.path, 'rb')
    while True:
        buff = fd.read(2048)
        if not buff:
            break
        md5obj.update(buff)
    fd.close()
    
    filemd5 = str(md5obj.hexdigest()).lower()
    if filemd5 in md5list:
        md5list[filemd5].add(file.path)
    else:
        md5list[filemd5] = set([file.path])
        
for key in md5list:
    list = md5list[key]
    if len(list) > 1:
        print (list)

在遍歷中以文件MD5字符串作為key,維護具備相同MD5的圖片路徑,最后遍歷這個map查找存在一個以上路徑的數(shù)組并且輸出

尋找相似圖片

相似圖片在圖片內(nèi)容、色彩上都十分的接近,多數(shù)時間可以考慮復(fù)用這些圖片,但相似圖片的問題在于無法通過MD5直接匹配。為了確認(rèn)兩個圖片是否相似,要使用簡單的一個數(shù)學(xué)公式來幫忙查找:

方差。在概率論和統(tǒng)計學(xué)中,一個隨機變量的方差描述的是它的離散程度,也就是該變量離其期望值的距離

舉個例子,甲同學(xué)五次成績分別是65, 69, 81, 89, 96,乙同學(xué)五次成績是82, 80, 77, 81, 80,兩個人平均成績都是80,但是引入方差公式計算:

甲: ((65-80)^2 + (69-80)^2 + (81-80)^2 + (89-80)^2 + (96-80)^2) / 5 = 136.8
乙: ((82-80)^2 + (80-80)^2 + (77-80)^2 + (81-80)^2 + (80-80)^2) / 5 = 2.8

平均值相同的情況下,方差越大,說明數(shù)據(jù)偏離期望值的情況越嚴(yán)重。方差越接近的兩個隨機變量,他們的變化就越加趨同,獲取方差代碼如下:

def getVariance(nums):
    variance = 0
    average = sum(nums) / len(nums)
    for num in nums:
        variance += (num - average) * (num - average) / len(nums)
    return variance

因此將圖片劃分成連串的一維數(shù)據(jù),以此計算出圖片的方差,通過方差匹配可以實現(xiàn)一個簡單的圖片相似度判斷工具,實現(xiàn)前還要注意兩點:

  1. 圖片RGB色彩值會導(dǎo)致方差的計算變得復(fù)雜,所以轉(zhuǎn)成灰度圖可以降低難度
  2. 不同尺寸需要縮放到相同尺寸進行計算

最終將圖片轉(zhuǎn)換成一維數(shù)據(jù)列表的代碼如下:

def getAverageList(img):
    commonlength = 30
    img = cv2.resize(img, (commonlength, commonlength), interpolation=cv2.INTER_CUBIC)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    res = []
    for idx in range(commonlength):
        average = sum(gray[idx]) / len(gray[idx])
        res.append(average)

將圖片轉(zhuǎn)成灰度圖后,仍然可能存在RGB色值不同但灰度值相同的情況導(dǎo)致判斷失準(zhǔn),可以考慮兩種方案提高算法的檢測準(zhǔn)確率:

  1. 在不修改以灰度值計算方差的方案下,構(gòu)建以列平均像素值為單位的一維列表計算另一個方差,兩個方差值一并做判斷
  2. 摒棄灰度值方差方案,每一行分別生成RG、B三種色彩平均值的一維列表,計算出三個方差進行匹配檢測

效果

經(jīng)過兩輪圖片減包處理后,整個項目資源產(chǎn)生的減包量約有20M,其中通過文中的三種手段產(chǎn)生的減包量在6.5M左右,整體上來看產(chǎn)出還是比較可觀的

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,702評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,143評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,553評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,620評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,416評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,940評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,024評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,170評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,709評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,597評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,291評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,029評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,407評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,663評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,403評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,746評論 2 370

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