質量監控-圖片減包

文章連接html

通過多個版本迭代,項目在release配置下的打包體積依舊輕鬆破百,應用體積過大致使的問題包括:python

  • 更長的構建時間,換個詞就是加班
  • TEXT段體積過大會致使審覈失敗
  • 用戶不肯意下載應用

一般來講,資源文件能在應用體積包中佔據1/3或者更多的體積,相比起代碼(5kb/千行)的平均佔用來講,對圖片進行減包是最直接高效的手段,對圖片資源的處理方式包括四種:算法

  1. 經過請求下載大圖
  2. 使用工具壓縮圖片
  3. 查找刪除重複圖片
  4. 查找複用類似圖片

考慮到因爲項目開發分工的問題,方式1須要推進落地,因此本文不討論這種處理方式。其餘三種都能經過編寫腳本實現自動化處理數組

圖片壓縮

圖片壓縮分爲有損壓縮無損壓縮兩類,有損壓縮放棄了一部分圖片的質量換取更高的壓縮比。網上主流的壓縮工具備tinypngpngquantImageAlphaImageOptim等,分別採用了一種或者多種壓縮技術完成圖片壓縮app

爲何png可以無損壓縮

因爲png格式的靈活性,同一張圖片可使用多種方式進行表示,不一樣方式佔用的大小不同。通常的軟件會採用效率更高的方式來表示圖片,因此這種狀況下png圖片存在巨大的優化空間。一般來講,從png文件中能去除的數據包括:工具

  • iTXttEXtzTXt這些能夠存儲任意文本的數據區段
  • iCCP數據區段存儲的profile等等
  • photoshop導出的png圖片存在大量的額外信息

png圖片有兩種類型的數據塊,一種是必不可缺的數據塊稱爲關鍵數據塊。另外一種叫作輔助數據塊png文件格式規範指定的輔助數據塊包括:測試

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

其中tEXtzTXt數據段中存在的數據包括:優化

關鍵字
Title 圖像名稱
Author 圖像做者
Description 圖像說明
Copyright 版權聲明
CreationTime 原圖創做時間
Software 創做圖像使用的軟件
Disclaimer 棄權
Warning 圖像內容警告
Source 創做圖像使用的設備
Comment 註釋信息

由上可見,輔助數據塊在png文件中可能佔據了極大的篇幅,正是這些數據塊構成了png的無損壓縮條件spa

tinypng

tinypng採用了一種稱做Quantization的壓縮技術,經過合併圖片中類似的顏色,將24bit的圖片文件壓縮成8bit圖片,同時去除圖片中沒必要要的元數據,圖片最高能達到70%以上的壓縮率。截止文章完成以前,tinypng僅提供了線上壓縮功能,暫未提供工具下載命令行

pngquant

根據官方介紹,pngquant24bit以上的圖片轉換成8bit的保留透明度通道的壓縮圖片,壓縮算法的壓縮比很是顯著,一般都能減小70%的大小。pngquant提供了命令行工具來完成解壓任務:

pngquant --quality=0-100 imagepath
複製代碼

命令行更多調試參數能夠在官網參閱

ImageAlpha

ImageAlpha是一個macOS系統下的有損圖片壓縮工具,內置了pngquantpngnq-s9等多個壓縮工具,多數狀況下經過將圖片降至8bit來獲取高壓縮比。因爲ImageAlpha的可視化界面沒法批量處理圖片,直接使用提供的命令工具能夠實現批量壓縮圖片:

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命令實現替換
  2. 有損壓縮會修改關鍵數據塊,可能致使壓縮圖片尺寸增大,須要過濾

在使用有損壓縮時須要注意單張png圖片是能夠被屢次壓縮的,但這會致使圖片的清晰度和色彩都受到影響,不建議對圖片超過一次以上的有損壓縮

ImageOptim

ImageOptim是介紹的四種工具中惟一的無損壓縮,它採用了包括去除exif信息從新排列像素存儲方式等手段實現圖片的壓縮。無損表明着一張圖片被ImageOptim壓縮後,後續沒法再次進行壓縮,同時它的壓縮比每每比不上其餘的有損壓縮方案,但最大程度上保證了圖片的原始清晰度和色彩

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的表現不盡人意

刪除重複圖片

一般來講,出現重複圖片的緣由包括模塊間需求開發沒有打通或是缺乏統一的圖片命名規範。經過圖片MD5摘要是識別重複圖片的最快方法,以python爲例,匹配重複圖片的代碼以下:

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查找存在一個以上路徑的數組而且輸出

尋找類似圖片

類似圖片在圖片內容、色彩上都十分的接近,多數時間能夠考慮複用這些圖片,但類似圖片的問題在於沒法經過MD5直接匹配。爲了確認兩個圖片是否類似,要使用簡單的一個數學公式來幫忙查找:

方差。在機率論和統計學中,一個隨機變量的方差描述的是它的離散程度,也就是該變量離其指望值的距離

舉個例子,甲同窗五次成績分別是65, 69, 81, 89, 96,乙同窗五次成績是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
複製代碼

平均值相同的狀況下,方差越大,說明數據偏離指望值的狀況越嚴重。方差越接近的兩個隨機變量,他們的變化就越加趨同,獲取方差代碼以下:

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

所以將圖片劃分紅連串的一維數據,以此計算出圖片的方差,經過方差匹配能夠實現一個簡單的圖片類似度判斷工具,實現前還要注意兩點:

  1. 圖片RGB色彩值會致使方差的計算變得複雜,因此轉成灰度圖能夠下降難度
  2. 不一樣尺寸須要縮放到相同尺寸進行計算

最終將圖片轉換成一維數據列表的代碼以下:

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)
複製代碼

將圖片轉成灰度圖後,仍然可能存在RGB色值不一樣但灰度值相同的狀況致使判斷失準,能夠考慮兩種方案提升算法的檢測準確率:

  1. 在不修改以灰度值計算方差的方案下,構建以列平均像素值爲單位的一維列表計算另外一個方差,兩個方差值一併作判斷
  2. 摒棄灰度值方差方案,每一行分別生成RGB三種色彩平均值的一維列表,計算出三個方差進行匹配檢測

效果

通過兩輪圖片減包處理後,整個項目資源產生的減包量約有20M,其中經過文中的三種手段產生的減包量在6.5M左右,總體上來看產出仍是比較可觀的

關注個人公衆號獲取更新信息
相關文章
相關標籤/搜索