ByteScope

WOFF2 字型檔案格式

Web Open Font Format 2——WOFF 的後繼者,改用 Brotli 壓縮。

MIME 類型
font/woff2
副檔名
.woff2
分類
字型

Magic number(檔案簽章)

0x00000000774F4632wOF2'wOF2' tag

關於 WOFF2 字型格式

WOFF2 維持 WOFF 的外形,把底下的東西全部換掉。標頭長到 48 個位元組,好放進壓縮主體的大小;表目錄變成長度不定的結構,常見的表標籤用單一個位元組表示;每張表各一條 zlib 資料流換成整個字型一條 Brotli 資料流;而 glyf 與 loca 表會先過一次可逆轉換,把外框重新編碼成 Brotli 壓得好很多的形狀。還原出來的字型仍然等價於放進去的那份,但和 WOFF 不同,不把整份解壓縮就什麼都讀不到。

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

位移長度欄位意義
04signature77 4F 46 32,ASCII 的 wOF2。和 WOFF 的標籤在同一個位置、只差一個字元,正是那種會讓草率的字串比較配到錯格式的近似撞號。
44flavor裡面那份字型的 sfntVersion:TrueType 外框是 00 01 00 00,CFF 是 4F 54 54 4F。意義與位置都和 WOFF 那個欄位相同,而且它是前 48 個位元組裡唯一在講字型、而不是在講外殼的地方。
84lengthWOFF2 檔案的總大小。和 WOFF 一樣,它必須和磁碟上的檔案完全相符,所以你得到一個不花成本、也不需要 Brotli 解碼器的截斷檢查。
122numTables目錄記錄的筆數。和 WOFF 不同,它不會告訴你資料從哪裡開始,因為記錄的長度是不定的;你得一筆一筆走過去。
142reserved必須是零,而且瀏覽器消毒器會強制。這裡出現別的值,在網頁上是快速拒收,在多數離線工具裡則是被默默忽略——這是「同一個字型在頁面裡和在桌面上表現不同」很好的例子。
164totalSfntSize還原後 sfnt 字型的大小,解碼器用它一次配置好輸出緩衝區。拉丁文字字體相對於位移 8 的 length,接近三比一的比例很平常。
204totalCompressedSizeBrotli 資料流的長度。這是 WOFF 沒有的欄位,也是標頭從 44 變成 48 個位元組的原因,更是唯一能讓讀取端不解壓縮任何東西就找到壓縮主體結尾的數字。
244majorVersion and minorVersion位移 24 和 26 的兩個 16 位元數字,標的是字型而不是格式的版本,和 WOFF 完全一樣,只是因為前面多了一個欄位而往後移了 4 個位元組。用 WOFF 解析器去讀 WOFF2,從這裡開始就會產出一堆看起來很像樣的胡說八道,這比乾脆被拒收更難纏。
2812metaOffset, metaLength, metaOrigLength選用的壓縮 XML 中繼資料區塊,由位移 28、32、36 三個 32 位元欄位描述。通常全是 0。它存在時是和字型主體分開壓縮的,所以不用碰主資料流就讀得到。
408privOffset and privLength選用的私有資料區塊,位在位移 40 和 44,把 48 位元組的標頭收尾。沒有任何規範,通常是 0;非零代表做這個字型的人在檔案裡塞了自己的東西。
48variableTable directory長度不定的記錄,所以和其他 sfnt 衍生格式都不同,沒有任何算術能算出第二筆的位址。每筆記錄以一個旗標位元組開頭,它的低 6 位元是一份常見表標籤固定清單的索引——值 63 代表後面接一個字面的 4 位元組標籤——最高 2 位元則帶著轉換版本。後面的長度以每位元組 7 位元儲存、最高位元代表還有下一個,所以整筆記錄可以短到只有 2 個位元組。
variablevariableBrotli stream所有表依目錄順序串接起來、壓成一條。glyf 與 loca 預設會被轉換,而它的編碼方式真的很反直覺:對這兩個標籤而言,轉換版本 0 代表「已轉換」,而對其他所有標籤,0 代表「未轉換」。第三方讀取端經常把它搞反。

怎麼跟長得像的格式分開

容易搞混的怎麼分
WOFF 字型位移 0 的標籤是最快的測試——77 4F 46 32 對上 77 4F 46 46——而結構上的差別是 WOFF2 在位移 20 插入了 totalCompressedSize,把 majorVersion、minorVersion 與中繼資料欄位全部往後推了 4 個位元組。拿 WOFF 解析器去讀 WOFF2 不會當掉;它會把壓縮大小當成版本號讀出來,然後一路走進垃圾裡。
TrueType 字型sfnt 讀取端在該有版本號的地方看到 77 4F 46 32,就停手了。字型真正的 sfntVersion 在位移 4,所以這個檔案裡確實有 00 01 00 00 或 4F 54 54 4F,只是不在字型工具會看的位置。除了 WOFF2 解碼器,沒有東西弄得出那些表。
Brotli (.br)原始的 Brotli 完全沒有簽章位元組,所以 .br 檔案在位移 0 沒有任何可辨識的東西,只能靠檔名或 Content-Encoding 認出來。而 WOFF2 也不是 Brotli 檔案:前 48 個位元組加上整份表目錄都是未壓縮的明文結構,所以從位移 0 把檔案餵給 Brotli 解壓縮器會立刻失敗。資料流要到目錄之後才開始,而那個位移只能靠走過目錄才找得到。

常見的壞法

  • length 欄位和檔案對不上。位移 8 那 4 個位元組寫的是精確的檔案大小,所以截斷從標頭就證明得了。這件事要第一個做;相當高比例的網頁字型失敗到這裡就結案了。
  • Brotli 資料流被截斷。和 WOFF 不同,這裡沒有逐表隔離——所有表都住在同一條資料流裡——所以尾端少幾個位元組,代價不是損失一張表,而是損失損壞點之後的每一張表,實務上等於整份字型。沒有「還能用一部分」的退路可走。
  • 字型網址底下其實是一頁錯誤頁。404 或登入轉址被存成 .woff2,瀏覽器在期待 wOF2 的地方看到 HTML doctype,主控台報的是解碼失敗與消毒器錯誤,沒有一句話提到網頁。
  • 檔案被改名。從字型服務下載的 .woff2 給它 .ttf 或 .otf 副檔名,到哪都裝不起來,而作業系統會回報檔案損毀而不是格式不對。前 4 個位元組立刻就能結案。
  • 文字模式傳輸,或任何會改寫換行的處理。Brotli 的輸出不是文字,0D 0A 被改掉就活不下來,而且因為只有一條資料流,連能搶救的殘餘都沒有。標頭讀起來還是完美無缺,這才是讓人困惑的地方。

這個格式現在還在用嗎

WOFF2 就是那個網頁字型格式,基本上已經沒有對手。目前在用的每個瀏覽器都支援它,Google Fonts 和其他託管服務預設送的都是它,而現代的 @font-face 區塊裡如果還列了別的,那是列給流量裡早就不存在的瀏覽器看的。同一份字型比 WOFF 省下大約三成,實務上就是「首次繪製要不要等字型」的差別。它從來不是正確選擇的場合,是任何「要打開它、而不是拿它來算繪」的地方:桌面裝不起來、多數字型編輯器不讀它,而每個檢視工具都得先整份解壓縮才說得出任何東西。所以建置流程會把 TTF 或 OTF 留作單一事實來源、把 WOFF2 當成產出,就像它們留著來源圖片、產出 WebP 一樣——而一個把原檔弄丟、只剩 WOFF2 的專案,是真的替自己製造了一個麻煩。

在這個站上打開 WOFF2 字型檔

這些全部在你的瀏覽器裡跑,檔案不會離開你的電腦。

相關格式

容易和 WOFF2 字型搞混的格式,可以比對它們的開頭位元組。

格式開頭位元組副檔名
WOFF 字型77 4F 46 46.woff
TrueType 字型00 01 00 00.ttf
OpenType 字型4F 54 54 4F.otf

常見問題

檔案的 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 仍然可能夾帶惡意內容。辨識真實類型是有用的第一道檢查,尤其在副檔名和位元組不一致的時候,但它不是惡意軟體掃描。

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