A high-level, safe, zero-allocation TrueType font parser.
Can be used as Rust and as 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 | ✓ | ~ (very primitive) | |
avar table | ✓ | ✓ | |
bdat table | ✓ | ||
bloc table | ✓ | ||
CBDT table | ✓ | ✓ | |
CBLC table | ✓ | ✓ | |
CFF table | ✓ | ✓ | ~ (no seac support) |
CFF2 table | ✓ | ✓ | |
cmap table | ~ (no 8) | ✓ | ~ (no 2,8,10,14; Unicode-only) |
EBDT table | ✓ | ||
EBLC table | ✓ | ||
fvar table | ✓ | ✓ | |
gasp table | ✓ | ||
GDEF table | ~ | ||
glyf table | ~1 | ✓ | ~1 |
GPOS table | ~ (only 2) | ||
GSUB table | |||
gvar table | ✓ | ✓ | |
head table | ✓ | ✓ | ✓ |
hhea table | ✓ | ✓ | ✓ |
hmtx table | ✓ | ✓ | ✓ |
HVAR table | ✓ | ✓ | |
kern table | ✓ | ~ (only 0) | ~ (only 0) |
maxp table | ✓ | ✓ | ✓ |
MVAR table | ✓ | ✓ | |
name table | ✓ | ✓ | |
OS/2 table | ✓ | ✓ | |
post table | ✓ | ✓ | |
sbix table | ~ (PNG only) | ~ (PNG only) | |
SVG table | ✓ | ✓ | |
vhea table | ✓ | ✓ | |
vmtx table | ✓ | ✓ | |
VORG table | ✓ | ✓ | |
VVAR table | ✓ | ✓ | |
Language | Rust + C API | C | C |
Dynamic lib size | <300KiB2 | ~760KiB3 | ? (header-only) |
Tested version | 0.8.0 | 2.9.1 | 1.24 |
License | MIT / Apache-2.0 | FTL / GPLv2 | public domain |
Legend:
Notes:
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 the font.
Table/Library | ttf-parser | FreeType | stb_truetype |
---|---|---|---|
glyf | 0.835 ms | 1.194 ms | 0.695 ms |
gvar | 3.158 ms | 3.594 ms | - |
CFF | 1.114 ms | 5.946 ms | 2.862 ms |
CFF2 | 1.763 ms | 7.001 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: 778 ns/iter (+/- 15) test from_data_otf_cff ... bench: 760 ns/iter (+/- 13) test from_data_otf_cff2 ... bench: 709 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: 476 ns/iter (+/- 14) test from_data_ttf ... bench: 352 ns/iter (+/- 11) test glyph_name_post_276 ... bench: 223 ns/iter (+/- 5) test outline_glyph_8_from_cff ... bench: 261 ns/iter (+/- 13) test outline_glyph_8_from_glyf ... bench: 281 ns/iter (+/- 5) test family_name ... bench: 183 ns/iter (+/- 102) test glyph_name_cff_276 ... bench: 109 ns/iter (+/- 1) test glyph_index_u41 ... bench: 16 ns/iter (+/- 0) test glyph_name_cff_8 ... bench: 7 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.