FOP — Pure Rust XSL-FO Processor
A high-performance, pure Rust reimplementation of Apache FOP (Formatting Objects Processor), translating XSL-FO documents to PDF, SVG, PostScript, raster images, and plain text.
170 Rust files · 72,872 lines of code · 3,010+ tests · Zero warnings · 10–1200× faster than Java FOP
Project Status
Phase 5–6 Enhanced — Production ready with comprehensive features and testing.
| Phase | Status | Description |
|---|---|---|
| Phase 1: Foundation | ✅ Complete | Core types, property system, FO tree parsing |
| Phase 2: Basic Layout | ✅ Complete | Area tree, block/inline layout, PDF output |
| Phase 3: Advanced Layout | ✅ Complete | Knuth-Plass line breaking, tables, lists, graphics, images |
| Phase 4: Integration | ✅ Complete | Multi-page breaking, engine integration |
| Phase 5: Advanced Features | ✅ Complete | Image rendering, links, bookmarks, font embedding, i18n, encryption |
| Phase 6: Optimization | 🔄 85% Complete | Performance (✅), streaming (✅), testing (✅) |
Current stats: 3,010+ tests (all passing), 0 compiler warnings, 0 clippy warnings, 10–1200× faster than Java FOP
Key Features
XSL-FO Processing
- 294 XSL-FO 1.1 properties with full inheritance and shorthand expansion
- 29 FO element types — blocks, inlines, tables, lists, graphics, links, page masters
- Knuth-Plass optimal line breaking — same algorithm as TeX for publication-quality typography
- Multi-page breaking with widow/orphan control and overflow detection
Output Formats
- PDF — valid, viewable, text-extractable, with font embedding and subsetting
- SVG — scalable vector graphics output
- PostScript — for print workflows
- PNG / JPEG — raster image output
- Plain text — text extraction mode
PDF Advanced Features
- PDF encryption — RC4-128 with owner/user passwords and permission control
- PDF/A compliance mode — for archival-quality output
- Bookmarks and outlines — document navigation
- Internal and external links — clickable hyperlinks
- Font embedding and subsetting — TrueType/OpenType with CIDFontType2 + Identity-H encoding
Internationalization (i18n)
- 16+ languages supported — Japanese, Chinese, Korean, Arabic, Thai, Hindi, Hebrew, and more
- CJK support — Type 0 composite fonts with proper glyph rendering
- Right-to-left (RTL) — Arabic and Hebrew bidirectional text
- Emoji and full Unicode — complete Unicode coverage
- See docs/I18N_CAPABILITIES.md for the full guide
Streaming & Performance
- Streaming mode for large documents (>1000 pages) with bounded memory
- Parallel rendering infrastructure for multi-core utilization
- 10–1200× faster than Java FOP across all benchmarks
- <10ms startup vs ~2000ms JVM cold start
Self-verification (Pure Rust)
The fop-pdf-renderer crate parses and rasterizes PDF output with no C dependencies (no poppler, no Ghostscript). Use it programmatically or from the CLI:
use PdfRenderer;
let renderer = from_bytes?;
let page = renderer.render_page?; // 150 DPI → RasterPage
let text = renderer.extract_text?; // user-visible text extraction
CLI equivalents:
# Round-trip self-verification (generates PDF then rasterizes it internally)
# Standalone PDF → PNG conversion
Bindings
- CLI — Apache FOP-compatible command-line interface with progress bars and JSON stats
- WASM — browser and Node.js bindings via
wasm-bindgen - Python — bindings via PyO3 (published as
fop2on PyPI)
Performance
Real benchmark results against Java Apache FOP:
| Metric | Java FOP | Rust FOP | Speedup |
|---|---|---|---|
| Simple document render | ~50ms | ~0.04ms | ~1200× |
| Parse 1000-page doc | ~500ms | <50ms | ~10× |
| Memory per page | ~50KB | <5KB | ~10× |
| Binary size | 15MB+ JAR | <5MB stripped | ~3× |
| Startup time | ~2000ms (JVM) | <10ms | ~200× |
Quick Start
# Build
# Run tests (zero warnings policy)
# Run an example
Generate a PDF from XSL-FO
use FoTreeBuilder;
use LayoutEngine;
use PdfRenderer;
use Cursor;
CLI Usage
# Convert XSL-FO to PDF
# Convert to SVG
# Convert to PostScript
# With progress bar and JSON stats
# See all options
See crates/fop-cli/USAGE.md for the full CLI reference.
Python Bindings
The Python package is available on PyPI as fop2.
# One-shot conversion
=
# Or use the converter class
=
=
=
=
WASM Bindings
The WASM package is available on npm as @cooljapan/fop.
import init from '@cooljapan/fop';
await ;
const converter = ;
const pdfBytes = converter.;
const svgString = converter.;
Documentation
📚 Comprehensive documentation available in docs/
- docs/README.md — Complete documentation index
- docs/I18N_CAPABILITIES.md — Internationalization guide (Japanese, CJK, Arabic RTL, etc.)
- docs/LIMITATIONS.md — Current limitations and migration guide from Java FOP
Workspace Structure
fop/
├── Cargo.toml # Workspace root + top-level fop crate
├── crates/
│ ├── fop-types/ # Core types (Length, Color, Rect, FontMetrics, errors)
│ ├── fop-core/ # FO tree parsing & 294-property system
│ ├── fop-layout/ # Layout engine (block, inline, table, list, page breaking)
│ ├── fop-render/ # Rendering backends (PDF, SVG, PostScript, raster, text)
│ ├── fop-pdf-renderer/ # Pure Rust PDF-to-image renderer (glyph outlines, text extraction, self-verification)
│ ├── fop-cli/ # CLI tool (fop binary)
│ ├── fop-wasm/ # WebAssembly bindings (browser / Node.js)
│ └── fop-python/ # Python bindings via PyO3
├── examples/ # 23 runnable examples
├── benches/ # Performance & comparison benchmarks
├── tests/ # Integration tests
├── fuzz/ # Fuzz testing targets
└── docs/ # Documentation
Dependency Graph
fop-types (no internal deps)
│
├── fop-core (+ quick-xml)
│ │
│ ├── fop-layout (+ image)
│ │ │
│ │ ├── fop-render (+ oxiarc-deflate, ttf-parser, png, aes, sha2, md-5,
│ │ │ resvg, usvg, jpeg-encoder, tiny-skia)
│ │ │
│ │ ├── fop-cli (+ clap, anyhow, indicatif, console,
│ │ │ humantime, bytesize, serde_json)
│ │ │
│ │ ├── fop-wasm (+ wasm-bindgen, js-sys, serde-wasm-bindgen)
│ │ │
│ │ └── fop-python (+ pyo3)
│ │
└───────┘
fop-pdf-renderer (standalone: thiserror, oxiarc-deflate, ttf-parser, png,
jpeg-decoder, tiny-skia)
Supported XSL-FO Elements
| Category | Elements |
|---|---|
| Root & Structure | fo:root, fo:layout-master-set, fo:simple-page-master |
| Regions | fo:region-body, fo:region-before, fo:region-after, fo:region-start, fo:region-end |
| Page Sequences | fo:page-sequence, fo:flow, fo:static-content |
| Block-level | fo:block, fo:block-container |
| Inline-level | fo:inline, fo:character, fo:page-number, fo:page-number-citation |
| Tables | fo:table, fo:table-column, fo:table-header, fo:table-body, fo:table-row, fo:table-cell |
| Lists | fo:list-block, fo:list-item, fo:list-item-label, fo:list-item-body |
| Graphics & Links | fo:external-graphic, fo:basic-link |
| Leaders | fo:leader |
Examples
All 23 examples can be run with cargo run --example <name>:
| Example | Description |
|---|---|
basic_types |
Length, Color, Geometry type usage |
border_background_demo |
Borders and background styling |
cli_production_example |
Production CLI workflow demonstration |
comprehensive_demo |
All Phase 3 features combined |
generate_japanese_pdfs |
Japanese PDF generation with CJK fonts |
hello_pdf |
Minimal PDF generation |
i18n_multi_font |
Multi-font internationalization |
i18n_showcase |
Full i18n showcase (16+ languages) |
layout_demo |
FO tree to area tree transformation |
manual_japanese_font |
Manual Japanese font configuration |
parse_fo_document |
Full XSL-FO document parsing |
pdf_encryption |
PDF encryption with RC4-128 |
phase5_complete_demo |
Phase 5 complete feature demonstration |
phase5_features |
Phase 5 individual features |
properties |
Property system and inheritance |
ps_output_demo |
PostScript output generation |
shorthand |
Shorthand property expansion (margin, padding, border) |
streaming_demo |
Streaming mode for large documents |
styled_pdf |
PDF with colors and fonts |
svg_output_demo |
SVG output generation |
tables_lists_demo |
Tables and lists end-to-end |
text_extraction_demo |
Text extraction from PDF |
validation |
Element nesting validation |
Dependencies
All dependencies are pure Rust — no C/Fortran/system libraries required.
Production Dependencies
| Crate | Version | Purpose |
|---|---|---|
quick-xml |
0.39 | XML parsing (zero-copy) |
thiserror |
2.0 | Error type derivation |
log |
0.4 | Logging facade |
oxiarc-deflate |
0.2.6 | PDF stream compression (deflate) — pure Rust |
ttf-parser |
0.25 | TrueType/OpenType font parsing |
png |
0.18 | PNG image encoding/decoding |
jpeg-decoder |
0.3 | JPEG image decoding |
jpeg-encoder |
0.7 | JPEG image encoding |
image |
0.25 | Image format detection and loading |
tiny-skia |
0.12 | 2D raster rendering |
resvg |
0.47 | SVG rendering |
usvg |
0.47 | SVG tree simplification |
aes |
0.8 | AES encryption (PDF security) |
cbc |
0.1 | CBC block cipher mode |
sha2 |
0.10 | SHA-256 hashing (PDF encryption) |
md-5 |
0.10 | MD5 hashing (PDF encryption) |
CLI Dependencies
| Crate | Version | Purpose |
|---|---|---|
clap |
4.5 | Command-line argument parsing |
anyhow |
1.0 | Error handling |
indicatif |
0.18 | Progress bars |
console |
0.16 | Terminal formatting |
humantime |
2.3 | Human-readable durations |
bytesize |
2.3 | Human-readable byte sizes |
serde_json |
1.0 | JSON statistics output |
Bindings Dependencies
| Crate | Version | Purpose |
|---|---|---|
pyo3 |
0.28 | Python bindings (ABI3, Python 3.8+) |
wasm-bindgen |
0.2 | WebAssembly bindings |
js-sys |
0.3 | JavaScript interop |
Architecture
Pipeline
XSL-FO XML ──→ FO Tree ──→ Area Tree ──→ Output (PDF/SVG/PS/PNG/text)
(parse) (layout) (render)
Design Principles
- Zero-copy parsing —
Cow<'static, str>and arena allocation throughout - Arena allocation — index-based tree nodes (no
Rc<RefCell<>>overhead) - Static dispatch — enum dispatch over trait objects where possible
- Millipoint arithmetic — 1/1000 pt precision with integer math (no floating-point drift)
- Release profile — LTO + single codegen unit + opt-level 3 + stripped binaries
Testing
- 3,010+ tests — unit, integration, and fuzz targets
- Zero warnings — enforced via
cargo clippy --all-targets -- -D warnings - Fuzz testing —
fuzz_xml_parser,fuzz_property_parser,fuzz_layout - PDF self-verification —
fop-pdf-rendererrenders generated PDFs back to compare
Continuous Integration
.github/workflows/ci.yml runs fmt, clippy -D warnings, cargo nextest, and doc -D warnings on every push and PR across Linux, macOS, and Windows (stable Rust). No poppler or Ghostscript is installed on any runner — the auto-verify path is exercised end-to-end through the pure-Rust fop-pdf-renderer. Python (PyO3) and WASM bindings are built in a dedicated job that installs the required toolchains.
Development
Zero Warnings Policy
This project enforces zero compiler warnings and zero clippy warnings:
Build Profiles
# Debug build
# Optimized release build (LTO + stripped)
# Build WASM bindings
&&
# Build Python bindings
&&
Benchmarks
See benches/README.md for benchmark details.
Reference
- Based on Apache FOP (Java, 1566+ files across 8 Maven modules)
- Implements XSL-FO 1.1 Specification
- CHANGELOG.md — Release history
Sponsorship
FOP is developed and maintained by COOLJAPAN OU (Team Kitasan).
If you find FOP useful, please consider sponsoring the project to support continued development of the Pure Rust ecosystem.
https://github.com/sponsors/cool-japan
Your sponsorship helps us:
- Maintain and improve the COOLJAPAN ecosystem
- Keep the entire ecosystem (OxiBLAS, OxiFFT, SciRS2, etc.) 100% Pure Rust
- Provide long-term support and security updates
License
Licensed under the Apache License, Version 2.0. See LICENSE for details.
Copyright 2024–2026 COOLJAPAN OU (Team Kitasan)