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; Unicode-only) | ✓ | ~ (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:
```text test outlineglyph276fromcff2 ... bench: 778 ns/iter (+/- 15) test fromdataotfcff ... bench: 760 ns/iter (+/- 13) test fromdataotfcff2 ... bench: 709 ns/iter (+/- 25) test outlineglyph276fromcff ... bench: 678 ns/iter (+/- 41) test outlineglyph276fromglyf ... bench: 649 ns/iter (+/- 11) test outlineglyph8fromcff2 ... bench: 476 ns/iter (+/- 14) test fromdatattf ... bench: 352 ns/iter (+/- 11) test glyphnamepost276 ... bench: 223 ns/iter (+/- 5) test outlineglyph8fromcff ... bench: 261 ns/iter (+/- 13) test outlineglyph8fromglyf ... bench: 281 ns/iter (+/- 5) test familyname ... bench: 183 ns/iter (+/- 102) test glyphnamecff276 ... bench: 109 ns/iter (+/- 1) test glyphindexu41 ... bench: 16 ns/iter (+/- 0) test glyphnamecff8 ... bench: 7 ns/iter (+/- 0) test glyphnamepost_8 ... bench: 2 ns/iter (+/- 0)
test subscriptmetrics ... bench: 2 ns/iter (+/- 0) test glyphhoradvance ... bench: 2 ns/iter (+/- 0) test glyphhorsidebearing ... bench: 2 ns/iter (+/- 0) test glyphname8 ... bench: 1 ns/iter (+/- 0) test ascender ... bench: 1 ns/iter (+/- 0) test underlinemetrics ... bench: 1 ns/iter (+/- 0) test strikeoutmetrics ... bench: 1 ns/iter (+/- 0) test xheight ... bench: 1 ns/iter (+/- 0) test unitsper_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.