最有效地使用PNG之續篇:Zopfli優化

原文作者:Jeff Atwood

2007年,我寫過一篇文章介紹使用PNGOUT來產生非常小的PNG圖片。我仍然經常提起這個話題,因爲8年後的今天,我隨便在網上看到的PNG圖片很有可能是未經優化的。

舉個例子,來看看pbfcomics.com上最近發佈的這張卡通圖:


把圖片從網站直接保存下來,我們發現,這幅漫畫是800 x 1412、32位的PNG圖像,文件大小爲671012字節。讓我們把它保存爲幾種不同的(無損)格式,來看一看這幅圖像要佔用多少空間:

  • BMP,24位                     3,388,854
  • BMP,8位                        1,130,678
  • GIF,8位,無抖動                147,290
  • GIF,8位,最大抖動           283,162
  • PNG,32位                      671,012

PNG表現不錯,因爲它像GIF一樣採用了壓縮算法;與GIF不同的是,你的圖像位深不會被限制在令人不快的8位(256色)。現在,我們用PNGOUT(點擊這裏下載)來處理一下,看看情況會怎樣?

  • 原始的PNG           671,012
  • PNGOUT               623,859                 7%

隨便從哪裏拿來一個PNG,用PNGOUT處理一下,你很可能獲得大約10%的文件大小縮減,也許還能更多。記住,這是無損壓縮!輸出的圖像質量是完全相同的。在網上傳輸的文件會變得更小;而且文件越小,解壓縮就越快。同學們,這是免費帶寬啊!還有比這更好的事嗎?

嗯,還真有……

2013年,谷歌推出了一種完全向後兼容新算法,他們稱之爲Zopfli:

Zopfli產生的輸出通常比zlib在最大壓縮比的情況下還要小3~8%。我們相信,Zopfli代表了Deflate壓縮算法的當前工藝水平。爲了可移植性,ZopfliC語言寫成。這個庫只支持壓縮;現有的軟件都能對它解壓縮。ZopfligzipZipPNGHTTP請求等使用的壓縮是位流兼容的。

非常抱歉,這個情況我瞭解得太晚了!還是讓我們來驗證一下他們的大膽狂言吧。拿上面這幅圖片來試驗,會發生什麼呢?

  • 原始的PNG           671,012
  • PNGOUT                       623,859                 7%
  • ZopfliPNG                     585,117   13%

看起來不錯啊!不過,那只是一張圖片。在discourse.org上,我們都喜歡用表情圖片。讓我們試試第一版表情Emoji One——那是一整套64 x 64、32位的842個PNG文件:

  • 原始的PNG           2,328,243
  • PNGOUT               1,969,973             15%
  • ZopfliPNG             1,698,322         27%

哇,此等好事,我豈能錯過!

在我的測試中,Zopfli處理過的PNG圖像總能比PNGOUT小3~8%,儘管PNGOUT已經非常強大了——這真是令人難以置信的成就!而且,任何使用標準gzip壓縮的資源都能從Zopfli獲益,比如jQuery:


我們再來看一看各種標準的壓縮測試:

測試素材

gzip -9

kzip

Zopfli

Alexa 10k

128mb

125mb

124mb

Calgary

1017kb

979kb

975kb

Canterbury

731kb

674kb

670kb

enwik8

36mb

35mb

35mb

 (奇怪得很,我之前都沒有聽說過kzip。事後證明,那又是我們的老朋友Ken Silverman的傑作。他也許使用了跟PNGOUT工具一樣的壓縮技巧。)

不過,有一個問題,因爲問題總是有的——它同時也慢80倍。不,我沒有搞錯。你也沒看錯!

  • gzip -9                        5.6s
  • 7zip mm=Deflate mx=9         128s
  • Kzip                     336s
  • Zopfli                          454s

Gzip壓縮一般比上表裏的速度還要快一點,因爲第9級是比較慢的:

 

時間

大小

gzip -1

11.5s

40.6%

gzip -2

12.0s

39.9%

gzip -3

13.7s

39.3%

gzip -4

15.1s

38.2%

gzip -5

18.4s

37.5%

gzip -6

24.5s

37.2%

gzip -7

29.4s

37.1%

gzip -8

45.5s

37.1%

gzip -9

66.9s

37.0%

你看吧,爲了獲得gzip -7和gzip -9之間那區區0.1%的壓縮比差異,是否值得花上雙倍的CPU時間呢?再說開一點,這也是爲什麼幾乎所有的壓縮工具的“極端”壓縮級別或模式通常都不靠譜。你從算法懸崖邊上快速掉了下去,因此你須待在曲線的中間或者最理想的位置,這常常就是缺省的壓縮級別。他們選擇那些缺省參數總是有原因的。

PNGOUT也不快,別急着用它;想象一下爲了壓縮一幅圖像或一個文件會慢80倍的(這還是好的情況!),這肯定讓人望而卻步。如果只是處理小圖片,你可能注意不到這個問題。但如果PNG比較大,你基本上可以出去吃一個三明治;或者如果你有一個多核CPU,處理完PNG的時間夠你吃4~16個三明治。這也是爲什麼使用Zopfli來處理用戶上傳的圖片可能是不明智的,因爲第一臺嘗試用Zopfli處理10k x 10k PNG圖片的服務器會掉入絕望的深淵。

然而,請記住解壓縮的速度是一樣的,並且絕對安全。這意味着你可能只想用Zopfli處理一些可以預處理的資源,也就是說,壓縮一次,然後用於幾百萬次的下載場景——這跟你的用戶上傳一些PNG圖片,不管你對這些圖片做何等的優化,可能最多也只會被瀏覽幾百次或幾千次的應用場景是不同的。

舉個例子吧。在discourse.org,我們有一個默認頭像渲染器,可以爲用戶基於他們的用戶名裏的第一個字母產生一個很好看的PNG格式的頭像,並且根據用戶名的哈希值選定一種顏色。噢,對了,我們還用了很漂亮的來自谷歌的開源字體Roboto。


我們在輸出頭像圖片的優化上花費了很多時間,因爲這些頭像會被使用幾百萬次。基於這些約束條件:

  • 10個數字
  • 26個字母
  • 大約256種顏色
  • 5種大小

預先把這些頭像生成出來就是45000個文件,也並不是毫無道理。我們還有一個所有discourse.org實例都能訪問的中央https CDN,需要的話也可以用於部署這些頭像圖片,這樣可以進一步減小負載、提高緩存命中率。

因爲這些圖像都是單色的,爲了節省空間,我把調色板降低到了8位(實際上用了128種顏色)。當然,我用PNGOUT優化處理了這些文件。它們差不多已經小到極限了。當我對這些頭像文件執行Zopfli時,我超級興奮,因爲我期望看到3~8%的文件大小縮減。不過,在處理命令執行完之後,我看到的是……分別省了1字節、5字節、2字節……我有點憂傷!

(沒錯,生成“有損的”PNG圖像在技術上是可行的,儘管有點奇怪,但我想那樣有悖於PNG的精神——它就是爲無損圖像而生的!如果你想要有損的圖像,那就用JPEG或其他格式吧。)

Zopfli的最大特色是,假設你不介意極高的CPU要求,它就是“用完就丟”的一次性優化步驟,你可以應用在任何地方,而且不會受到任何傷害。好吧,除了可能會燒掉很多空閒的CPU週期。

如果你參與的項目需要提供壓縮素材,仔細看一看Zopfli吧。它不是銀彈——聽了上述建議之後,你拿自己的文件來測試看看——但對於幹我們這行的人來說,它真正是給我們送來了免費帶寬啊!

發佈了58 篇原創文章 · 獲贊 1581 · 訪問量 156萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章