WebP 檔案格式
Google 的 WebP 格式,一個可放有損或無損影像的 RIFF 容器。
- MIME 類型
- image/webp
- 副檔名
- .webp
- 分類
- 圖片
Magic number(檔案簽章)
| 0x00000000 | 52494646 | RIFF | RIFF container |
| 0x00000008 | 57454250 | WEBP | 'WEBP' form type |
關於 WebP 格式
WebP 同時提供有損與無損兩種模式,還支援動畫與透明度,檔案大小通常勝過 JPEG 與 PNG。它本質上是 RIFF 容器:'RIFF' 四個位元組、4 位元組的長度,接著是格式類型 'WEBP'。後面跟著一個或多個 chunk,而第一個出現的是哪一種,就決定了這個檔案的一切 — 單純的有損影像是一個 VP8 chunk,單純的無損影像是一個 VP8L chunk,而只要帶了 alpha 通道、動畫、ICC 描述檔或中介資料,第一個就會是 VP8X chunk,由它宣告用到哪些功能,再由後面的 chunk 各自提供內容。
檔頭結構,一個位元組一個位元組看
| 位移 | 長度 | 欄位 | 意義 |
|---|---|---|---|
| 0 | 4 | RIFF container tag | 52 49 46 46,ASCII 的 RIFF 四個字母。這絕對不是 WebP 專有的 — AVI 和 WAV 開頭就是一模一樣的四個位元組 — 所以在讀到位移 8 之前,關於格式你什麼都還沒確定。 |
| 4 | 4 | RIFF payload size | 這個欄位之後所有東西的位元組數,小端序,也就是檔案大小減八。跟多數大小欄位不同,這個欄位是被期待要精確的,所以拿它跟磁碟上的長度比對,花四個位元組就能立刻抓到截斷和隨手往後串接的內容。 |
| 8 | 4 | WEBP form type | 57 45 42 50。這個欄位才是把 WebP 從其他所有 RIFF 檔案裡分出來的關鍵,它加上位移 0 的標籤,才是這個格式真正的 magic number:十二個位元組,中間那四個是變動的。 |
| 12 | 4 | First chunk FourCC | 這裡只有三種合法的值。56 50 38 20 是 VP8 加一個尾隨空格,單純的有損影像。56 50 38 4C 是 VP8L,單純的無損影像。56 50 38 58 是 VP8X,只要有 alpha、動畫、Exif、XMP 或 ICC 描述檔就會用的擴充形式。 |
| 16 | 4 | First chunk payload size | 後面那段 chunk 資料的長度,小端序,不含 FourCC 與長度本身這八個位元組。RIFF 會把每個 chunk 補齊到偶數長度,而補的那個位元組不算進這裡 — 手寫的剖析器碰上奇數長度 chunk 會對不齊,就是漏了這個細節。 |
| 20 | 3 | VP8 frame tag — simple lossy only | 三個位元組的封裝位元欄位,是 VP8 位元串流的開頭:最低位元說這是關鍵影格還是中間影格,接下來三個位元是 profile,一個位元是 show_frame,剩下十九個位元是第一個資料分區的大小。在靜態的 WebP 裡,它永遠是關鍵影格。 |
| 23 | 3 | VP8 key-frame start code — simple lossy only | 固定值 9D 01 2A。這是這個格式最接近第二個簽章的東西,在位移 23 找到它,同時確認了兩件事:檔案是有損 WebP,而且它第一個 chunk 標頭的大小如你所料。 |
| 26 | 4 | VP8 width and height — simple lossy only | 兩個小端序 16 位元值,先寬後高。每個值只有低十四個位元是尺寸;最高兩個位元是水平或垂直的縮放提示,而那個東西基本上沒人實作。十四個位元也就是為什麼單一個 VP8 影格每邊不能超過 16383 像素。 |
| 20 | 1 | VP8L signature byte — simple lossless only | 固定值 2F。緊接在它後面,寬度減一與高度減一各以十四個位元打包在位元串流裡,所以跟這一頁其他每個欄位都不同,它們不落在位元組邊界上,不做位移就沒辦法從 hex dump 直接讀出來。 |
| 20 | 4 | VP8X flags and reserved bytes — extended only | 一個旗標位元組,接著三個保留的零位元組。旗標從位元 5 往下依序宣告:ICC 描述檔、alpha 通道、Exif 中介資料、XMP 中介資料、動畫。它們只是宣告、不是資料本身:每項功能都由檔案後面它自己的 chunk 提供。 |
| 24 | 6 | VP8X canvas size — extended only | 畫布寬度減一與畫布高度減一,兩個 24 位元小端序值,所以畫布可以遠大於單一個 VP8 影格容納得下的尺寸。在動畫裡,這就是各影格要合成上去的那塊畫布,而每一格自己帶著各自的位移與尺寸。 |
怎麼跟長得像的格式分開
| 容易搞混的 | 怎麼分 |
|---|---|
| AVI | 前八個位元組完全相同,因為兩者都是 RIFF 檔案。位移 8 的格式類型就是全部的判別法:WebP 是 57 45 42 50,AVI 是 41 56 49 20 加一個尾隨空格。只比對 52 49 46 46 的工具,會很開心地把一段影片標成影像 — 偵測器把類別判錯時,第一個要查的就是這件事。 |
| WAV | 同一個 RIFF 陷阱的另一個方向:位移 8 是 57 41 56 45。值得特別點名,因為 WAV、AVI 和 WebP 是大家實際會碰到的三種 RIFF 格式,橫跨音訊、影片和影像,而在第九個位元組之前它們無從分辨。 |
| PNG | 89 50 4E 47 對上 52 49 46 46。它們在「帶 alpha 的無損影像」上正面對決,而無損 WebP 通常在檔案大小上贏個四分之一左右。要注意的是:帶透明度的無損 WebP 是一個 VP8X 檔案,另外配一個 ALPH chunk,所以它的結構跟上面講的那種單純有損形式毫無共通之處。 |
| GIF | 動畫 WebP 不是另一種格式:它就是一個設了動畫旗標的 VP8X 檔案,配上一個交代背景色與循環次數的 ANIM chunk,再加上每格一個 ANMF chunk。它用零頭的大小取代 GIF,透明度是完整 alpha 而不是單一個透明索引 — 這就是為什麼那麼多平台現在會把上傳的檔案轉碼,再繼續用 .gif 網址送出去。 |
常見的壞法
- 位移 4 的 RIFF 大小過期了。往 WebP 後面附加東西卻沒更新那個欄位,產出的檔案會讓嚴格的讀取端停在宣告的長度,寬鬆的則一路走 chunk 走到資料尾端,於是同一張圖在某個工具裡看得到中介資料、在另一個裡看不到。用 shell 重導向把檔案串起來,通常就是這個下場。
- 截斷。十二個位元組的容器標頭和 chunk 標頭都還在,所以尺寸讀得對,圖的上半部也解得出來,接著 VP8 分區用完了;下半部留成一片平灰或平綠。位移 4 的大小欄位會超過實際檔案長度,四個位元組就確認完畢。
- 奇數長度 chunk 後面少了補齊位元組。RIFF 要求每個 chunk 補到偶數長度,寫入端忘了補,後面每一個 chunk 標頭的位移就全部差一。第一個 chunk 照樣解得出來,所以圖出得來,而它的 ICC 描述檔或 Exif 區塊就悄悄消失了。
- 用錯的副檔名提供或改名。社群與通訊 app 一天到晚用 .jpg 的名字送 WebP 出來,所以一個在舊版桌面編輯器裡打不開的檔案,很多時候是完好無損的 WebP。位移 0 四個位元組就能斷定,而且根本不需要重新編碼 — 改名就夠了。
- VP8X 標頭承諾了檔案裡沒有的功能。alpha 旗標設了、後面卻沒有 ALPH chunk,各家解碼器的反應就不一致:有的把圖畫成不透明,有的直接拒收。位元組排版沒有任何一處不合法,所以驗證器一律放行。
這個格式現在還在用嗎
WebP 是現在網路影像的預設交付格式,從 2020 年 Safari 14 補上支援、讓它擁有全瀏覽器覆蓋之後就是了。它剛好卡在最實用的中間位置:同畫質下比 JPEG 小四分之一到三分之一,無損模式贏過 PNG,alpha 和動畫都在同一個容器裡,而且編碼快到可以在 CDN 或影像伺服器上隨要隨編,不必只能塞進夜間批次。AVIF 壓得更好、HEIC 才是手機拍出來的東西,但那兩者都沒有它這麼便宜、也沒有它這麼可以安心假設對方吃得下。它的限制是真的,投入之前值得先知道:每通道只有 8 位元,所以沒有 HDR、也交付不了廣色域;有損模式強制開色度次取樣;單一影格每邊上限 16383 像素。如果網站只想用一種格式、不想寫任何 fallback 邏輯,照片內容用它就是今天的正確答案;如果 picture 元素和 fallback 本來就都準備好了、目標是壓到最小,那標準做法是 AVIF 排第一、WebP 排第二。
在這個站上打開 WebP 檔
這些全部在你的瀏覽器裡跑,檔案不會離開你的電腦。
相關格式
容易和 WebP 搞混的格式,可以比對它們的開頭位元組。