ByteScope

WOFF フォントファイル形式

Web Open Font Format — ウェブ配信向けに TTF/OTF を圧縮して包んだ形式。

MIME タイプ
font/woff
拡張子
.woff
カテゴリ
フォント

マジックナンバー(ファイル署名)

0x00000000774F4646wOFF'wOFF' tag

WOFF フォント形式について

WOFF は独立したフォント形式ではなく、コンテナです。完成した TrueType または OpenType フォントを受け取り、各テーブルを個別に zlib で圧縮し、44 バイトのヘッダと新しいテーブルディレクトリを前に付けます。取り出したフォントは、入れたものとバイト単位で等価です。動機は 2 つありました。サイズの削減と、WOFF が「インストールできるデスクトップ用ファイル」ではなく明らかにウェブフォントだと見て取れること。後者は、フォントベンダーに @font-face 向けのライセンスを許可させるのに十分な理由でした。まさにそのライセンス情報を入れるための、圧縮された XML メタデータのブロックも省略可能な形で持てます。

ヘッダーの構造(バイト単位)

オフセット長さフィールド意味
04signature77 4F 46 46、小文字の w を含む ASCII の wOFF。この大文字小文字の混在は意図的で、覚えておく価値があります。hex ビューアで大文字小文字を無視して WOFF を検索すると、メタデータブロックや埋め込みの著作権表示の文字列にも引っかかるからです。
44flavor中に入っているフォントの sfntVersion で、TrueType アウトラインなら 00 01 00 00、CFF なら 4F 54 54 4F。.ttf や .otf がオフセット 0 に持っているものを 4 バイト後ろへずらしたもので、ラッパーを外したときに何が出てくるかを教えてくれます。
84lengthWOFF ファイル全体のバイト数。実際のファイル長と一致していなければならないので、途中で切れたダウンロードを、展開もフォントの知識もなしに先頭 12 バイトだけで検出できます。この検査をただで手に入れられる形式はごくわずかです。
122numTablesテーブルディレクトリのエントリ数。エントリはちょうど 20 バイトずつなので、この数値から圧縮データの開始位置も分かります。
142reservedゼロでなければなりません。ブラウザはウェブフォントをすべてサニタイザに通してからラスタライザへ渡すので、誰も読まないフィールドが非ゼロというだけで、デスクトップのツールが平気で開くファイルがウェブでは門前払いされます。
164totalSfntSize再構成したフォントのサイズで、ディレクトリとテーブル間のパディングも含みます。オフセット 8 の length と並べれば、何も展開せずに圧縮率が分かります。本文用書体なら 2 対 1 を少し上回るくらいが典型です。
204majorVersion and minorVersionオフセット 20 と 22 にある 16 ビットの数値 2 つ。バージョンを付けている対象は WOFF 形式ではなくフォントのほうで、たいていは元フォントの head テーブルから写すか、それに合わせてあります。ほとんどの場合 1.0 か 1.1 が入っています。
2412metaOffset, metaLength, metaOrigLengthオフセット 24、28、32 にある 3 つの 32 ビットフィールドで、省略可能な zlib 圧縮の XML メタデータのブロックを記述します。ライセンス、ベンダー、説明を入れることを想定した場所です。無ければ 3 つともゼロで、実際にはそれが普通です。
368privOffset and privLengthオフセット 36 と 40 にある 2 つ目の省略可能なブロックで、フォントの作者が好きなものを入れてよく、中身は何も定義されていません。これも通常はゼロなので、非ゼロならフォントの出どころを突き止めたいときに覗く価値があります。
44variableTable directoryヘッダの直後から、テーブルごとに 20 バイト。タグ、WOFF ファイル内のオフセット、圧縮後の長さ、元の長さ、そして元の非圧縮テーブルのチェックサム。したがって最初のテーブルの圧縮データは 44 + 20 × numTables から始まり、hex ビューアの前で暗算できる程度の計算です。
variablevariableCompressed table dataテーブルごとに独立した zlib ストリームが、ディレクトリの順に並びます。圧縮しても小さくならないテーブルはそのまま格納してよいことになっていて、ディレクトリ上では圧縮後の長さと元の長さが等しいエントリとして見分けられます。数十バイトしかない小さなテーブルではよくあることです。

似た形式との見分け方

紛らわしい形式見分け方
WOFF2 フォントオフセット 0 が 77 4F 46 46 か 77 4F 46 32 か。そしてそれ以降もすべて違います。WOFF2 のヘッダはオフセット 20 に totalCompressedSize を足したぶん 44 ではなく 48 バイト、ディレクトリのレコードは 20 バイト固定ではなく可変長、本体はテーブルごとの zlib ではなくフォント全体で 1 本の Brotli ストリームです。
TrueType フォントWOFF の中にあるのは TrueType か OpenType のフォントそのもので、何も改変されていません。ただ、それを識別する 4 バイトがオフセット 0 から 4 へ移っているだけです。オフセット 0 しか見ない読み手は wOFF を見て「不明なフォント」と報告し、オフセット 4 も見る読み手は、展開した後に何が手に入るかまで教えてくれます。
GZIPどちらも zlib 圧縮のペイロードを運びますし、どちらも汎用の展開器をオフセット 0 に向けても読めません。gzip のファイルは 1F 8B で、先頭近くから始まるストリームを 1 本持ちます。WOFF はディレクトリしか知らないオフセットから始まるストリームを多数持ち、そのどれにもローカルヘッダが付いていません。WOFF を .gz にリネームして gunzip にかければ即座に失敗しますが、その失敗はフォントが無事かどうかについて何も語っていません。

よくある壊れ方

  • length フィールドがファイルと食い違っている。オフセット 8 の 4 バイトがファイル全体のサイズを宣言しているので、途中切れや余分なパディングは、何も展開しないうちに hex ビューアで証明できます。まず走らせるべき検査であり、これだけで失敗したウェブフォント読み込みのかなりの割合が片付きます。
  • フォントの URL の下にエラーページが置かれていた。404 やログインへのリダイレクト、レート制限の通知が .woff として保存されると、テキストエディタでは HTML として開きます。ブラウザのコンソールは「ダウンロードしたフォントをデコードできない」とサニタイザのパースエラーを報告しますが、そのメッセージのどこにも「これはウェブページです」とは書いていないので、やたらと時間を溶かします。
  • ブラウザのサニタイザに拒否された。ブラウザはデスクトップのフォントツールよりかなり厳格です。ゼロでない予約フィールド、許容範囲外の値、重なり合う構造。手元のマシンには問題なくインストールできるファイルでも、ウェブではこれらが理由で拒否されます。ローカルでは動くのにページでは動かないフォントは、サーバーの問題ではなくたいていこれです。
  • テーブルが 1 つ壊れた。テーブルごとに zlib ストリームが独立しているので、1 バイトの反転はちょうど 1 つを殺し、残りは無傷で残ります。その結果、フォントは読み込まれ、正しいメトリクスを報告し、グリフも描くのに、カーニングだけが、あるいは縦組みのメトリクスだけが失われている、という奇妙な壊れ方をします。展開に失敗したテーブル次第です。
  • テキストモード転送。改行を変換するデプロイ手順は圧縮ストリーム内の 0D 0A を書き換えますが、そこはテキストではないので生き延びません。ヘッダとディレクトリは無傷で通るので、inflate が失敗するその瞬間まで、ファイルはちゃんとフォントに見えています。

この形式の現在地

WOFF はおおよそ 2012 年から WOFF2 が追いつくまでの間、ウェブフォントの形式でした。今の役目は配信ではなく互換性です。この 10 年に出たブラウザはどれも WOFF2 を優先しますし、同じ内容で 3 分の 1 ほど小さくなるので、今どきの @font-face は WOFF2 を先に書き、WOFF はフォールバックとしてだけ添えます。しかも最近はそれすら書かなくなりました。フォールバックが要るブラウザは、解析データからほぼ消えたからです。今も WOFF に出くわすのは、何年も前に作られてそのまま再ビルドされていないパッケージ済みソフトウェア、ドキュメントのバンドル、テーマの中、そして Brotli より古いツール群の中です。この形式の本当の功績は技術面ではありませんでした。明らかにインストールできない形で包み、ライセンスがファイルと一緒に旅できるメタデータのブロックを持たせたことで、ベンダーがウェブ利用を認めない理由になっていた論争に決着を付けたのです。それ以降のウェブフォントはすべて、この決着の上で暮らしています。

WOFF フォントファイルをこのサイトで開く

どれもブラウザ内で動きます。ファイルが端末から出ることはありません。

関連する形式

WOFF フォントと混同しやすい形式です。先頭バイトを見比べてください。

形式先頭バイト拡張子
WOFF2 フォント77 4F 46 32.woff2
TrueType フォント00 01 00 00.ttf
OpenType フォント4F 54 54 4F.otf

よくある質問

ファイルのマジックナンバーとは何ですか?

ファイル先頭の数バイトで、名前が何であろうとその形式を示すものです。PNG は必ず 89 50 4E 47 で始まり、ZIP は 50 4B 03 04 で始まります。OS もブラウザも file コマンドも、拡張子を信用せずこのバイト列を読みます。だからファイル名を変えても中身の正体は変わりません。

マジックナンバーを自分で確認する方法は?

macOS や Linux なら xxd -l 16 ファイル名 で先頭 16 バイトが表示されます。Windows なら PowerShell で Format-Hex -Path ファイル名 -Count 16 です。あるいはこのサイトのファイル形式判別ツールにドロップすれば、ローカルでバイト列を読んで形式を教えてくれます。アップロードはありません。

2 つの形式が同じマジックナンバーを持つのはなぜ?

一方が他方の上に作られているからです。docx、xlsx、pptx、apk、jar、epub はすべて中身が ZIP アーカイブなので ZIP の署名で始まり、区別するには内部のエントリを見る必要があります。Java の class ファイルと macOS のユニバーサルバイナリはどちらも CA FE BA BE で始まり、直後のフィールドで見分けます。

マジックナンバーがまったくないファイルもある?

あります。XML、HTML、JSON、SVG、CSV といったテキストベースの形式には固定のバイト署名がないため、構造から判別します。先頭の <?xml 宣言、<svg 要素、あるいは { に続く引用符付きのキーなどです。これは確定ではなく推測なので、このリファレンスではそうした形式をプローブ判別として示しています。

マジックナンバーが一致すればそのファイルは安全?

いいえ。わかるのは形式であって、中身が無害かどうかではありません。正規の PDF や docx でも悪意のあるペイロードを含んでいることがあります。特に拡張子とバイト列が食い違うときに真の形式を知るのは有用な第一段階ですが、マルウェアスキャンではありません。

WOFF フォントかもしれないファイルをお持ちですか?ファイル形式判別ツールで調べる — マジックナンバーをローカルで読み取ります。アップロードは一切ありません。またはすべての形式を見る。