1. 程式人生 > >減少PNG圖片大小

減少PNG圖片大小

本篇文章翻譯自谷歌出的優化視訊裡面的光頭佬(Colt McAnlis),原文地址需翻牆, 以下正文:

我在谷歌工作的其中一個好處是可以瀏覽很多的Android程式,看看這些程式有哪些共同的地方可以優化。

後來我注意到一個可怕的趨勢:越來越臃腫的PNG檔案。

正如上一篇文章說的,PNG是一種很屌和可擴充套件的圖片格式,圖片質量高又支援透明度。因此,它成為這十幾年來開發者夢寐以求的透明圖片格式。

問題是PNG格式圖片(就像上一篇提到的增加2個畫素寬度就增加了兩倍大小)很容易臃腫。因此,可以想象的是,很多現在在使用的PNG圖片並沒有經過嚴格的處理。

對於減少PNG檔案大小,我有以下這些建議:

你應該使用一種優化工具

如果你理解PNG格式,有一些點是明顯可以優化的:

  • 去掉不需要的區塊(chunks)
  • 減少特殊顏色
  • 優化每一行的過濾演算法
  • 優化DEFLATE壓縮率

這幾點人們早就知道,PNG優化是一個老大難的問題了。20年前,Ken_Silverman就寫出了第一個流行的PNG優化工具,PNGOUT(這後來變成了毀滅公爵3D引擎的核心原始碼)。從那以後,又陸續的出現很多PNG優化工具,你隨便google一下就能搜出一大堆,比如:

不幸的是,上面這麼多工具裡,沒有一個工具能優化到所有的點,它們都只優化了其中一部分。所以這裡並沒有最好的工具,你只要把時間花在分析哪種工具對你最有用就好,其他的不去管它。

不過,對我個人而言上面列表裡我最喜歡的工具是zopfliPNG。它提供了一個更有效和更強大層級的壓縮器,可以更好的匹配你的資料,從而減少你的PNG檔案大小。它可以減少PNG檔案5%大小而不影響圖片的任何質量,雖然有點少,但不要忘了還可以繼續給用其他壓縮器繼續壓縮。

很重要的一點是,如果有很多資料經過你的應用程式,你應該在資料傳輸過程(上傳/釋出圖片)中就對PNG進行優化,不要讓大圖四處流動。

減少顏色

如果上面的工具都不好用,而你又想在使用上面這些工具前自己先手動處理一下圖片,這時你需要注意的是:儘管你自己可以手動做很多處理,但我還是建議你應該只專注在減少你圖片裡特殊顏色的數量上,因為這會直接影響到所有其它層級的壓縮效果,其他的事交給工具去做。

在PNG壓縮過程中的過濾(filtering)階段,壓縮的強度是取決於相鄰畫素色的差異程式。例如:減少特殊顏色的數量會減少相鄰畫素色的差異程式,繼而減小過濾出來後的值的大小。因此,到了DEFLATE壓縮階段就會得到更多重複的值,當然就能壓縮得更小。

值得注意的是,減少了特殊顏色的數量,到了對圖片做有損處理階段會更有效果。

由於工具並沒有人類對於圖片質量的感知能力,在一些情況,只要有一點點小差錯就可能使整張圖片糊掉。這就是為什麼這道程式你應該自己處理的原因。不過,如果你處理得當的話,使用者應該不會注意到,同時你又節省了一大堆空間。

選擇正確的畫素格式

這本來可以不說的,但我見到一些APK使我不得不說:

你應該確保使用正確的PNG畫素格式

例如,如果你的圖片沒有透明通道,但你又使用了RGBA 32bpp(bit per pixel 每畫素32位)畫素格式,那麼你的圖片就浪費了整整1/4的空間,這種情況你就應該使用24bpp的真彩色(RGB)或者用JPG格式。又或如果你的圖片只包含灰度資料,那你應該只使用8bpp的GrayScale格式來儲存圖片。

這是最基本的事,不要因為使用了錯誤的畫素格式而使PNG檔案的臃腫。

索引圖片,一級棒!!!

讓我們繼續,顏色的減少應該始終從嘗試優化你的顏色數開始,那麼就可以把圖片定義為索引格式(INDEXED FORMAT)了。索引顏色的原理是,只選擇使用最佳的256種顏色,然後把你的圖片的所有畫素都替換成這256種顏色。想想看從原來的1600萬種顏色(24bpp)減少到256種,這會減少多少空間呀。

這有一張例圖,右邊是索引格式的圖片:

左是RGB格式的PNG圖片,右是索引格式的PNG圖片

上面這張Google塗鴉是從Photoshop的”save for web”選項匯出來的,它的圖片格式被設定為PNG8(8bpp),它的顏色都來自下面的調色盤:

這是索引PNG圖片的顏色調色盤

把真彩圖轉成索引圖,你就得把每一個特殊的顏色都替換成調色盤裡的顏色,這樣做能把佔32位的一個畫素減少到8位,這一步就減少了很多空間。

這個模式還會在過濾和壓縮階段帶來進一步的節省:

  1. 由於特殊顏色已經減少,這意味著相鄰的顏色有更高概率是同樣的顏色
  2. 又由於相鄰同樣畫素顏色數量增加,在過濾階段會產生更多重複的值,在使用LZ77的DEFLAFT演算法的壓縮效果會更好

如果你的圖片可以用索引圖替代,這種方法將大大的減少圖片的大小,所以花時間檢查下你大部分圖片可否被轉換成索引圖是值得的。

優化全透明的畫素

索引模式其中一個不錯的功能是 : 你可以在調色盤中表示特定的顏色,以作為”透明”。當RGBA格式的PNG圖片被解析進記憶體裡,透明畫素會被相應的處理。有趣的是透明通道完全是二進位制的,它指定一個畫素是否可見。

一張具有多個確定透明度值的索引圖

這種”穿透”型的透明圖片會被更有效的壓縮,通常來說,如果一張圖片有大面積的透明背景,那麼它會有很多相似的畫素,這樣更有利於壓縮。

但這種情況只在索引模式下有效。在那些你要用這種”穿透”型透明圖片,但你的PNG圖片又得是RGB模式,這種情況很容易犯一種錯誤,就是沒有把看不見的畫素去掉。想一下下面這個例子,兩張圖片都支援透明通道和真彩色,但右邊那張明顯小很多。

兩張圖片看起來一樣,但大小差別卻很大

造成這兩張圖片大小不同的原因也很明顯:就你看有沒有去掉透明通道:

兩張圖片在螢幕上看起來一模一樣,但左邊圖片裡的那些會被透明掉的顏色資訊沒有去掉。儘管使用者看不見這些資訊,壓縮工具也必須對這些透明的顏色做處理。

儘管有透明通道的圖片只被渲染其中一部分,但對於RGB層來說那些畫素資料還在那(只是沒渲染而已),這就意味著在過濾和壓縮階段還必須處理所有這些看不見的資料。

相反,如果你知道哪些畫素不會顯示,並確保它們是均勻的,那麼我們就可以把那些看不見的畫素替換成相同值。這樣做會產生更多單一顏色的畫素行,即會提高壓縮率。

這是一個讓你在RGB模式下使用”穿透”型透明但不至於產生大圖的小技巧。

有損預處理

索引模式的PNG圖片是屌,但是,僅僅256種顏色並不能準確的顯示每一張圖片,有些可能需要257,310,512,912種顏色才能讓圖片看起來像樣。由於索引模式只支援256種顏色,所以這些圖片都必須被定義成RGB(24bpp),儘管只使用了其中一部分顏色。

幸運的是,你可以手動的減少顏色數量類似用索引方式。

這種建立一張索引圖片的過程,叫做向量化可能更好一點。這是一個多維數的四捨五入過程,更直接的說是你圖片的所有顏色會根據它們的相似性而分組。在給定的一個組裡,組內的所有顏色會被替換成”中心點”那個值,這會最大限度減少誤差。(類似沃羅諾伊圖)

下面這張2維圖片展示了這個過程是怎麼設值的。

在這個2維空間綠色的點代表所有輸入資料。藍色線圈起來的區域代表相似顏色組,紅色點是每組的代表色。向量化的過程是把每個組裡的畫素都替換成組的代表色。

對一張圖片使用向量化替換會很有效的減少特殊顏色的數量,把它們替換成視覺上”相似”的一種顏色。

還有一個方法讓你定義一張圖片最大顏色數。

例如,下圖左邊是一張24位每個體畫素的鸚鵡圖,而右圖只有16種顏色數可用。

鸚鵡頭

你可以即刻的看出來右邊的鸚鵡嚴重失真,所有過渡色都被替換掉,看起來一坨一坨,很顯然這張圖片需要多於16種顏色才不失真。

向量化圖片的這個過程,可以讓你更清楚圖片到底需要多少種顏色,也可以幫你減少圖片大小。不過,除了pngquant,我還不知道有哪個工具可以讓你手動指定具體的顏色數。

所以,如果這個工具你用得不爽,你也可以搞一個自己的向量化工具來做這事。

協作

總結一下,你應該是用一個工具把圖片儘可能的壓縮到最小,這些工具的作者已經花了很多時間在解決這些問題上,站在巨人的肩膀上你會工作得更快。不過呢,在使用這些工具壓縮前還是有很多工作你可以親自去處理的。

So,加油做出更小的PNG圖片吧!

PS:由於文人水平有限,如有翻譯得不好的地方,請留言討論。
PPS:CSDN的圖片註釋沒顯示出來,可以到我簡書的部落格看。