Typf is a modular text rendering library with a three-stage pipeline: Shaping → Rendering → Export.
┌─────────────────────────────────────────────────────┐
│ Pipeline │
└─────────────────────────────────────────────────────┘
│
┌──────────────────────────────────┼──────────────────────────────────┐
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Shaper │ │ Renderer │ │ Exporter │
│ │ │ │ │ │
│ text → glyphs │ ────▶ │ glyphs → pixels │ ────▶ │ pixels → file │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
┌────┴────┐ ┌────────┼────────┐ ┌─────┴─────┐
│ │ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼ ▼
HarfBuzz ICU+HB Opixa Skia Zeno SVG PNG SVG
(hb) (icu-hb) (opixa) (skia) (zeno) (svg) (png) (svg)
Central types and traits that all components share:
Pipeline: Chains shaper → renderer → exporterShapertrait: Text → positioned glyphsRenderertrait: Glyphs → pixels or vectorsExportertrait: Pixels/vectors → file bytesFontReftrait: Abstraction over font data accessShapingParams: Font size, features, variations, languageRenderParams: Colors, padding, antialiasing, output modeShapingResult: Positioned glyphs with metricsRenderOutput: Bitmap or vector data
Loads fonts from files or memory with:
- TrueType Collection (TTC) face index support
- On-demand
FontRefcreation (no memory leaks) - Units-per-em and glyph metrics access
Unicode processing for complex scripts:
- Bidirectional text (Arabic, Hebrew)
- Script detection and segmentation
- Cluster boundaries
Converts rendered output to file formats:
- PNG export with proper IHDR/IDAT/IEND
- Format validation and error handling
Shapers transform text into positioned glyphs, applying OpenType features and script rules.
| Backend | Crate | Description |
|---|---|---|
| HarfBuzz | typf-shape-hb |
Industry-standard shaper via harfbuzz-rs |
| HarfBuzz Rust | typf-shape-hr |
Pure Rust HarfBuzz alternative via harfrust |
| ICU+HarfBuzz | typf-shape-icu-hb |
HarfBuzz with ICU for enhanced Unicode |
| CoreText | typf-shape-ct |
macOS native shaping |
| None | typf-shape-none |
Pass-through (testing only) |
All shapers support:
- OpenType features (
liga,kern,smcp, etc.) - Variable font axes (
wght,wdth, etc.) - Script/language tags
- Bidirectional text
- Shaping cache for repeated text
Renderers convert positioned glyphs into visual output.
| Backend | Crate | Output | Color Glyphs | Description |
|---|---|---|---|---|
| Opixa | typf-render-opixa |
Bitmap | ❌ | Pure Rust, high-quality antialiasing, SIMD |
| Skia | typf-render-skia |
Bitmap | ✅ COLR/SVG/bitmap | Uses tiny-skia for path rendering |
| Zeno | typf-render-zeno |
Bitmap | ✅ COLR/SVG/bitmap | Pure Rust, zeno rasterizer |
| SVG | typf-render-svg |
Vector | ❌ | Scalable vector output |
| JSON | typf-render-json |
Data | ❌ | Glyph data for debugging |
| CoreGraphics | typf-render-cg |
Bitmap | macOS native rendering | |
| Color | typf-render-color |
Bitmap | ✅ All | Color glyph support (COLR/CPAL/SVG/bitmap) |
All raster renderers share:
- Canvas sizing from actual glyph bounds (ascent/descent/bbox)
- 32-bit glyph ID support (>65k glyphs)
- Foreground/background colors
- Configurable padding
- Antialiasing options
The SVG renderer additionally supports:
- Variable font variations
- Perfect scaling (vector output)
The skia and zeno renderers support color glyphs via typf-render-color:
For each glyph in ShapingResult:
1. Check GlyphSourcePreference order
2. Try color sources first (if allowed):
- COLR v1: skrifa ColorPainter → gradients, transforms, compositing
- COLR v0: skrifa ColorPainter → layered solid colors
- SVG: resvg → parse and rasterize SVG document
- Bitmap: decode sbix/CBDT/EBDT PNG/bitmap data
3. If no color glyph found, fall back to outline (glyf/CFF/CFF2)
4. Composite onto canvas with proper positioning
GlyphSource priority order (default):
glyf/cff/cff2— outline sources (first match)colr1— COLR v1 with gradientscolr0— COLR v0 layered colorssvg— SVG table glyphssbix/cbdt/ebdt— bitmap sources
Use --glyph-source prefer=X,Y to customize priority or --glyph-source deny=X to disable sources.
1. Input
└─► "Hello مرحبا" + font.ttf + params
2. Shaping (HarfBuzz)
├─► Bidi analysis: [LTR: "Hello "] [RTL: "مرحبا"]
├─► Cluster mapping: H→glyph72, e→glyph68, ...
├─► OpenType features: ligatures, kerning
└─► ShapingResult: [{id:72, x:0, y:0}, {id:68, x:12, y:0}, ...]
3. Rendering (Opixa)
├─► Load glyph outlines from font
├─► Calculate canvas from actual bounds
├─► Rasterize with antialiasing
└─► RenderOutput::Bitmap { width, height, data }
4. Export (PNG)
├─► Encode bitmap as PNG
└─► Vec<u8> ready to write
ShapingParams {
size: 24.0, // Font size in pixels
language: Some("ar".into()), // Language tag
script: Some("arab".into()), // Script tag
features: vec![("liga".into(), 1)], // OpenType features
variations: vec![("wght".into(), 700.0)], // Variable font axes
direction: Direction::Auto, // Text direction
letter_spacing: 0.0, // Extra spacing
}RenderParams {
foreground: Color::black(), // Text color
background: Some(Color::white()), // Canvas color
padding: 10, // Pixels around text
antialias: true, // Smooth edges
variations: vec![("wght".into(), 700.0)], // For SVG renderer
color_palette: 0, // CPAL palette index
glyph_sources: GlyphSourcePreference::default(), // Outline-first glyph source order
output: RenderMode::Bitmap, // Vector: RenderMode::Vector(VectorFormat::Svg)
}| Feature | macOS | Linux | Windows |
|---|---|---|---|
| HarfBuzz shaping | ✓ | ✓ | ✓ |
| CoreText shaping | ✓ | - | - |
| Opixa rendering | ✓ | ✓ | ✓ |
| Skia rendering | ✓ | ✓ | ✓ |
| CoreGraphics rendering | ✓ | - | - |
| System font discovery | ✓ | ✓ | ✓ |
Typf uses the Moka TinyLFU caching system for optimal performance:
- Key: text + font ID + size + features + variations + language + script
- Value:
ShapingResult(positioned glyphs) - TinyLFU admission tracks frequency of both hits AND misses
- 10-minute time-to-idle prevents memory leaks
- Scan-resistant architecture optimized for font matching workloads
- Key: font ID + glyph ID + size + render params
- Value: rasterized bitmap or mesh data
- Per-renderer implementation with shared interface
- Configurable capacity with automatic eviction
// Prevents cache interference between tests
cache_config::scoped_caching_enabled(|| {
// Test code with isolated caching
});All operations return Result<T, TypfError>:
pub enum TypfError {
FontError(FontError), // Font loading/parsing
ShapingError(ShapingError), // Text shaping
RenderError(RenderError), // Rasterization
ExportError(ExportError), // File encoding
ConfigError(String), // Invalid configuration
}# Render text to PNG
typf render -f font.ttf -t "Hello" -o hello.png
# Get font info
typf info -f font.ttf --shapers --renderers
# Batch processing
typf batch -c config.jsonimport typf
# Simple rendering
png_data = typf.render_simple("Hello", font_path, size=24)
# With full control
result = typf.render(
text="Hello",
font=font_path,
size=24,
features={"liga": 1},
variations={"wght": 700},
)- README.md — Getting started
- CONTRIBUTING.md — Development guide
- API Documentation — Crate docs