# fontdue: pure Rust font rasterization without std

> fontdue parses TrueType and OpenType fonts, rasterizes glyphs, and performs basic layout in a no_std Rust environment. It is a good fit for latency-sensitive rendering, but its lack of shaping and immature layout API narrow where it can replace a full text engine.

**mooman219/fontdue** — The fastest font renderer in the world, written in pure rust.

- Repository: https://github.com/mooman219/fontdue
- Stars: 1,712 · Forks: 89
- Language: Rust
- License: Apache-2.0
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/mooman219-fontdue

## Why fontdue targets embedded and interactive Rust rendering

fontdue addresses the part of text rendering that occurs after an application has font data but before it has pixels. It supports TrueType `.ttf` and `.ttc` files and OpenType `.otf` files, converts a font into an in-memory representation, calculates glyph metrics, and rasterizes a requested glyph at a requested size. The intended audience is Rust developers working on graphical interfaces, games, custom renderers, or other systems where avoiding `std` and controlling the font rendering path matter.

The crate describes itself as pure Rust and `no_std`. That does not mean it performs no dynamic allocation. Its documentation explicitly rejects allocation-free loading as a non-goal, states that it depends on `alloc`, and explains that a font is fully parsed when it is created. The parsed structures own their storage, which avoids lifetime dependencies on the original font bytes but transfers allocation and parse-time costs to font creation.

This distinction affects the adoption decision. fontdue can fit environments that avoid the Rust standard library, but it is not a zero-allocation parser. An application that loads fonts dynamically and must avoid heap growth should account for that behavior rather than assuming that `no_std` implies fixed memory use. The README also places strong emphasis on low end-to-end latency, although its benchmark pages do not include the numerical data needed to compare it with another crate independently.

## Inside fontdue's parse, rasterize, and layout pipeline

The first stage is `Font::from_bytes`. Fontdue delegates font parsing to `ttf-parser`, configured through the `opentype-layout` and `no-std-float` features. After parsing, fontdue retains font information in a format intended for repeated access. Because it allocates its own storage, the resulting `Font` value has no lifetime parameter tied to the input byte slice. That is useful when a renderer owns several faces and does not want every font structure to preserve the lifetime of its source buffer.

For rasterization, `Font::rasterize` takes a character and a pixel size, then returns two products: layout metrics and a bitmap. Metrics describe how the rendered glyph should be positioned and integrated into a line. The bitmap contains the rasterized mask. This direct character-oriented API is the more established part of the crate, and the README says that the rasterization API is not expected to change substantially in the near future.

Layout is a separate stage. `Layout::new` receives a `CoordinateSystem`, `reset` applies `LayoutSettings`, and `append` adds styled text through `TextStyle`. The resulting glyphs can be read with `glyphs`. Reusing a layout context reduces repeated heap allocation, according to the README. Styles can also carry a user metadata type, and all styles passed to one `Layout` must use the same metadata type.

The central limitation is visible in the architecture: fontdue is not a shaping library. It can resolve characters, calculate metrics, produce bitmaps, and arrange text, but it does not provide the script-specific shaping layer needed by the README's recommended alternative, Cosmic Text. Applications dealing with complex scripts should treat fontdue as a rendering component rather than as the complete text engine.

## Using the documented rasterization API for a first glyph

The README does not provide a package installation command or a dependency snippet. It directs readers to the `fontdue` crate on Crates.io and to the documentation at `https://docs.rs/fontdue`. The repository identifies version `0.9.4` in `Cargo.toml`, but it does not show which version an integrating project should pin, so that choice must be made against the published crate metadata rather than guessed here.

The following first use follows the README's rasterization example. It compiles a font into the binary, parses it with `FontSettings::default()`, then requests metrics and a bitmap for `g` at `17.0` pixels. The `.unwrap()` means the example will panic if parsing fails, which is acceptable for the documentation example but should be handled explicitly in production code.

```rust
let font = include_bytes!("../resources/Roboto-Regular.ttf") as &[u8];
let font = fontdue::Font::from_bytes(font, fontdue::FontSettings::default()).unwrap();
let (metrics, bitmap) = font.rasterize('g', 17.0);
```

A successful call produces the bitmap for the requested character and size. The example does not print either value, so the repository does not define a particular expected console output. The referenced `Roboto-Regular.ttf` is stored under `dev/examples/resources`, based on the example paths. Additional examples are located under `dev/examples`; those files are excluded from the published package according to `Cargo.toml`, so they should be viewed in the repository rather than assumed to ship in the crate.

## Fontdue layout behavior and its no_std feature choices

The layout example creates a font collection, initializes `Layout` with `CoordinateSystem::PositiveYUp`, and appends two styles. It then reads the generated glyphs. Calling `reset` with `LayoutSettings::default()` is shown as redundant because a new layout already has default settings, but the example includes it to demonstrate customization.

```rust
let fonts = &[roboto_regular];
let mut layout = Layout::new(CoordinateSystem::PositiveYUp);
layout.reset(&LayoutSettings {
    ..LayoutSettings::default()
});
layout.append(fonts, &TextStyle::new("Hello ", 35.0, 0));
layout.append(fonts, &TextStyle::new("world!", 40.0, 0));
println!("{:?}", layout.glyphs());
```

The README calls this layout naïve and says it is only intended to be comparable to libraries such as `glyph_brush`. More importantly, it labels the API immature and warns of possible breaking changes. That warning should influence version planning because callers may face source changes when upgrading.

Feature selection adds another constraint. Default features are `simd` and `hashbrown`. The `std` feature substitutes `std::HashMap` for `hashbrown::HashMap`. The `simd` feature enables SIMD usage on x86 and x86_64, while `parallel` adds `rayon`, enables `hashbrown`, and enables `hashbrown/rayon` for parallel font loading. With no default features enabled, the project requires either `hashbrown` or `std`. Applications targeting non-x86 hardware should verify whether the default SIMD selection is appropriate for their build configuration.

## fontdue's performance claim and reproducible comparison limits

The README says fontdue is designed for low end-to-end latency and claims the lowest current end-to-end latency for a font rasterizer. It also publishes graphs for TrueType glyf rasterization, CFF rasterization, and layout of Latin text with word-boundary wrapping. Those are the project's documented comparison targets.

The README embeds graph images but no tabulated values, hardware configuration, crate versions for competitors, compiler settings, or complete benchmark commands. Consequently, the article cannot reproduce the claim or state a specific margin over `rusttype`, `ab_glyph`, `glyph_brush`, or another renderer. The repository has no GitHub releases, so there is no release entry from which to infer recent performance changes or upgrade notes.

Engineers evaluating fontdue for interactive rendering should compare the complete operation rather than bitmap generation alone. Font parsing, glyph lookup, shaping outside the crate, cache behavior, and integration with the destination surface all affect end-to-end latency. The README's graphs can establish which scenarios the project chose to measure, but they do not establish how the library performs on an application's fonts, processors, text sizes, or rendering framework.

## Maintenance, licensing, and the boundary with Cosmic Text

The repository is not archived, and its last push was on 2026-07-29. The README separately warns that fontdue is a solo project and that the maintainer has limited time. Bug fixes are described as a priority. The repository has no GitHub releases, so release cadence cannot be inferred from release tags or announcements. Upgrade planning should account for the documented immaturity of layout and possible breaking changes rather than assuming every API follows a formal release schedule.

The repository includes `LICENSE-APACHE`, `LICENSE-MIT`, and `LICENSE-ZLIB`. Its README says users may choose any one of Apache License 2.0, MIT, or Zlib. `Cargo.toml` records the combined expression `MIT OR Apache-2.0 OR Zlib`. Contributions are multi-licensed under those choices unless a contributor explicitly states otherwise. This is a licensing notice rather than legal advice; downstream projects still need to preserve applicable notices and follow the selected license terms.

Cosmic Text is the clearest documented alternative. The README calls it a more complete pure Rust text library and recommends it when shaping is needed. Its difference is architectural: Cosmic Text covers the text-processing layer that fontdue deliberately leaves out. fontdue instead concentrates on parsing, rasterization, metrics, and basic layout through a compact crate with `no_std` support. That makes it appropriate for a narrow renderer and unsuitable as a stand-alone solution for complex script shaping.

## Conclusion

Adopt fontdue when a Rust application needs direct TrueType or OpenType rasterization, no_std support, or a small path from font bytes to glyph bitmaps. Do not choose it for scripts that require shaping, or when a stable advanced layout API is a primary requirement. Verify glyph handling for your font set, the allocation budget at load time, and whether your required Rust features remain compatible with your platform before integration.

## FAQ

### Does fontdue support no_std Rust?

Yes. fontdue is documented as a `no_std` crate, but it still depends on `alloc` and performs allocations while parsing fonts. With default features disabled, either `hashbrown` or `std` must be enabled.

### Does fontdue provide font shaping?

No. The README explicitly says fontdue is a class of font libraries that does not tackle shaping. It points applications needing a more complete text engine to Cosmic Text.

### Can fontdue load fonts in parallel?

Yes, through its optional `parallel` feature. That feature enables `rayon`, `hashbrown`, and `hashbrown/rayon` for parallel font loading.

## Sources

- [Issues](https://github.com/mooman219/fontdue/issues)
- [License: Apache-2.0](https://github.com/mooman219/fontdue/blob/master/LICENSE)
- [mooman219/fontdue on GitHub](https://github.com/mooman219/fontdue)
- [README](https://github.com/mooman219/fontdue/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/mooman219-fontdue
