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 | -1 | ✓ | ~ (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 | ~2 | ✓ | ~2 |
| GPOS
table | ✓ | | ~ (only 2) |
| GSUB
table | ✓ | | |
| gvar
table | ✓ | ✓ | |
| head
table | ✓ | ✓ | ✓ |
| hhea
table | ✓ | ✓ | ✓ |
| hmtx
table | ✓ | ✓ | ✓ |
| HVAR
table | ✓ | ✓ | |
| kern
table | ~ (no AAT 1) | ~ (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 |
| Tested version | 0.13.0 | 2.10.4 | 1.24 |
| License | MIT / Apache-2.0 | FTL / GPLv2 | public domain |
Legend:
Notes:
ttf-parser
doesn't support rendering by itself,
there are mutliple 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 the font.
| Table/Library | ttf-parser | FreeType | stb_truetype |
| ------------- | -------------: | ---------: | -------------: |
| glyf
| 0.915 ms
| 1.258 ms
| 0.718 ms
|
| gvar
| 3.545 ms
| 4.288 ms
| - |
| CFF
| 1.365 ms
| 5.992 ms
| 2.836 ms
|
| CFF2
| 1.982 ms
| 6.859 ms
| - |
Note: FreeType is surprisingly slow, so I'm worried that I've messed something up.
And here are some methods benchmarks:
text
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.