ByteScope

WebP 檔案格式

Google 的 WebP 格式,一個可放有損或無損影像的 RIFF 容器。

MIME 類型
image/webp
副檔名
.webp
分類
圖片

Magic number(檔案簽章)

0x0000000052494646RIFFRIFF container
0x0000000857454250WEBP'WEBP' form type

關於 WebP 格式

WebP 同時提供有損與無損兩種模式,還支援動畫與透明度,檔案大小通常勝過 JPEG 與 PNG。它本質上是 RIFF 容器:'RIFF' 四個位元組、4 位元組的長度,接著是格式類型 'WEBP'。後面跟著一個或多個 chunk,而第一個出現的是哪一種,就決定了這個檔案的一切 — 單純的有損影像是一個 VP8 chunk,單純的無損影像是一個 VP8L chunk,而只要帶了 alpha 通道、動畫、ICC 描述檔或中介資料,第一個就會是 VP8X chunk,由它宣告用到哪些功能,再由後面的 chunk 各自提供內容。

檔頭結構,一個位元組一個位元組看

位移長度欄位意義
04RIFF container tag52 49 46 46,ASCII 的 RIFF 四個字母。這絕對不是 WebP 專有的 — AVI 和 WAV 開頭就是一模一樣的四個位元組 — 所以在讀到位移 8 之前,關於格式你什麼都還沒確定。
44RIFF payload size這個欄位之後所有東西的位元組數,小端序,也就是檔案大小減八。跟多數大小欄位不同,這個欄位是被期待要精確的,所以拿它跟磁碟上的長度比對,花四個位元組就能立刻抓到截斷和隨手往後串接的內容。
84WEBP form type57 45 42 50。這個欄位才是把 WebP 從其他所有 RIFF 檔案裡分出來的關鍵,它加上位移 0 的標籤,才是這個格式真正的 magic number:十二個位元組,中間那四個是變動的。
124First chunk FourCC這裡只有三種合法的值。56 50 38 20 是 VP8 加一個尾隨空格,單純的有損影像。56 50 38 4C 是 VP8L,單純的無損影像。56 50 38 58 是 VP8X,只要有 alpha、動畫、Exif、XMP 或 ICC 描述檔就會用的擴充形式。
164First chunk payload size後面那段 chunk 資料的長度,小端序,不含 FourCC 與長度本身這八個位元組。RIFF 會把每個 chunk 補齊到偶數長度,而補的那個位元組不算進這裡 — 手寫的剖析器碰上奇數長度 chunk 會對不齊,就是漏了這個細節。
203VP8 frame tag — simple lossy only三個位元組的封裝位元欄位,是 VP8 位元串流的開頭:最低位元說這是關鍵影格還是中間影格,接下來三個位元是 profile,一個位元是 show_frame,剩下十九個位元是第一個資料分區的大小。在靜態的 WebP 裡,它永遠是關鍵影格。
233VP8 key-frame start code — simple lossy only固定值 9D 01 2A。這是這個格式最接近第二個簽章的東西,在位移 23 找到它,同時確認了兩件事:檔案是有損 WebP,而且它第一個 chunk 標頭的大小如你所料。
264VP8 width and height — simple lossy only兩個小端序 16 位元值,先寬後高。每個值只有低十四個位元是尺寸;最高兩個位元是水平或垂直的縮放提示,而那個東西基本上沒人實作。十四個位元也就是為什麼單一個 VP8 影格每邊不能超過 16383 像素。
201VP8L signature byte — simple lossless only固定值 2F。緊接在它後面,寬度減一與高度減一各以十四個位元打包在位元串流裡,所以跟這一頁其他每個欄位都不同,它們不落在位元組邊界上,不做位移就沒辦法從 hex dump 直接讀出來。
204VP8X flags and reserved bytes — extended only一個旗標位元組,接著三個保留的零位元組。旗標從位元 5 往下依序宣告:ICC 描述檔、alpha 通道、Exif 中介資料、XMP 中介資料、動畫。它們只是宣告、不是資料本身:每項功能都由檔案後面它自己的 chunk 提供。
246VP8X 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 格式,橫跨音訊、影片和影像,而在第九個位元組之前它們無從分辨。
PNG89 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 搞混的格式,可以比對它們的開頭位元組。

格式開頭位元組副檔名
PNG89 50 4E 47 0D 0A.png
JPEGFF D8 FF.jpg
WAV52 49 46 46.wav
AVI52 49 46 46.avi

常見問題

檔案的 magic number 是什麼?

檔案開頭的前幾個位元組,不管檔名寫什麼,它標明的是真正的格式。PNG 一定以 89 50 4E 47 開頭,ZIP 則是 50 4B 03 04。作業系統、瀏覽器和 file 指令讀的都是這幾個位元組,而不是相信副檔名 — 這就是為什麼把檔案改名並不會改變它實際上是什麼。

我要怎麼自己檢查 magic number?

在 macOS 或 Linux 上,xxd -l 16 檔名 會印出前 16 個位元組;在 Windows 上,PowerShell 的 Format-Hex -Path 檔名 -Count 16。或者把檔案丟進本站的檔案類型辨識工具,它會在本機讀取位元組並告訴你是什麼格式,不會上傳任何東西。

為什麼兩種格式的 magic number 會一樣?

因為其中一種是建立在另一種之上。docx、xlsx、pptx、apk、jar 與 epub 骨子裡都是 ZIP 壓縮檔,所以全都以 ZIP 的簽章開頭;要分辨它們得看裡面的項目。Java class 檔和 macOS 的通用二進位檔都以 CA FE BA BE 開頭,靠緊接其後的欄位區分。

有完全沒有 magic number 的檔案嗎?

有。XML、HTML、JSON、SVG、CSV 這類以文字為基礎的格式沒有固定的位元組簽章,所以改用結構來辨識:開頭的 <?xml 宣告、<svg 元素,或是 { 後面接著帶引號的鍵。這種偵測是合理推測而非確定,因此本參考頁會把這些格式標示為結構偵測。

magic number 相符就代表檔案安全嗎?

不代表。它告訴你的是格式,不是內容是否無害 — 一個貨真價實的 PDF 或 docx 仍然可能夾帶惡意內容。辨識真實類型是有用的第一道檢查,尤其在副檔名和位元組不一致的時候,但它不是惡意軟體掃描。

手上有檔案可能是 WebP?用檔案類型辨識工具查出來 — 它在本機讀取 magic number,不上傳任何東西。或者瀏覽所有格式。