How to how woff wraps ttf: a look under the hood
- Step 1Read the header — Bytes 0–3: signature 'wOFF'. 4–7: flavor (0x00010000 for TTF, 0x4F54544F for OTF). 8–11: total file length. 12–13: numTables. 14–15: reserved. 16–19: totalSfntSize (decompressed table data total). 20–43: version, metadata offsets, private offsets.
- Step 2Read the table directory — Each entry is 20 bytes: 4-byte tag, 4-byte offset to compressed data, 4-byte compressed length, 4-byte original length, 4-byte original checksum. Sorted by tag for spec compliance.
- Step 3Decompress each table — Compare compLength vs origLength. If they differ, run pako.inflate on the table bytes; if they match, the table is uncompressed (raw passthrough). Padded to 4-byte boundaries between tables.
Frequently asked questions
Why per-table compression instead of whole-file?+
Lets the browser parse the table directory without decompressing first, and means tables that don't compress well (loca, hmtx) can stay uncompressed. WOFF2 takes a different approach with whole-file Brotli plus glyf preprocessing — more efficient but more complex.
What's in the metadata block?+
Optional XML-formatted metadata: licensing info, vendor URLs, designer credits. Most browsers ignore it; some font managers display it. WOFF2 omits the metadata block entirely — the name table is the canonical source.
How is the WOFF directory different from sfnt?+
sfnt directory entries are 16 bytes (tag + checksum + offset + length). WOFF entries are 20 bytes — adds compLength so the browser knows how many compressed bytes to read before decompressing.
Can I corrupt a WOFF by re-saving it?+
If you don't update the directory entries to match the new compressed lengths, yes. Always re-emit the entire WOFF after modifying any table — never edit in place. The JAD WOFF tool does a full round-trip every time for this reason.
Privacy first
Every JAD Font tool runs entirely in your browser using opentype.js and the wawoff2 WASM Brotli encoder. Your fonts never leave your device — verified by zero outbound network requests during processing.