Skip to main content

High-performance, multi-backend text rendering for Python and Rust

Project description

TYPF: Modern Font Rendering Engine

Production-ready, cross-platform font rendering with Rust performance and Python convenience

Status Language Python

For overall project coordination: See root README.md | PLAN.md | TODO.md


What is TYPF?

TYPF is a modern, cross-platform font rendering engine providing unified text layout and rasterization. It's built in Rust for performance and safety, with Python bindings for ease of use.

Key Design Goals:

  • Performance: Sub-millisecond rendering, lock-free concurrency, zero-copy font loading
  • Correctness: Pixel-perfect output, comprehensive testing, fuzzing-ready
  • Cross-Platform: Native backends for macOS (CoreText), Windows (DirectWrite), Linux (HarfBuzz)
  • Flexible Output: PNG, SVG, NumPy arrays, PGM, raw bitmaps

Features

Core Capabilities

Multiple Shaping Backends

  • CoreText (macOS native)
  • DirectWrite (Windows native)
  • ICU + HarfBuzz (cross-platform fallback)
  • Automatic backend selection based on platform

Multiple Rasterizers

  • orge - Custom CPU rasterizer (F26Dot6 fixed-point, scan conversion)
  • tiny-skia - Vector renderer (feature-gated)
  • zeno - Alternative rasterizer (feature-gated)

Modern Font Stack

  • Built exclusively on skrifa + read-fonts
  • Full OpenType support (TTF, CFF, CFF2)
  • Variable font support (wght, wdth, and all registered axes)
  • Named instance support

Output Formats

  • PNG (via resvg + png crate)
  • SVG paths with kurbo
  • NumPy arrays (Python bindings)
  • PGM (P5 format)
  • Raw RGBA/BGRA bitmaps

Advanced Features

  • COLRv1/CPAL color font support
  • Gradients and clip paths
  • Complex script shaping (Arabic, Devanagari, CJK)
  • Bidirectional text (via unicode_bidi)
  • Text segmentation (ICU-based)

Architecture

Project Structure

typf/
├── backends/               # Platform-specific rendering
│   ├── typf-core/         # Shared traits, types, caching (1,086 lines)
│   ├── typf-icu-hb/       # HarfBuzz+ICU backend (~2,000 lines)
│   ├── typf-orge/         # Custom rasterizer (~500 lines)
│   ├── typf-mac/          # CoreText backend (~800 lines)
│   ├── typf-win/          # DirectWrite backend (~1,000 lines)
│   ├── typf-pure/         # Minimal pure-Rust fallback (~350 lines)
│   └── typf-zeno/         # Zeno rasterizer (~200 lines)
├── crates/                # Modular components
│   ├── typf-api/          # Public API facade
│   ├── typf-batch/        # Batch job processing
│   ├── typf-fontdb/       # Font discovery & loading
│   ├── typf-render/       # Output utilities (SVG/PNG)
│   ├── typf-shaping/      # Shaping helpers
│   └── typf-unicode/      # Text segmentation
├── python/                # PyO3 bindings
│   ├── src/lib.rs         # Rust FFI layer
│   └── typf/              # Python wrapper
├── typf-cli/              # Command-line tool
├── tests/                 # Integration tests
└── examples/              # Rust & Python examples

Backend Comparison

Backend Platform Performance Completeness Use Case
CoreText macOS Excellent ✅ Full macOS primary
DirectWrite Windows Excellent ✅ Full Windows primary
HarfBuzz+ICU All Good ✅ Full Cross-platform fallback
orge All Excellent* ⚠️ Partial Custom rasterization (in progress)
tiny-skia All Good ✅ Full Vector rendering (feature-gated)
zeno All Good ⚠️ Partial Alternative rasterizer
pure All Basic ⚠️ Minimal WASM compatibility fallback

*orge core algorithm complete; backend integration pending

Caching Architecture

Three-Layer Caching:

  1. Backend Font Cache (Per-backend, LRU)

    • CoreText: CTFont instances (64-128 capacity)
    • DirectWrite: IDWriteFont objects (64-128 capacity)
    • HarfBuzz: hb_face_t objects (64-128 capacity)
  2. Shape Result Cache (Global, Multi-Shard)

    • Implementation: 16-shard DashMap + per-shard LRU
    • Key: (text, font_key, size, features)
    • Benefit: Eliminates lock contention on concurrent workloads
    • Capacity: Configurable (1,000-10,000 entries typical)
  3. System Font Database (Global, OnceCell)

    • Location: typf-fontdb
    • DashMap-backed for thread-safe lookups
    • Loads system fonts + custom directories once

Memory Management:

  • Arc-based shared ownership for font data
  • memmap2 for file-backed zero-copy loading
  • Mmap kept alive via FontKey references
  • Explicit clear_cache() methods on all backends

Installation

From Source

Prerequisites:

  • Rust 1.70+ (rustup install stable)
  • Python 3.12+ (for Python bindings)
  • Platform-specific dependencies:
    • macOS: Xcode command-line tools
    • Windows: Visual Studio Build Tools
    • Linux: HarfBuzz + FreeType development packages

Rust Library:

cd github.fontlaborg/typf
cargo build --release --workspace
cargo test --workspace --all-features  # Run tests

Python Bindings:

⚠️ Important: Python bindings MUST be built inside an active virtual environment. System Python builds will fail with linker errors.

# 1. Create and activate virtual environment
cd github.fontlaborg/typf
uv venv --python 3.12      # or: python3.12 -m venv .venv
source .venv/bin/activate  # macOS/Linux
# .venv\Scripts\activate   # Windows

# 2. Install maturin in the venv
uv pip install maturin     # or: pip install maturin

# 3. Build the bindings
cd python
maturin develop --release --features "python,icu,mac"  # macOS
# maturin develop --release --features "python,icu"    # Linux
# maturin develop --release --features "python,windows" # Windows

# 4. Verify installation
python -c "import typf; print(typf.__version__)"

Troubleshooting:

If you encounter linker errors or missing Python symbols:

  • macOS: Install Xcode CLI tools: xcode-select --install
  • Linux: Install Python dev headers: sudo apt install python3-dev (Debian/Ubuntu) or sudo dnf install python3-devel (Fedora/RHEL)
  • Windows: Install Visual Studio Build Tools with Python development workload
  • All platforms: Ensure you're inside an activated virtual environment before running maturin develop

To build a distributable wheel:

maturin build --release    # Build wheel
pip install target/wheels/typf-*.whl

CLI Tool:

cargo install --path typf-cli
typf --help

Feature Flags

Control optional functionality via Cargo features:

[dependencies]
typf = { version = "*", features = ["mac", "tiny-skia-renderer"] }

Available features:

  • mac - CoreText backend (macOS only, default on macOS)
  • windows - DirectWrite backend (Windows only, default on Windows)
  • icu - HarfBuzz+ICU backend (cross-platform, default)
  • tiny-skia-renderer - tiny-skia rasterizer (optional)
  • orge - Custom orge rasterizer (experimental)

Usage

Rust API

Basic rendering:

use typf::prelude::*;

// Auto-select best backend for platform
let backend = Backend::auto_select()?;

// Create font specification
let font = Font::new("Arial", 24.0)
    .weight(700)  // Bold
    .style(FontStyle::Italic);

// Render text
let options = RenderOptions::default()
    .format(RenderFormat::PNG)
    .size(800, 600);

let result = backend.render_text("Hello, TYPF!", &font, &options)?;

// result.data contains PNG bytes
std::fs::write("output.png", &result.data)?;

Variable fonts:

let font = Font::new("RobotoFlex", 24.0)
    .variation("wght", 800.0)
    .variation("wdth", 125.0);

let result = backend.render_text("Variable!", &font, &options)?;

Font features:

let font = Font::new("OpenSans", 18.0)
    .feature("liga", 1)   // Enable ligatures
    .feature("smcp", 1);  // Small caps

let result = backend.render_text("fi fl", &font, &options)?;

SVG output:

let options = RenderOptions::default()
    .format(RenderFormat::SVG);

let result = backend.render_text("SVG Text", &font, &options)?;
let svg = String::from_utf8(result.data)?;

Python API

Basic rendering:

from typf import TextRenderer, Font, RenderFormat

# Auto-select backend
renderer = TextRenderer()

# Create font
font = Font("Arial", size=24.0)

# Render text
result = renderer.render(
    text="Hello from Python!",
    font=font,
    format=RenderFormat.PNG
)

# result.data is bytes (PNG)
with open("output.png", "wb") as f:
    f.write(result.data)

Variable fonts + NumPy:

import numpy as np
from PIL import Image

font = Font("RobotoFlex", size=48.0)
font.variation("wght", 700)
font.variation("wdth", 100)

result = renderer.render("Variable", font, format=RenderFormat.RAW)

# Convert to NumPy array
arr = np.frombuffer(result.data, dtype=np.uint8)
arr = arr.reshape(result.height, result.width, 4)  # RGBA

# Convert to PIL Image
img = Image.fromarray(arr)
img.show()

Batch rendering:

jobs = [
    {"font": "Arial", "text": "Job 1", "size": 24},
    {"font": "Times", "text": "Job 2", "size": 32},
]

results = renderer.render_batch(jobs)
for i, result in enumerate(results):
    with open(f"output_{i}.png", "wb") as f:
        f.write(result.data)

CLI

Single render:

# Render to PNG
typf render \
  --font=/path/to/font.ttf \
  --text="Hello, CLI!" \
  --size=48 \
  --output=output.png

# Render with variable font axes
typf render \
  --font=RobotoFlex.ttf \
  --text="Variable" \
  --axes="wght=700,wdth=100" \
  --output=variable.png

Batch processing (JSONL):

# Create job file
echo '{"font": "Arial", "text": "Line 1", "size": 24}' > jobs.jsonl
echo '{"font": "Times", "text": "Line 2", "size": 32}' >> jobs.jsonl

# Process batch
typf batch < jobs.jsonl

# Streaming mode (memory-efficient)
cat jobs.jsonl | typf stream

Output formats:

# PNG (default)
typf render --font=font.ttf --text="PNG" --format=png --output=out.png

# SVG
typf render --font=font.ttf --text="SVG" --format=svg --output=out.svg

# PGM (grayscale)
typf render --font=font.ttf --text="PGM" --format=pgm --output=out.pgm

# Metrics only (JSON)
typf render --font=font.ttf --text="Metrics" --format=metrics

Performance

Rendering Speed:

  • Typical glyph: Sub-millisecond
  • Complex scripts (Arabic, Devanagari): 1-5ms
  • Batch processing: Rayon-parallelized across CPU cores

Memory:

  • Zero-copy font loading via memmap2
  • Arc-based shared ownership (no unnecessary clones)
  • Multi-shard cache eliminates lock contention

Caching:

  • First render: Font load + shape + rasterize (~5-20ms)
  • Cached render: Shape lookup only (~0.1-1ms)
  • Cache hit rate: 80-95% typical for repeated text

Testing

Run all tests:

cargo test --workspace --all-features

Run platform-specific tests:

# macOS only
cargo test --features mac

# Windows only
cargo test --features windows

# HarfBuzz only
cargo test --features icu

Run integration tests:

cargo test --test integration

Python binding tests:

cd python
pytest tests/

Benchmarks:

cargo bench --workspace

Current Status

Production-Ready ✅

  • All 3 platform backends (CoreText, DirectWrite, HarfBuzz)
  • Multi-shard LRU caching
  • Python bindings (PyO3) with automatic backend selection
  • CLI with batch/stream/render commands
  • 38+ integration tests passing
  • SVG/PNG output with COLRv1 color font support

In Progress ⏳

  • Orge rasterizer backend integration
  • FFI panic handling (std::panic::catch_unwind wrappers)
  • Visual regression framework (SSIM-based)
  • Comprehensive documentation

Planned 📋

  • SIMD-accelerated fixed-point math (SSE2/AVX2/Neon)
  • cargo-fuzz + cargo-miri in CI
  • Unified typf_error::Error enum
  • seccomp sandboxing for untrusted fonts
  • Publishto crates.io

Development

Guidelines: See CLAUDE.md for development workflow, coding standards, and testing requirements.

Quick commands:

# Format code
cargo fmt --all

# Lint
cargo clippy --workspace --all-features -- -D warnings

# Build release
cargo build --workspace --release

# Build Python bindings
cd python && maturin develop --release

For tasks and roadmap: See root TODO.md (look for **(typf)** prefix)


Contributing

We follow a philosophy of ruthless minimalism and test-driven development:

  1. Write tests first (RED → GREEN → REFACTOR)
  2. Minimize code (delete > add)
  3. No panics in library code (use Result<T, TypfError>)
  4. Document all public APIs (rustdoc with examples)
  5. Benchmark performance-critical changes

See CLAUDE.md for detailed contribution guidelines.


License

See LICENSE file.


made by FontLab https://www.fontlab.com/



Last Updated: November 16, 2025 Status: Production-ready; focused on hardening and optimization Total Code: ~15,000 lines Rust + 500 lines Python

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

typf-0.1.0-cp312-cp312-macosx_11_0_arm64.whl (2.9 MB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

File details

Details for the file typf-0.1.0-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for typf-0.1.0-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 1526781d0b201bf3f5ed3f2b07500e4791fcdf93f3c3dc667ec1351fb736a71a
MD5 e66d629c19b00ecf08f52e9773f145f3
BLAKE2b-256 2266d3d0639ae07d67b86b5389308676feb6cd67c6a885b558004b48846c2e75

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page