A high-level, safe, zero-allocation font parser for TrueType, OpenType, and AAT.
Can be used as a Rust or C library.
no_std
/WASM compatible.It's very hard to compare different libraries, so we are using table-based comparison. There are roughly three types of TrueType tables:
head
, OS/2
, etc.).glyf
, CFF
(kinda), hmtx
, etc.).cmap
, kern
, GPOS
, etc.).Feature/Library | ttf-parser | FreeType | stb_truetype |
---|---|---|---|
Memory safe | ✓ | ||
Thread safe | ✓ | ~ (mostly reentrant) | |
Zero allocation | ✓ | ||
Variable fonts | ✓ | ✓ | |
Rendering | -1 | ✓ | ~ (very primitive) |
ankr table |
✓ | ||
avar table |
✓ | ✓ | |
bdat table |
~ (no 4) | ✓ | |
bloc table |
✓ | ✓ | |
CBDT table |
~ (no 8, 9) | ✓ | |
CBLC table |
✓ | ✓ | |
COLR table |
✓ | ✓ | |
CPAL table |
✓ | ✓ | |
CFF table |
✓ | ✓ | ~ (no seac support) |
CFF2 table |
✓ | ✓ | |
cmap table |
~ (no 8) | ✓ | ~ (no 2,8,10,14; Unicode-only) |
EBDT table |
~ (no 8, 9) | ✓ | |
EBLC table |
✓ | ✓ | |
feat table |
✓ | ||
fvar table |
✓ | ✓ | |
gasp table |
✓ | ||
GDEF table |
~ | ||
glyf table |
~2 | ✓ | ~2 |
GPOS table |
✓ | ~ (only 2) | |
GSUB table |
✓ | ||
gvar table |
✓ | ✓ | |
head table |
✓ | ✓ | ✓ |
hhea table |
✓ | ✓ | ✓ |
hmtx table |
✓ | ✓ | ✓ |
HVAR table |
✓ | ✓ | |
kern table |
✓ | ~ (only 0) | ~ (only 0) |
kerx table |
✓ | ||
MATH table |
✓ | ||
maxp table |
✓ | ✓ | ✓ |
morx table |
✓ | ||
MVAR table |
✓ | ✓ | |
name table |
✓ | ✓ | |
OS/2 table |
✓ | ✓ | |
post table |
✓ | ✓ | |
sbix table |
~ (PNG only) | ~ (PNG only) | |
STAT table |
✓ | ||
SVG table |
✓ | ✓ | ✓ |
trak table |
✓ | ||
vhea table |
✓ | ✓ | |
vmtx table |
✓ | ✓ | |
VORG table |
✓ | ✓ | |
VVAR table |
✓ | ✓ | |
Language | Rust + C API | C | C |
Tested version | 0.17.0 | 2.12.0 | 1.24 |
License | MIT / Apache-2.0 | FTL / GPLv2 | public domain |
Legend:
Notes:
ttf-parser
doesn't support rendering by itself,
there are multiple rendering libraries on top of it:
rusttype,
ab-glyph
and fontdue.TrueType fonts designed for fast querying, so most of the methods are very fast. The main exception is glyph outlining. Glyphs can be stored using two different methods: using Glyph Data Format and Compact Font Format (pdf). The first one is fairly simple which makes it faster to process. The second one is basically a tiny language with a stack-based VM, which makes it way harder to process.
The benchmark tests how long it takes to outline all glyphs in a font.
x86 (AMD 3700X)
Table/Library | ttf-parser | FreeType | stb_truetype |
---|---|---|---|
glyf |
0.901 ms |
1.171 ms |
0.675 ms |
gvar |
2.972 ms |
4.132 ms |
- |
CFF |
1.197 ms |
5.647 ms |
2.813 ms |
CFF2 |
1.968 ms |
6.392 ms |
- |
ARM (Apple M1)
Table/Library | ttf-parser | FreeType | stb_truetype |
---|---|---|---|
glyf |
0.550 ms |
0.854 ms |
0.703 ms |
gvar |
2.270 ms |
4.594 ms |
- |
CFF |
1.054 ms |
5.223 ms |
3.262 ms |
CFF2 |
1.765 ms |
5.995 ms |
- |
Note: FreeType is surprisingly slow, so I'm worried that I've messed something up.
And here are some methods benchmarks:
test outline_glyph_276_from_cff2 ... bench: 867 ns/iter (+/- 15)
test from_data_otf_cff ... bench: 968 ns/iter (+/- 13)
test from_data_otf_cff2 ... bench: 887 ns/iter (+/- 25)
test outline_glyph_276_from_cff ... bench: 678 ns/iter (+/- 41)
test outline_glyph_276_from_glyf ... bench: 649 ns/iter (+/- 11)
test outline_glyph_8_from_cff2 ... bench: 534 ns/iter (+/- 14)
test from_data_ttf ... bench: 467 ns/iter (+/- 11)
test glyph_name_post_276 ... bench: 223 ns/iter (+/- 5)
test outline_glyph_8_from_cff ... bench: 315 ns/iter (+/- 13)
test outline_glyph_8_from_glyf ... bench: 291 ns/iter (+/- 5)
test family_name ... bench: 183 ns/iter (+/- 102)
test glyph_name_cff_276 ... bench: 62 ns/iter (+/- 1)
test glyph_index_u41 ... bench: 16 ns/iter (+/- 0)
test glyph_name_cff_8 ... bench: 5 ns/iter (+/- 0)
test glyph_name_post_8 ... bench: 2 ns/iter (+/- 0)
test subscript_metrics ... bench: 2 ns/iter (+/- 0)
test glyph_hor_advance ... bench: 2 ns/iter (+/- 0)
test glyph_hor_side_bearing ... bench: 2 ns/iter (+/- 0)
test glyph_name_8 ... bench: 1 ns/iter (+/- 0)
test ascender ... bench: 1 ns/iter (+/- 0)
test underline_metrics ... bench: 1 ns/iter (+/- 0)
test strikeout_metrics ... bench: 1 ns/iter (+/- 0)
test x_height ... bench: 1 ns/iter (+/- 0)
test units_per_em ... bench: 0.5 ns/iter (+/- 0)
test width ... bench: 0.2 ns/iter (+/- 0)
Licensed under either of
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.