Parse a Font

Parsing TrueType (TTF) Font Files

A practical, implementation-agnostic guide to reading the TTF binary format. This page covers the mental model and parse order; the byte-level field layouts for every table live on the compact reference — TTF Byte Layout Reference.

Contents

  1. Introduction
  2. Mental model
  3. Parse order
  4. Byte layouts

↑ Contents

1. Introduction

The goal is to take a .ttf file as a flat array of bytes and turn it into structured data — the font header, the glyph outlines, the metrics, the character map. This document covers how to do that: the file’s shape, the order to read things in, and how to move the read cursor through the bytes.


↑ Contents

2. Mental model

A TTF file is not a document you read front to back. It is a small archive (the format is called “sfnt” — scalable font). Its bytes are organized as:

  1. A 12-byte offset table (the sfnt header): what kind of font this is and how many tables it holds.
  2. A table directory: one fixed-size record per table, each saying “the table with this tag lives at this byte offset and is this long.”
  3. The table data, located only by the offsets in the directory.

The crucial consequence: you never assume where anything is. You read a table’s offset and length from the directory, then jump there.

It helps to know what the tables are for before parsing them. This is how a character becomes a drawn glyph:

character code ──(cmap)──► glyph index ──(loca)──► glyf  (the outline)
                                        └─(hmtx)──► advance width (the spacing)

head and maxp are the configuration that makes loca interpretable. This chain is also why the parse order in section 3 is what it is.


↑ Contents

3. Parse order

Where a table sits (physical) is independent of when you decode it (logical). Decode order is forced by data dependencies:

  1. Offset table — Read the first 12 bytes; capture numTables.
  2. Table directory — Read numTables × 16 bytes into a tag → (offset, length) map. After this, switch from linear reading to seeking by offset.
  3. head — Yields unitsPerEm, indexToLocFormat, the font bounding box.
  4. maxp — Yields numGlyphs.
  5. hhea — Yields numberOfHMetrics.
  6. hmtx — Needs numberOfHMetrics (hhea) and numGlyphs (maxp).
  7. loca — Needs indexToLocFormat (head) and numGlyphs (maxp).
  8. glyf — Needs loca to bracket each glyph.
  9. cmap — Independent; the character → glyph map.
  10. name, post, OS/2, kern — Independent / optional; parse as needed.

Validate as you go. sfntVersion is a known value; head.magicNumber == 0x5F0F3CF5; every offset + length stays within the file; the last loca entry equals the glyf table length.


↑ Contents

4. Byte layouts

For offset-by-offset field layouts of every table — big-endian, all field types, every table — see the TTF Byte Layout Reference. It is organized as quick-lookup tables for every table in the font.