A font collection is a header followed by one ordinary table directory per font and the tables they point to. This page covers the header, its two versions, how tables are shared, and what changes for checksums and signatures in a collection. Everything else, the table directory and the tables themselves, is as in a single font: see the TTF table directory. All numbers are big-endian.
Header
The header is at byte 0. Version 1.0 was used for collections without a digital signature; version 2.0 adds three fields after the offsets, and can be used with or without a signature. Without one, the three fields are zero.
| Offset | Type | Name | Description |
|---|---|---|---|
0 | Tag | ttcTag | ttcf (74 74 63 66), for collections of any kind of outlines. |
4 | uint16 | majorVersion | 1 or 2. |
6 | uint16 | minorVersion | 0. |
8 | uint32 | numFonts | The number of fonts in the collection. |
12 | Offset32 × numFonts | tableDirectoryOffsets | For each font, where its table directory starts, from the start of the file. |
Version 2.0 only, straight after the offsets (at 12 + 4 × numFonts): | |||
+0 | uint32 | dsigTag | 0x44534947 (DSIG) if the collection is signed, otherwise 0. |
+4 | uint32 | dsigLength | The length of the DSIG table in bytes, or 0. |
+8 | uint32 | dsigOffset | Where the DSIG table starts, from the start of the file, or 0. |
So a version 1.0 header is 12 + 4 × numFonts bytes, and a version 2.0
header 24 + 4 × numFonts. The specification defines no other versions or
minor versions.
Table directories
- Each font in the collection has a complete table directory of its own, in exactly
the same format as at the start of a single font:
sfntVersion(0x00010000for TrueType outlines,OTTOfor CFF or CFF2),numTables, the three search fields and the sorted table records. - Every table offset in every directory counts from the start of the collection file, not from the start of that font’s directory.
- A font is chosen by its index in
tableDirectoryOffsets, starting at 0. Software that opens a collection usually shows each font separately, by the names in its ownnametable. - Fonts in one collection may have different kinds of outlines, layout tables or not, and may include one or more variable fonts.
Checksums and signatures
- Table checksums in each directory must match the tables as they are in the collection file. They are worked out as for a single font; see checksums.
- The
checksumAdjustmentfield in eachheadtable is not used in a collection and may be 0. - A signed collection needs a version 2.0 header. The
DSIGtable must be the last thing in the file, after every other table, and is found through the header’sdsigOffset, not through any font’s table directory. Signatures in a collection are expected to be format 1 (PKCS#7).
Example
The start of ArialHB.ttc, the Arial Hebrew collection that comes with
macOS (188,236 bytes):
00000000 74 74 63 66 00 02 00 00 00 00 00 09 00 00 00 3C ttcf...........<
00000010 00 00 01 88 00 00 02 D4 00 00 04 20 00 00 05 6C ........... ...l
00000020 00 00 06 B8 00 00 08 04 00 00 09 50 00 00 0A 9C ...........P....
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 ................
| Offset | Bytes | Field | Value |
|---|---|---|---|
0 | 74 74 63 66 | ttcTag | ttcf |
4 | 00 02 00 00 | majorVersion, minorVersion | 2.0 |
8 | 00 00 00 09 | numFonts | 9 fonts |
12 | 9 × 4 bytes | tableDirectoryOffsets | 60, 392, 724, 1,056, 1,388, 1,720, 2,052, 2,384, 2,716 |
48 | 12 zero bytes | dsigTag, dsigLength, dsigOffset | Not signed |
60 | 00 01 00 00 … | First table directory | TrueType outlines |
The header is 24 + 4 × 9 = 60 bytes, so the first directory starts at 60. Each
directory has 20 tables (00 14), so it is 12 + 20 × 16 = 332 bytes, and the
directories follow one another 332 bytes apart. Comparing the first two fonts’
records shows what they share:
| Tag | Font 0 offset | Font 1 offset | Shared |
|---|---|---|---|
GDEF | 177,552 | 177,552 | Yes |
GSUB | 177,684 | 177,684 | Yes |
cmap | 178,452 | 178,452 | Yes |
morx | 179,412 | 179,412 | Yes |
prep | 178,416 | 178,416 | Yes |
GPOS | 57,272 | 49,884 | No |
glyf | 131,616 | 119,088 | No |
head | 3,156 | 3,324 | No |
name | 13,608 | 9,284 | No |
Here the two fonts have different outlines, so glyf is not shared,
but the character map, the substitution rules and Apple’s
morx table are stored once.