PNG圖片壓縮對比分析

背景與現狀

隨着版本的迭代,業務的增加,QQ音樂apk的大小已經超過25M,其中res目錄佔用的大小超過5.5M,所以提出了對安裝包進行瘦身的技術需求。業務的增加導致圖片越來越多,通過分析可以知道PNG格式圖片是項目中數量最多的圖片,關於PNG圖片的介紹可以參考:PNG文件格式詳解。爲了實現減包任務,對圖片進行壓縮是很重要的一部分。

爲了實現PNG圖片的壓縮,之前的處理方式是先在本地進行壓縮,然後提交到SVN,再打包發佈。一般採用在線壓縮工具處理,將res目錄下的PNG圖片批量手動處理,這種方式容易出現的問題是:

1) 爲了追求高的壓縮率,容易出現一張圖片重複壓縮的情況,導致圖片嚴重失真;

2) 不能自定義參數開發,無法滿足開發需求;

3) 壓縮效率比較低,每次發佈時都需要人爲進行一次圖片的壓縮。

壓縮工具及原理分析

tinypng

1)原理介紹

根據官網https://tinypng.com/介紹,主要是使用Quantization的技術,通過合併圖片中相似的顏色,通過將 24 位的 PNG 圖片壓縮成小得多的 8 位色值的圖片,並且去掉了圖片中不必要的 metadata(元數據,從 Photoshop 等工具中導出的圖片都會帶有此類信息),這種方式幾乎能完美支持原圖片的透明度。有部分文檔指出tinypng同時採用了pngquant、optipng、advpng幾種腳本。圖片的壓縮率能達到50%以上。

2)在線API

提供在線API供開發者二次開發,支持Ruby、PHP、Node.js、Python、Java等語言,其中Java庫源碼地址爲tinify-java。但是,在線api需要申請api-key,並且對調用次數有限制,可以免費調用500次。在公司內部的開發網環境無法正常運行,無法通過API在線調用接口。

pngquant

根據官網https://pngquant.org/介紹,pngquant是國外的一個有損的PNG壓縮開源庫,提供了命令行形式和源碼庫形式。將24位或32位的RGBA PNG圖轉換成8位PNG圖並保留透明度通道。通過這個庫的轉化可以顯著減少png文件大小(通常減少70%)。生成的圖片文件可以兼容所有現代web瀏覽器,在IE6下比24-bit PNGs也有更好的表現。它的特性有:

1)結合Vector_quantization算法生成高質量的色彩範圍;

2)獨特的自適應抖動算法,比標準的FloydSteinberg算法具有更強的抗噪性;

3)易與集成,提供了shell腳本,圖形化界面,服務端庫,PS插件;

4)具有快速模式,用於處理大批圖片。源碼庫地址爲pngquant

其他PNG壓縮工具

網上流行的PNG壓縮工具主要有ImageAlpha、ImageOptim、pngcrush、optipng、pngout、pngnq、advpng等。他們的對比可以參考以下文章;

1)John Wong的PNG圖片極限壓縮,介紹了ImageAlpha和ImageOptim兩種壓縮方法;

2)圖片優化的那些工具,介紹了pngcrush、optipng、pngout、pngnq等。

各壓縮工具的對比表格如下:


根據資料顯示,tinypng、pngquant、ImageAlpha、pngnq都是有損壓縮,基本採用的都是quantization算法,將24位的PNG圖片轉換爲8位的PNG圖片,減少圖片的顏色數;pngcrush、optipng、pngout、advpng都是無損壓縮,採用的都是基於LZ/Huffman的DEFLATE算法,減少圖片IDAT chunk區域的數據。一般有損壓縮的壓縮率會大大高於無損壓縮。

壓縮對比

一些流行的PNG壓縮工具的壓縮率對比可以參照:常用PNG壓縮工具壓縮率對比。在參考以上文章的基礎上,本文主要針對pngquant和tinypng做出了對比。

1.單個圖片壓縮對比

選取QQ音樂Android項目中佔用空間最大的幾個PNG圖片進行壓縮效果的對比,通過pngquant.exe腳本以及tinypng網站分別進行單個壓縮,壓縮率如下圖所示:(pngquant使用默認壓縮品質)

從表格中可以知道,tinypng的壓縮率大概比pngquant的壓縮率會高10%左右。其中pngquant壓縮過程會出現比原來圖片大的情況,所以在實際利用腳本壓縮過程中需要對壓縮後的圖片和原來圖片大小進行對比,如果出現變大的情況應該捨棄。

2.批量圖片壓縮對比

由於項目中存在大量的PNG格式圖片,所以不可能單個單個進行壓縮,需要通過批量壓縮來進行,tinypng的批量壓縮目前只能是在官網進行(由於在線API的開發會有圖片數量受限以及開發網環境受限等),而pngquant的批量壓縮可以通過自己完全自定義開發,調用壓縮腳本進行壓縮,在官網上可以下載windows和linux版本下的運行文件。

選取項目中大小4KB以上的106個PNG圖片進行壓縮實現,效果對比如下:(pngquant使用默認壓縮品質)

從表格中可以知道,tinypng工具由於是採用網站在線壓縮的方式,所以批量上傳過程中容易出現上傳不成功等錯誤,而pngquant採用的是本地腳本壓縮,所以這個問題可以有效避免。由於tinypng採用了多種壓縮算法,壓縮效果會好於pngquant,大概可以多壓縮12%左右,不過由於是有損壓縮,所以在追求儘可能增加壓縮比率的同時也應該考慮壓縮後圖片的顯示效果。

3.本地運行腳本對drawable目錄壓縮

使用pngquant腳本壓縮資源目錄res下的drawable、drawable-hdpi、drawable-ldpi、drawable-mdpi、drawable-xhdpi、drawable-xhdpi-v21、drawable-xxhdpi、drawable-xxxhpi等8個文件夾,在多線程的情況下,共耗時17s940ms。主線48322版本的資源目錄採用各種壓縮品質(通過設置—quality參數實現)進行壓縮,對比效果如下圖,綜合考慮壓縮率和壓縮後效果,最終採用品質爲90的壓縮方案,可以減包1.97MB。


4.結論

在綜合比較tinypng和pngquant的基礎上,項目最終考慮使用pngquant來對PNG圖片進行批量壓縮,主要考慮有:

1)雖然在pngquant採用默認壓縮品質的情況下壓縮率會低於tinypng,但是tinypng是在線壓縮工具,不好自定義控制與維護,tinypng壓縮後的顯示效果還有待進一步驗證;

2)同時,pngquant腳本可以自定義壓縮品質,採用壓縮品質更低(比如90)的情況下,壓縮率會高於tinypng,而且pngquant是開源的,容易維護,風險可控。

使用pngquant的壓縮流程

1.gradle編譯

項目PNG圖片壓縮類存放在工程目錄buildSrc下,是使用groovy開發的ImageCompressionTask.groovy(由haodongyuan開發),在build.gradle或build_server.gradle中通過以下方式引用:(手動運行compressImages任務即可實現壓縮處理,其中quality表示壓縮品質,compress表示是否開啓壓縮)

import com.tencent.qqmusic.ImageCompressionTask

task compressImages(type: ImageCompressionTask) {
 multiThread = true
 verbose = false
 backupRoot = new File('res-backup')
 sourceRoot = rootDir
 quality = 90
 compress = true
 folders = [
   "res/drawable",
   "res/drawable-hdpi",
   "res/drawable-ldpi",
   "res/drawable-mdpi",
   "res/drawable-xhdpi",
   "res/drawable-xhdpi-v21",
   "res/drawable-xxhdpi",
   "res/drawable-xxxhdpi"
]
}

2.RDM自動化編譯

如果要做成gradle自動化編譯,除了在gradle中加入上面代碼外,還需要使用下面語句做成任務依賴,需要在編譯apk之前執行壓縮任務:

copyNativeLibs.dependsOn compressImages

並且同時關閉Android編譯工具AAPT自帶的壓縮效果:

aaptOptions {
    cruncherEnabled = false
}

pngquant的Linux版本的運行要依賴一些是so文件,需要在build.sh文件中加入依賴的so庫:

#加入動態加載pngquant壓縮的依賴so庫
export LD_LIBRARY_PATH=$(cd `dirname $0`; pwd)/scripts/Tools/pngquanti/linux/lib
ln -s $(cd `dirname $0`; pwd)/scripts/Tools/pngquanti/linux/lib/liblcms2.so.2.0.8 $(cd `dirname $0`; pwd)/scripts/Tools/pngquanti/linux/lib/liblcms2.so.2
ln -s $(cd `dirname $0`; pwd)/scripts/Tools/pngquanti/linux/lib/ld-2.23.so $(cd `dirname $0`; pwd)/scripts/Tools/pngquanti/linux/lib/ld-linux-x86-64.so.2
ln -s $(cd `dirname $0`; pwd)/scripts/Tools/pngquanti/linux/lib/libpng15.so.15.27.0 $(cd `dirname $0`; pwd)/scripts/Tools/pngquanti/linux/lib/libpng15.so.15

自動化編譯過程壓縮腳本運行的流程爲:


從壓縮流程圖中可以知道,在項目資源目錄下PNG圖片數據過多時,默認應該採用多線程執行壓縮腳本,爲了避免出現重複壓縮的情況,在進行壓縮之前需要讀取圖片的壓縮信息,壓縮過的不再壓縮,同時,壓縮完成後,需要對壓縮處理過的圖片寫入壓縮信息,方便下一次讀取。由於pngquant腳本的特殊性,需要判斷壓縮後文件是否大於原始文件,大於則需要刪除並記錄。

3.優勢

使用pngquant自動壓縮的優勢主要有三點:

1)選擇pngquant做爲png圖片壓縮腳本,可以在不影響圖片顯示效果的基礎上最大化壓縮(採用壓縮品質90);

2)同時通過groovy腳本對圖片進行批量壓縮處理與加入額外壓縮信息,可以提高壓縮效率並防止重複壓縮;

3)做成RDM自動化壓縮後,可以有效減少開發人員的工作量,方便後期維護。

JPG的壓縮

JPG的壓縮途經有,公司內部的優圖工具:優圖JPG壓縮;在線jpg壓縮工具tinyjpg:https://tinyjpg.com/;腳本工具jpegtran:http://jpegclub.org/jpegtran/等。由於優圖工具是無損壓縮,有專業的優圖團隊進行維護,並且壓縮率可以達到20%以上,而tinyjpg是有損壓縮,會出現重複壓縮的情況且不方便維護,所以項目優先考慮採用優圖工具進行壓縮。

選取工程res目錄下的49個JPG文件進行壓縮對比,可以減少0.23MB,效果如下:

第三方jar包中的圖片壓縮

通過觀察apk包會發現,assets目錄下會存在一些新生成的圖片目錄,包括common、drawable、images、Recommend目錄,通過分析發現,這些png圖片來自項目引用的第三方jar包,其中TVK_MediaPlayer-V3.6.0.10721.jar會產生common、Recommend目錄,videoad-sdk-1.7.2-20160527.jar會產生images目錄,weiboSDKCore_3.1.2.jar會產生drawable相關目錄。可以知道,這部分圖片的優化空間有限,重點需要對TVK_MediaPlayer、videoad-sdk、weiboSDKCore三個jar包手動進行PNG圖片壓縮。總共可以減少41KB。

部分jar包PNG圖片壓縮減少的大小對比:


總結

本次工程圖片壓縮過程,主要學習了PNG圖片的主要壓縮腳本(tinypng/pngquant/pngout)以及JPG圖片的壓縮工具(優圖/tinyjpg),經過對比最終選擇pngquant與優圖作爲工程PNG和JPG圖片的壓縮工具。爲了實現PNG圖片壓縮的自動化管理,將pngquant腳本集成到RDM編譯,主要遇到的問題有:

1)groovy腳本執行Linux命令,Linux環境下運行bin文件,需要首先使用chmod賦予權限;

2)gradle的編譯順序問題,根據編譯過程的依賴鏈關係,需要將compressImages任務放到最開始;

3)pngquant的運行需要依賴一些so庫,所以需要通過重設“LD_LIBRARY_PATH”來定向加載so庫,同時,通過ln命令來設置so庫的軟連接關係;

4)路徑識別問題,一開始總是無法找到圖片路徑,後面發現是在壓縮腳本路徑引用的時候多加了雙引號(“”),導致在RDM平臺無法識別;

5)RDM自動化編譯時間增加的問題,由於res目錄下的JPG圖片和第三方jar包的PNG圖片都是本地手動壓縮處理的,不用考慮時間問題。res目錄下的PNG圖片是在RDM平臺自動壓縮處理的,要考慮時間成本,如下圖所示,加上壓縮腳本,大概會多耗時26秒左右。


通過本次圖片壓縮優化,可以達到以下幾個目的:

1)res目錄下的PNG可以減少1.97MB,PNG的減包效果如下圖,res目錄下的JPG圖片可以減少200KB,第三方jar包(assets)目錄的PNG圖片大小可以減少40KB。總共可以減包2.22MB

PNG壓縮前:

PNG壓縮後:

2)實現PNG圖片自動化壓縮處理,大大提高了開發效率,方便維護管理;

3)通過groovy腳本可以實現自定義壓縮品質與寫入壓縮信息,有效控制壓縮率和智能判斷,避免二次壓縮的出現。

參考

[1]http://blog.csdn.net/bisword/article/details/2777121

[2]https://tinypng.com/

[3]https://pngquant.org/

[4]http://www.jianshu.com/p/a721fbaa62ab

[5]http://johnwong.github.io/showcase/2015/02/19/png-compress.html

[6]http://ued.ctrip.com/blog/image-optimization-tools.html

[7]http://advsys.net/ken/utils.htm

[8]http://jamiemason.github.io/ImageOptim-CLI/comparison/png/photoshop/desc/

[9]https://my.oschina.net/shede333/blog/373780

[10]https://tinyjpg.com/

[11]https://www.oschina.net/translate/4-free-tools-to-optimize-and-compress-png-images-without-loosing-quality

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章