一、概述
在上一篇文章當中,我們簡要介紹了PNG
的結構,以及PNG
壓縮的原理,對於壓縮的各個階段可以總結出一些優化的點:
- 減少原始影象的顏色種類
- 優化差分編碼器,使得經過差分編碼後的影象有儘可能多的零值和相同的值
- 優化
Deflate
的演算法,獲得更高的壓縮率 - 去除
PNG
檔案中不需要的資訊
今天,我們就來一起學習一些關於減小PNG
檔案大小的方法。
二、減小PNG
大小
2.1 使用PNG
優化工具
目前,已經有很多為開發者提供的PNG
優化工具,例如:
這些工具都針對PNG
壓縮的某一方面進行了優化,我們可以根據需要選擇適合的工具。
2.2 手動減少PNG
中的顏色的種類
在我們使用工具進行優化之前,可以先進行一些預處理,例如減少圖片當中顏色的種類。之所以這麼做是因為顏色的種類的個數會直接影響到整個PNG
壓縮過程的壓縮率:
- 在
Filter
階段,減少顏色的種類可以使得臨近畫素之間的區別變少。 - 因此,到了
Deflate
階段,就可以得到更多重複的值,那麼就會獲得更高的壓縮率。
減少圖片中的顏色的種類意味著有可能導致圖片的失真,因此這一過程更多的需要人為地去幹預,而不是通過工具來處理。
2.3 選擇正確的PNG
格式
在前面介紹PNG
的格式時,談到了PNG
可以分為8/24/32
三種型別,我們應當根據需要選擇正確的格式。
例如,如果圖片中沒有Alpha
通道,那麼就應當使用PNG 24
,而不是使用PNG 32
。類似,如果是灰度的圖片,那麼應當使用PNG 8
。
2.4 使用索引格式的PNG
如果圖片中的顏色種類小於256
,那麼就可以使用索引格式的PNG
。它會將這256
種顏色放到調色盤當中,而圖片中的每個畫素則轉換為調色盤中顏色的座標:
- 每個畫素所佔的位數就由
32
位減少到了8
位 - 減少了顏色的種類,這和我們在
2.2
中討論的優點相同。
因此,如果我們能夠把顏色減少到256
種以下,那麼PNG
的大小將會大大減少。
2.5 對於圖片中透明畫素點的處理
如果圖片中有完全透明的畫素點,我們根據PNG
的格式分為 索引PNG 和 普通PNG 兩部分來討論。
2.5.1 索引 PNG
如果使用的是索引PNG
,那麼只需要把"透明色"當作調色盤中的一個顏色就可以了。
2.5.2 普通 PNG
而如果我們使用的是普通PNG
,那麼就需要注意對於這些“不可見畫素點”的處理,例如下面這幅圖:
Alpha
通道,那麼效果是下面這樣:
造成它們大小之間差別的原因就在於:雖然左圖中的某些畫素點由於Alpha
通道的值為0
而變成透明的了,但是它們的RBG
通道仍然有不相同的值,因此在filer
和deflate
階段仍然要處理這些元素,並將它們壓縮。
因此,對於普通PNG
圖片,如果是ARGB
全綵的格式,對於那些Alpha
通道為0
的畫素點,說明它們是不可見的。那麼我們應當保證這些不可見畫素點的RGB
通道相同,這將能夠有效減少一行當中的顏色種類,從而獲得更好的壓縮效果。
2.6 採用 Vector Quantization 減少圖片中顏色的種類
如果影象中的顏色種類小於256
,那麼我們可以把它轉換為索引PNG
格式,而如果圖片原本的顏色大於256
種,那麼可以通過向量量化的方法來建立一個索引PNG
格式。
在向量量化的過程中,會把所有的畫素基於它們之間顏色的相似程度進行分組,一個組內畫素的顏色會比較接近。之後根據組內的所有顏色,計算出一箇中心點顏色,組內的所有顏色會被替換成為該中心點的顏色。
在上圖當中- 綠色的點表示原始的畫素顏色
- 藍色的範圍則表示一個分組
- 紅色的點則為根據該組中的顏色,所計算出的中心點顏色
向量量化會通過將相近顏色替換成同一種顏色的方法,來減少圖片中顏色的種類,因此有可能會使得圖片失真。
我們可以通過指定圖片中最多可以允許的顏色種類個數來控制量化的效果,pngquant 就是根據這一原理實現的。
三、AAPT
aapt
工具會對滿足一定條件的PNG
圖片進行優化,然而當它和其它工具結合起來的時候,反而有可能會使得經過aapt
處理後的圖片重新增大。
3.1 AAPT
對於PNG
圖片的優化
Android
的資原始檔是通過aapt(Android Asset Package Tool)
打包到Apk
檔案裡的,而在這一打包的過程當中,會對res/drawable
下的符合以下三個條件之一的圖片進行優化:
情況一:圖片中每個畫素點的RGB
三個通道的值相同
在這種情況下,PNG
會被轉換成為grayscale
格式,也就是每一個畫素僅佔8bit
。
情況二:圖片中每個畫素點的Alpha
通道的值都為1
,這表示該圖片是完全透明的。
情況三:圖片中總的顏色種類小於256
種,那麼會將該圖片轉換成為前面提到過的索引PNG
格式。
對於以上三種情況的處理,都是完全無損的處理方式,也就是經過aapt
處理後的圖片和原始的圖片質量相同。
3.2 使用aapt
的注意點
對於現代的壓縮演算法而言,它們都不可能做到迴圈壓縮。也就是說,如果你嘗試去壓縮一張已經被壓縮過的圖片,那麼有可能會使得該圖片變大,最好的情況也就是使得新的圖片和原始圖片大小相同。
因此,如果我們已經通過別的工具對png
圖片進行了壓縮操作,之後再通過aapt
進行優化,那麼有可能會使圖片增大10%
,如果需要解決這一問題,可以在build.gradle
中禁止除了.9.png
之外的圖片的aapt
的優化操作:
aaptOptions {
cruncherEnabled = false
}
複製程式碼
這樣,你就可以使用自己的png
優化工具進行優化,而不用擔心aapt
的優化操作會使得圖片進一步變大。
四、總結
在第二節中談到的這六點優化點,其實它們最核心的思想就是減少圖片中顏色的種類,然而減少顏色的種類就意味會導致圖片的失真,因此,如何選取這一平衡點是減少PNG
的難點所在。