圖片壓縮知識梳理(2) 減小 PNG 大小

澤毛發表於2017-12-21

一、概述

在上一篇文章當中,我們簡要介紹了PNG的結構,以及PNG壓縮的原理,對於壓縮的各個階段可以總結出一些優化的點:

  • 減少原始影象的顏色種類
  • 優化差分編碼器,使得經過差分編碼後的影象有儘可能多的零值和相同的值
  • 優化Deflate的演算法,獲得更高的壓縮率
  • 去除PNG檔案中不需要的資訊

圖片壓縮知識梳理(2)   減小 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種顏色放到調色盤當中,而圖片中的每個畫素則轉換為調色盤中顏色的座標:

圖片壓縮知識梳理(2)   減小 PNG 大小
經過這一轉換之後:

  • 每個畫素所佔的位數就由32位減少到了8
  • 減少了顏色的種類,這和我們在2.2中討論的優點相同。

因此,如果我們能夠把顏色減少到256種以下,那麼PNG的大小將會大大減少。

2.5 對於圖片中透明畫素點的處理

如果圖片中有完全透明的畫素點,我們根據PNG的格式分為 索引PNG普通PNG 兩部分來討論。

2.5.1 索引 PNG

如果使用的是索引PNG,那麼只需要把"透明色"當作調色盤中的一個顏色就可以了。

2.5.2 普通 PNG

而如果我們使用的是普通PNG,那麼就需要注意對於這些“不可見畫素點”的處理,例如下面這幅圖:

圖片壓縮知識梳理(2)   減小 PNG 大小
表面上看來,這兩幅圖是一樣的,但是左圖卻要比右圖大,如果我們去掉Alpha通道,那麼效果是下面這樣:
圖片壓縮知識梳理(2)   減小 PNG 大小
造成它們大小之間差別的原因就在於:雖然左圖中的某些畫素點由於Alpha通道的值為0而變成透明的了,但是它們的RBG通道仍然有不相同的值,因此在filerdeflate階段仍然要處理這些元素,並將它們壓縮。

因此,對於普通PNG圖片,如果是ARGB全綵的格式,對於那些Alpha通道為0的畫素點,說明它們是不可見的。那麼我們應當保證這些不可見畫素點的RGB通道相同,這將能夠有效減少一行當中的顏色種類,從而獲得更好的壓縮效果。

2.6 採用 Vector Quantization 減少圖片中顏色的種類

如果影象中的顏色種類小於256,那麼我們可以把它轉換為索引PNG格式,而如果圖片原本的顏色大於256種,那麼可以通過向量量化的方法來建立一個索引PNG格式。

在向量量化的過程中,會把所有的畫素基於它們之間顏色的相似程度進行分組,一個組內畫素的顏色會比較接近。之後根據組內的所有顏色,計算出一箇中心點顏色,組內的所有顏色會被替換成為該中心點的顏色。

圖片壓縮知識梳理(2)   減小 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的難點所在。

五、參考文獻

Reducing PNG file Size

相關文章