我們是如何記錄圖片的?
作為 Web 開發(fā)者,我們?nèi)粘P枰c各式各樣的圖片格式打交道,以至于有些知識幾乎已經(jīng)成為常識,比如我們應該都知道 PNG 可以支持透明度,jpg 可以壓縮到較低的質(zhì)量,而 gif 則可以顯示動圖……但是,你知道這些不同的圖片格式是如何產(chǎn)生的、并且演進至今的嗎?
起源?
最早的圖片格式如今已經(jīng)不可考證,但可以肯定的是,從計算機誕生之初,數(shù)字圖片就已經(jīng)存在了,正如早在沒有計算機時我們就創(chuàng)造了“楊輝三角”這樣的圖形。不過在互聯(lián)網(wǎng)誕生之后,由于信息(biao qing bao)傳遞的效率飛速提升,我們才有了更多機會看到數(shù)字圖片格式的發(fā)展。
1982 年,隨著網(wǎng)絡社交的開始,互聯(lián)網(wǎng)上開始出現(xiàn)了一種被稱為 ASCII Art 的藝術(shù)形式。人們開始使用一些字符來構(gòu)成一些復雜的圖形:
██████╗ ██████╗ ███╗ ███╗███╗ ███╗ █████╗ ███████╗
██╔════╝██╔═══██╗████╗ ████║████╗ ████║██╔══██╗██╔════╝
██║ ██║ ██║██╔████╔██║██╔████╔██║███████║███████╗
██║ ██║ ██║██║╚██╔╝██║██║╚██╔╝██║██╔══██║╚════██║
╚██████╗╚██████╔╝██║ ╚═╝ ██║██║ ╚═╝ ██║██║ ██║███████║
╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝
這實際上就是一種非常直觀的計算機圖片存儲方式:在上面這張圖里,我們可以把每一個單元格看成是顯示屏幕的一個光學元件。當這些光學元件展示一張圖片時,有些可能不發(fā)光(對應上面的空白部分),有些可能具有不同的顏色(對應上面的 █ 或者 ║)。通過這種方式,我們用一種非常符合計算機直覺的“編碼”保存了這張圖片——這里我不妨將其命名為 「Commas 編碼」 吧。
通過 Commas 編碼,「我們只需要保存一個二維數(shù)組,對應圖中的不同位置,在數(shù)組的每一項記錄對應的字符(顏色)」。這就是我們現(xiàn)在看到的絕大多數(shù)圖片的保存方式:「點陣圖」,或者用術(shù)語來描述:「位圖」。
如果使用我們上面描述的方式保存這張圖片,它的存儲效率是怎樣的呢?
沒錯,實際上上面的代碼塊就是圖片文件本身!因為我們用了 Unicode 而非二進制的方式保存,它的像素數(shù)是 55*6,每一個像素需要用一個 Unicode 字符存儲。假設我們使用 UCS-2 編碼,則這張圖片使用我們的編碼方式需要 「660B」 的存儲空間。
PNM: 色彩與二進制?
在真實的計算機世界里,真的有像 Commas 編碼這種圖片格式嗎?事實上還真有。在萬維網(wǎng)還沒有誕生的年代,就已經(jīng)有了一種用于電子郵件傳輸?shù)膱D片格式,它叫做 PBM(Portable BitMap)。在現(xiàn)在,它使用 .pbm? 后綴和 image/x?portable?bitmap MIME 類型。
PBM 是一種單色圖片,這意味著它只有黑色和白色兩種顏色,在游戲美術(shù)中這通常被稱為 1-bit。在存儲時,我們可以使用 0 和 1 代表黑白兩種顏色。比如上面的 COMMAS 圖片,如果用 PBM 它的編碼方式如下:
P1
# This is comment
55 6
0 1 1 1 1 1 1 0 0 1 1 1 1 1 1 0 0 1 1 1 0 0 0 0 1 1 1 0 1 1 1 0 0 0 0 1 1 1 0 0 1 1 1 1 1 0 0 1 1 1 1 1 1 1 0
1 1 0 0 0 0 0 0 1 1 0 0 0 0 1 1 0 1 1 1 1 0 0 1 1 1 1 0 1 1 1 1 0 0 1 1 1 1 0 1 1 0 0 0 1 1 0 1 1 0 0 0 0 0 0
1 1 0 0 0 0 0 0 1 1 0 0 0 0 1 1 0 1 1 0 1 1 1 1 0 1 1 0 1 1 0 1 1 1 1 0 1 1 0 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 0
1 1 0 0 0 0 0 0 1 1 0 0 0 0 1 1 0 1 1 0 0 1 1 0 0 1 1 0 1 1 0 0 1 1 0 0 1 1 0 1 1 0 0 0 1 1 0 0 0 0 0 0 1 1 0
0 1 1 1 1 1 1 0 0 1 1 1 1 1 1 0 0 1 1 0 0 0 0 0 0 1 1 0 1 1 0 0 0 0 0 0 1 1 0 1 1 0 0 0 1 1 0 1 1 1 1 1 1 1 0
你可以將它保存為一個 `.pbm` 文件,并利用 MacOS 的圖片查看器查看它。
比起 Commas 編碼,PBM 失去了表達顏色的能力,但多了注釋結(jié)構(gòu)。不過單色顯然是無法滿足我們發(fā)送表情包的需要的,至少連黑白電視也是支持不同亮度的黑色的。為了讓 PBM 支持灰度,我們可以將 0 和 1 擴展為 0-255,這就是 PGM;更進一步地,我們還可以用 255 255 255 來將每個像素擴展為真彩色,也就是我們熟悉的 RGB 編碼,這就是 PPM。在 PBM 開頭的 P1 就起到了描述編碼的作用,P1 P2 和 P3 分別代表 PBM、PGM 和 PPM 三種格式,他們被統(tǒng)稱為 PNM。
現(xiàn)在,我們來考慮一下存儲空間吧。PBM 使用 ASCII 明文存儲,上面的圖片文本長度是 575,因此它占用 575B。當然我們還可以進一步壓縮,在去除注釋后,它的長度是 557B,但也僅限于此了;如果使用支持色彩的 PPM,每個像素可能要占 11 個文本長度,于是一張簡單的 55*6 的 COMMAS Logo 圖需要使用 「3,857B」 來保存!
有什么方法可以進一步壓縮圖片呢?聰明的你一定可以想到,我們可以使用二進制。PBM 的編碼可以使用 P4-P6 表示它使用二進制保存。于是我們可以用兩個字節(jié)表示編碼,兩個 Int32 也就是 8 個字節(jié)表示尺寸,后面的 330 個像素可以將每一個真彩色轉(zhuǎn)換成 3 個字節(jié)的色彩空間,這樣我們一共只需要 1,000B 就能夠存儲上面的 COMMAS Logo 圖了,而且還是支持真彩色的!
GIF: 空間與編碼壓縮?
在 20 世紀 80 年代,1K 的尺寸依然是無法想象的 —— 只是一張小小的 Logo,竟然比 Commas 的使用文檔還要大!有什么辦法能夠繼續(xù)優(yōu)化尺寸呢?
在那個年代,在我們甚至很難購買到支持真彩色的顯示屏的時候,使用真彩色編碼圖片無疑是一種浪費。我們也可以縮小色彩空間來針對每個像素減少其占用的空間。在 1-bit 之外,同樣有一種常見于像素游戲的畫風叫做 8-bit,意思就是用 8bit 也就是 1 個字節(jié)來保存顏色,我們只需要將顏色限制為 256 種,就能將用于色彩的存儲進一步壓縮。假設我們將 PPM 的 Commas Logo 縮小到 256 種顏色的范圍,每一個像素就能用 1 個字節(jié)來保存了,這樣上面的 1,000B 的 COMMAS Logo 圖就能壓縮到 340B,甚至比文本格式的 PBM 圖還要?。?/p>
玻璃的光影只需要使用四種顏色即可完成。
另一方面,學過數(shù)據(jù)結(jié)構(gòu)的同學能夠想到一種常見的壓縮方式:「霍夫曼編碼」。簡單地來說就是我們可以記錄一份字典,用更小的比特序列來記錄更常出現(xiàn)的字符。比如 Commas,如果用 ASCII 的話,每一個字母都要 1 個字節(jié)也就是 8bit,但如果用 1 表示 m,10 表示 c,11 表示 o……我們只需要 12 bit 就能表達這個字符串了!只要字典占用的空間小于壓縮減少的空間,霍夫曼編碼就能有效減少文件尺寸。
沿著這樣的思路,一種主流的圖片格式終于誕生了,它就是 GIF。盡管我們現(xiàn)在提起 GIF 就會想到動圖,但實際上,GIF 是最早流行起來的圖片的編碼方式。GIF 的全稱是 「Graphics Interchange Format」,也就是“圖像交換格式”的意思,顯然它就是為了高效傳輸而誕生的。
GIF 使用了一種叫做 LZW 的壓縮技術(shù),它與幾乎所有現(xiàn)代壓縮軟件師出同源。比起標準的霍夫曼編碼,它的字典是動態(tài)生成的,因此需要傳輸?shù)某叽鐚M一步減小。所以 GIF 就相當于用壓縮文件來編碼圖片,這能不厲害嘛!
另外,在推出后不久,Netscape Navigator 支持了 GIF 的多幀動畫,以及定義動畫重復能力的功能——這下表情包王者們發(fā)揮的空間來了!GIF 很快風靡互聯(lián)網(wǎng),包含 Netscape 定義的動畫格式變成了事實標準。
那么,為什么現(xiàn)在除了動圖之外,我們都不再使用 GIF 了呢?一方面是由于 GIF 僅支持 256 種顏色,對于攝影圖片來說這幾乎是無法忍受的;另一方面則是因為一家公司的騷操作:
GIF 是歷史上首個提供電子郵件服務的公司 CompuServe 開發(fā)并開放給大家使用的,但是另一家公司優(yōu)利系統(tǒng)卻聲稱自己申請了 「LZW 中 W 的專利」,需要大家交納高額的專利費……于是很快,開源社區(qū)開始抵制 GIF 并開始開發(fā)新的圖片格式。因此盡管 2006 年開始 GIF 不再被專利限制,一個巨人已經(jīng)悄然站在了 GIF 的前面,它就是—— PNG。
PNG: 開放?
PNG 的全稱是 「Portable Network Graphics」,即“便攜式網(wǎng)絡圖片”。這意味著從設計之初它就面向:
- 面向 Web 展示場景。
- 更小的體積。
- 取代 GIF。實際上,確實如此!
PNG 的誕生離不開 GIF 的作死,正如 PNG 也被解釋為 「PNG is Not GIF」……PNG 從誕生之初就是完全無需許可的,由 IETF 作為 RFC 2083 發(fā)布,正如我們所知道的很多互聯(lián)網(wǎng)基礎協(xié)議一樣(例如 RFC 791 IP、RFC 1034 DNS、RFC 2616 HTTP/1.1~~ 等等),并在發(fā)布后不久就成為了 W3C 的推薦標準。PNG 能夠取代 GIF 是一件很容易理解的事情:畢竟,誰不喜歡白嫖呢?更何況 PNG 完美解決了 GIF 的另一個痛點:PNG 支持真彩色?。?!
其次,PNG 還有一個很大的特點:「向前兼容」。
PNG 格式與 PNM 和 GIF 類似,都由一個協(xié)議頭+多個內(nèi)容塊構(gòu)成,但 PNG 在標準制訂時就規(guī)定了塊可以分為兩類:「關(guān)鍵數(shù)據(jù)塊」 和 「輔助數(shù)據(jù)塊」。PNG 解析器必須支持關(guān)鍵數(shù)據(jù)塊的解析,而對于輔助數(shù)據(jù)塊則是能識別就識別,不能識別可以忽略。
這個特性有什么用呢?我們可以重新回顧一下,我們會在什么場景下使用 GIF 而不是 PNG 呢?顯然,最常見的場景就是上面所說的動圖。在 2004 年,Mozilla 推出了 APNG 格式。APNG 將動畫的第一幀作為 PNG 的關(guān)鍵數(shù)據(jù)塊,而后續(xù)幀和其他動畫信息則作為輔助數(shù)據(jù)塊,這樣即使是在不支持 APNG 的場景下,這些圖片也能展示為靜態(tài)的圖片了。
注意哦,這是一張 PNG 格式的圖!
另一個你可能感興趣的問題或許是,我們經(jīng)常使用 TinyPNG 這樣的工具來對 PNG 做壓縮,那么一張 PNG 圖片是如何被壓縮的呢?尤其是在我們已經(jīng)知道,GIF 為其壓縮算法保留了專利的情況下?
實際上 PNG 和 GIF 的算法非常相似。前面我們提到,GIF 為 LZW 中的 W 部分聲明了專利,而剩下的 LZ 部分實際上就是 LZW 的原始算法——LZ77,它來自于名字首字母 L 和 Z 的兩位大佬在 1977 年提出的壓縮算法。PNG 的壓縮正是基于 LZ77 的另一種算法:DEFLATE,這也正是 Web 領(lǐng)域常見的 GZIP 的壓縮算法。盡管細節(jié)不同,但基于動態(tài)字典的思路與 GIF 是類似的,這也保證了 PNG 具有高效的壓縮效率。
JPEG: 有損壓縮?
事情已經(jīng)發(fā)展到了這一階段:PNG 幾乎就要一統(tǒng)江湖了,但是為什么沒有呢?最主要的原因依然是 LZ77——它的壓縮效率相比原始數(shù)據(jù)已經(jīng)很高了,但是還遠遠不夠。像 LZ77 這樣的壓縮算法與霍夫曼編碼類似:數(shù)據(jù)多樣性越差,壓縮效率就越高。這意味著對于早期互聯(lián)網(wǎng)上的那種剪貼畫,PNG 是很有優(yōu)勢的;但隨著圖像復雜程度升高,PNG 能夠壓縮的空間也越來越有限了。有什么辦法能夠壓縮那些復雜的圖片,例如攝影作品呢?
JPEG 就是這樣誕生的。JPEG 全稱 「Joint Photographic Experts Group」,也就是“聯(lián)合圖像專家組”的意思,我們通常所說的 JPEG 就是這個專家組提出的第一種編碼標準,在 JPEG 之后實際上還有 JPEG 2000 這樣更高級的標準,但并沒有能夠撼動 JPEG 的地位(后文會提到)。事實上,JPEG 比 PNG 的出現(xiàn)還要更早,但比起 GIF 粗暴的 256 色化和 PNG 偏執(zhí)的無損壓縮,JPEG 采取了一種更實用主義的策略:「面向人眼識別的有損壓縮」。
不同于我們在 PNM 中使用的 RGB 色彩空間,JPEG 使用的是一種叫做 YUV 的色彩空間。YUV 三個字母分別代表亮度、色調(diào)和飽和度,這和現(xiàn)代更流行的 HSL 很接近。正如設計師們推崇 HSL 的主要原因是 HSL 更接近于人眼對色彩的感受方式,因此更適合做漸變處理,YUV 也被廣泛應用電視色彩調(diào)頻領(lǐng)域,原因就在于:「人眼對于亮度的感受要高于色調(diào)和飽和度」。你可以試試開啟或關(guān)閉手機的夜覽模式和原彩顯示,再試試調(diào)整亮度,就會發(fā)現(xiàn),我們對亮度的敏感程度是非常高的。
不僅如此,「人眼對于在一定范圍內(nèi)的亮度差異較為敏感」,例如我們會明顯感覺到 10% 和 20% 比 20% 和 25% 更接近,但卻難以區(qū)分 10% 和 90% 與 20% 和 80% 兩種對比的差異。通過一些矩陣變換的技巧,我們可以將頻域上的一些細節(jié)舍棄,這個過程被稱為「量化」。這是 JPEG 有損壓縮的最主要來源,通常 JPEG 壓縮時可以選擇壓縮質(zhì)量,影響的就是量化過程的系數(shù)。
從上面這張圖我們就可以看出來,一些亮度變化明顯的部分是 JPEG 損失最多的地方,例如鳥喙周圍會有明顯的噪點。盡管如此,對于我們通??吹降膱D片,JPEG 都能在合理地保證質(zhì)量的前提下大幅壓縮圖像的尺寸,這尤其體現(xiàn)在一些「繪畫作品」中,因為這些作品通常都有相對均勻的亮度。
然而,專利問題在 JPEG 身上依然未能幸免,2002 年一家公司宣稱自己擁有 JPEG 的專利,這在 PC 領(lǐng)域引發(fā)軒然大波,這與 JPEG 專家組創(chuàng)立之初期望的免版稅標準背道而馳。此案經(jīng)過 4 年的扯皮,最終以庭外和解的方式解決了。此事件同時暴露了 JPEG 2000 存在的專利風險,導致盡管 JPEG 2000 在技術(shù)上更加先進,卻最終沒有流行起來。
WebP: 金聲玉振?
數(shù)據(jù)壓縮是一個非常經(jīng)典的信息學問題。我們之所以能夠壓縮數(shù)據(jù),往往是因為這些數(shù)據(jù)「本身存在冗余信息」。例如霍夫曼編碼就利用了不同的數(shù)據(jù)出現(xiàn)的頻率不一致,這就是一種統(tǒng)計學冗余。但不論如何,我們都沒有辦法在 1bit 里面?zhèn)鬟f 2bit 的信息,因為信息也需要受到熵的限制,
截至此時,也許我們已經(jīng)把所有能夠使用的方式都窮盡了:我們嘗試了二進制編碼、壓縮算法,甚至針對人眼的觀感放棄了圖像的一部分信息……但是,真的結(jié)束了嗎?
開動我們的腦筋仔細想想,會不會有一種可能,我們可以將圖片信息中更多的部分「變成冗余」呢?
讓我們把視線從圖片轉(zhuǎn)向其他領(lǐng)域。有一個看起來和 JPEG 很有關(guān)系的格式是 MPEG,但是實際上二者的關(guān)系就和張飛與王菲差不多。但正如 JPEG 是專家組的名稱,MPEG 實際上也是如此,它是一個提出了音視頻領(lǐng)域多種編碼標準的組織。我們通常所說的 MPEG 實際上是 MPEG-1,是一種音頻標準,它最經(jīng)典的應用是 MPEG-1 第 3 音頻層,俗稱 MP3。而 MPEG 發(fā)布的最具影響力的標準當屬 MPEG-4,其中包含了 27 個子部分。每一個部分分別規(guī)定的視頻的編碼、控制、示例、優(yōu)化方式等等。我們最熟悉的應當是第 14 部分,俗稱 MP4。
在 MPEG-4 中,視頻編碼的部分是由第二部分(XVID)和第十部分(AVC)組成的,其中 AVC 更加高級;同時,由于 AVC 是 MPEG 和國際電信聯(lián)盟共同制定的,因此這個規(guī)范在國際電信聯(lián)盟也有一個別名,它就是 「H.264」。
H.264 通過只記錄幀與幀之間的變化,得以將視頻大幅壓縮,也就是我們通常所說的 「運動補償」。顯然比起 GIF 對圖片的每幀都進行保存,這種方式的存儲效率要高出幾個數(shù)量級!除了運動補償外,還有一些高級的壓縮手段,例如“「幀內(nèi)預測」”。這意味著,在解碼器對某一幀進行解碼時,「可以根據(jù)某個單元相鄰的單元來預測該單元的值,從而使視頻文件只需要記錄實際值和預測值的差值就足夠了」。由于其極高的壓縮效率,H.264 很快統(tǒng)治了視頻編碼領(lǐng)域。
但是,正如 GIF 和 JPEG 面對的一樣,MPEG 的標準實際上是包含專利的。因此,很多公司試圖開發(fā)能夠代替 H.264 的視頻編碼。Google 在 2010 年收購的一家叫做 On2 的公司就是做這件事情的。收購完成不久后,Google 就在當年的 Google I/O 上宣布開源 On2 的最新視頻編碼 VP8,為什么呢?因為與此同時,Google 推出了一個新的開源視頻格式,也就是本章節(jié)的主角的兄弟——WebM。
我們現(xiàn)在知道,WebM 實際上并未掀起多大波瀾,但在當時仍然是劃時代般的進步,尤其是在半年后,Google 基于 VP8 技術(shù)再次給出了新的圖片格式 WebP 的時候。在經(jīng)歷了那么多版權(quán)和專利糾紛后,Web 領(lǐng)域終于又有了「開源+免版稅」的新格式,并且還是圖片+視頻打包的!
正是因為 WebP 技術(shù)是從 VP8 衍生而來的,因此它繼承了視頻領(lǐng)域的有損壓縮手段,這就是前面提到的 「幀內(nèi)預測」。WebP 會使用每個塊上方的三個塊和左側(cè)的三個塊進行預測,并且包含了 H.264 的四種幀內(nèi)預測模式,這也就是 WebP 能夠做到比 PNG 更小的原因——通過幀內(nèi)預測實現(xiàn)了更多原始信息的冗余化。在此基礎之上,WebP 同樣使用了字典編碼等等無損壓縮技術(shù),從而使圖片的尺寸降到了盡可能低的程度。
展望?
WebP 已經(jīng)是圖片壓縮的終結(jié)了嗎?當然不!
在 WebP 誕生之初實際上不支持無損壓縮和透明通道,并且它的有損壓縮甚至不如 JPEG;但正是因為開源的力量,讓 WebP 逐漸成為了目前最具優(yōu)勢的主流 Web 圖片格式。那么現(xiàn)在,除了 WebP 我們還有哪些選擇呢?
如果說有哪種格式表現(xiàn)超越 WebP,BPG 一定是其中的一個。前面我們提到,WebP 的實現(xiàn)來自于 VP8,而 VP8 又來自于 H.264?,F(xiàn)在你也許知道,H.264 已經(jīng)不足以滿足如今大量的 4k、8k 甚至更高的顯示需要,因此 2013 年的時候國際電信聯(lián)盟發(fā)布了新的視頻標準 H.265,學名叫做 HEVC —— 「High Efficiency Video Coding」,高效視頻編碼。HEVC 在 H.264 之上做了諸多改進,例如幀內(nèi)預測就從 4 種模式上升到了 33 種!
BPG 使用了基于 HEVC 幀內(nèi)預測算法的有損壓縮,這意味著它的性能要顯著領(lǐng)先于 JPEG 甚至 WebP。然而,由于 HEVC 與 H.264 一樣保留版權(quán),這也成為了 BPG 并沒有大規(guī)模流行的主要原因。
在無損壓縮領(lǐng)域有沒有呢?顯然也是有的,F(xiàn)LIF(https://github.com/FLIF-hub/FLIF) 就是其中的典型。FLIF 是 2015 年發(fā)布的,并且也是完全開源的。FLIF 采用和 H.264 類似的一種動態(tài)學習的壓縮算法,在無損壓縮方面將壓縮性能優(yōu)化到了新高度。但作為一個純社區(qū)項目,F(xiàn)LIF 在發(fā)布后不久就逐漸式微,但其核心思路被 JPEG 的新標準 JPEG XL 繼承,并且 JPEG XL 最終也在 2020 年作為免版稅標準發(fā)布;BPG 和 FLIF 也最終啟發(fā)了 MPEG,發(fā)布了基于 HEVC 的圖片格式 HEIF。
WebP 的后現(xiàn)代藝術(shù)
最后?
故事的最后則重新回到我們的卷王 Google 身上。在 VP8 對標 H.264 而國際電信聯(lián)盟發(fā)布了 H.265 之后,Google 推出了 VP9 來對標 H.265;盡管不及預期,但最終促成了 AOMedia(開放標準聯(lián)盟,由 Google、蘋果、微軟、Facebook、Mozilla 等創(chuàng)建)的成立?;?VP10 的 AV1 正是 AOMedia 開發(fā)的用以代替 H.265 的最新免版稅標準。
2021 年起 Google 開始開發(fā)下一代 WebP,被稱為 WebP 2,便是基于 AV1 視頻編碼。或許在不久之后,我們就能看到新的圖片格式橫空出世,并建立它的天下。