Complete technical reference for the XFA PDF SDK. Last updated: 2026-03-16
- Project Vision
- System Architecture
- Crate Map (38 crates)
- Layer 1: PDF Parsing (hayro fork)
- Layer 2: XFA Engine
- Layer 3: Document Abstraction
- Layer 4: Forms & Annotations
- Layer 5: Manipulation & Content Intelligence
- Layer 6: Compliance & Standards
- Layer 7: Digital Signatures
- Layer 8: Data Exchange & Conversions
- Layer 9: Language Bindings
- Layer 10: Desktop Application
- Layer 11: CLI & Server
- Testing & Quality Infrastructure
- Dependency Graph
- External Dependencies
- Security Architecture
- Performance Architecture
- Implementation Status
XFA-Native-Rust is a 100% pure Rust PDF SDK delivering full Adobe Reader parity for XFA forms, plus a complete PDF manipulation and compliance stack. The architecture replaces all C/C++ dependencies (PDFium, Poppler, MuPDF) with memory-safe Rust implementations.
Core principles:
- Memory safety — no
unsafein application code; all parsing is bounds-checked - No C dependencies — WASM-compilable, no FFI overhead, no segfaults
- Layered architecture — each crate has a single responsibility with clear interfaces
- Standards-first — ISO 32000-2 (PDF 2.0), XFA 3.3, PDF/A (ISO 19005), PDF/UA (ISO 14289), PDF/X (ISO 15930)
Competitive positioning: Targets feature parity with iText, PSPDFKit, Aspose.PDF and Adobe Acrobat Pro.
┌──────────────────────────────────────────────────────────────────────┐
│ Applications │
│ ┌─────────────┐ ┌──────────────┐ ┌─────────────┐ ┌───────────┐ │
│ │ pdf-desktop │ │ xfa-cli │ │ xfa-api- │ │ xfa-wasm │ │
│ │ (Tauri) │ │ │ │ server │ │ (browser) │ │
│ └──────┬──────┘ └──────┬───────┘ └──────┬──────┘ └─────┬─────┘ │
├─────────┼────────────────┼─────────────────┼────────────────┼───────┤
│ │ Language Bindings │ │ │
│ ┌──────┴──────┐ ┌──────┴───────┐ ┌──────┴──────┐ │ │
│ │ pdf-capi │ │ pdf-python │ │ pdf-node │ │ │
│ │ (C FFI) │ │ (PyO3) │ │ (napi-rs) │ │ │
│ └──────┬──────┘ └──────┬───────┘ └──────┬──────┘ │ │
├─────────┼────────────────┼─────────────────┼────────────────┼───────┤
│ └────────────────┴────────┬────────┴────────────────┘ │
│ ▼ │
│ ┌────────────────┐ │
│ │ pdf-engine │ Unified Document API │
│ └───────┬────────┘ │
├──────────────────────────────────┼───────────────────────────────────┤
│ ┌───────────────────┼───────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌────────────────┐ ┌────────────────┐ ┌────────────────────┐ │
│ │ pdf-forms │ │ pdf-annot │ │ pdf-xfa │ │
│ │ (AcroForms) │ │ (Annotations) │ │ (XFA 3.3) │ │
│ └────────────────┘ └────────────────┘ └────────┬───────────┘ │
│ │ │
│ ┌─────────┼─────────┐ │
│ ▼ ▼ ▼ │
│ ┌──────────┐ ┌────────┐ ┌──────┐ │
│ │xfa-dom- │ │formcalc│ │xfa- │ │
│ │resolver │ │-interp │ │layout│ │
│ └──────────┘ └────────┘ └──────┘ │
├─────────────────────────────────────────────────────────────────────┤
│ Manipulation / Intelligence / Compliance / Signatures │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────┐ ┌─────────┐ │
│ │pdf-manip │ │pdf-extract│ │pdf-redact│ │pdf- │ │pdf-sign │ │
│ │ │ │ │ │ │ │compliance │ │ │ │
│ └──────────┘ └──────────┘ └──────────┘ └───────────┘ └─────────┘ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────┐ │
│ │pdf-docx │ │pdf-xlsx │ │pdf-pptx │ │pdf-invoice│ │
│ └──────────┘ └──────────┘ └──────────┘ └───────────┘ │
├─────────────────────────────────────────────────────────────────────┤
│ PDF I/O Foundation │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ pdf-syntax │ │ pdf-interpret│ │ lopdf │ │
│ │ (read-only) │ │ (content │ │ (read-write │ │
│ │ │ │ streams) │ │ mutation) │ │
│ └──────┬───────┘ └──────┬───────┘ └──────────────┘ │
│ │ │ │
│ ┌──────┴───────┐ ┌──────┴───────┐ ┌──────────────┐ │
│ │ pdf-font │ │ pdf-render │ │ Image codecs │ │
│ │ (CMap, CFF, │ │ (vello_cpu │ │ (JBIG2, │ │
│ │ Type1) │ │ rasterizer) │ │ JPEG2000, │ │
│ └──────────────┘ └──────────────┘ │ CCITT) │ │
│ └──────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
The SDK uses two PDF parsing stacks for different purposes:
| Stack | Crate | Purpose | Mutability |
|---|---|---|---|
| hayro fork | pdf-syntax |
Read-only parsing, rendering, compliance checking | Immutable |
| lopdf | lopdf (v0.39) |
PDF mutation, form filling, manipulation, AES-256 encryption | Mutable |
This dual-stack design allows read-only operations (rendering, text extraction, compliance) to use the zero-copy pdf-syntax parser, while write operations (form fill, redact, sign, encrypt) go through lopdf which supports full PDF serialization.
lopdf exposes aes256_encryption_state() (see crates/lopdf/src/encryption.rs) — a convenience wrapper that generates a random 32-byte file key and returns an EncryptionState ready for doc.encrypt(&state). This implements PDF 2.0 §7.6.4.3 (V=5, R=6, /CFM /AESV3). Decision: D008.
crates/
├── hayro-ccitt/ # CCITT Group 3/4 image decoder
├── hayro-jbig2/ # JBIG2 image decoder
├── hayro-jpeg2000/ # JPEG2000 image decoder
├── pdf-syntax/ # Read-only PDF parser (hayro fork)
├── pdf-interpret/ # Content stream interpreter
├── pdf-font/ # Font parsing (Type1, CFF, CMap)
├── pdf-render/ # Pure Rust rasterizer (vello_cpu)
├── cff-parser/ # CFF/Type2 font parser — local fork with CID glyph_width fix (#423)
├── pdf-engine/ # Unified document API
├── pdf-forms/ # AcroForm engine
├── pdf-annot/ # Annotation engine
├── pdf-xfa/ # XFA wrapper
├── xfa-dom-resolver/ # SOM path resolution, DOM management
├── formcalc-interpreter/ # FormCalc scripting engine
├── xfa-layout-engine/ # XFA layout engine
├── xfa-json/ # JSON output for XFA layout
├── pdf-manip/ # PDF manipulation (pages, encrypt, watermark, fonts)
├── pdf-extract/ # Content extraction (text, images)
├── pdf-redact/ # GDPR-compliant redaction
├── pdf-ocr/ # OCR integration (Tesseract + PaddleOCR, feature-gated)
├── pdf-compliance/ # PDF/A, PDF/UA, PDF/X validation
├── pdf-sign/ # Digital signature validation + signing (PAdES, CMS, TSA)
├── pdf-diff/ # Visual PDF comparison (SSIM)
├── pdf-docx/ # PDF → DOCX conversion
├── pdf-xlsx/ # PDF → XLSX conversion
├── pdf-pptx/ # PDF → PPTX conversion
├── pdf-invoice/ # FDF/XFDF + ZUGFeRD/Factur-X
├── pdf-capi/ # C FFI binding
├── pdf-python/ # Python binding (PyO3) — excluded from workspace
├── pdf-node/ # Node.js binding (napi-rs)
├── xfa-wasm/ # WebAssembly binding
├── pdf-desktop/ # Tauri v2 desktop viewer
├── xfa-cli/ # CLI tool
├── xfa-api-server/ # HTTP API server (Axum)
├── xfa-test-runner/ # Corpus test runner
├── xfa-golden-tests/ # Visual regression tests
├── pdf-bench/ # Performance benchmarks (Criterion)
├── pdfium-ffi-bridge/ # PDFium FFI (optional, golden tests only)
fuzz/ # Fuzzing harness (cargo-fuzz)
Purpose: Zero-copy, read-only PDF parsing. Forked from the hayro ecosystem (MIT/Apache-2.0).
Key types:
Pdf— Root document handle. Lazy parsing: objects resolved on access.Page— Page access withraw() → &Dict,page_stream() → Option<&[u8]>Object— Enum:Dict,Array,Stream,String,Name,Number,Bool,Null,RefRect— Bounding box withx0, y0, x1, y1(f64)
Subsystems:
- XRef parsing (standard + cross-reference streams)
- Stream decoding: FlateDecode, LZWDecode, ASCIIHexDecode, ASCII85Decode, RunLengthDecode, CCITTFaxDecode, JBIG2Decode, JPXDecode, DCTDecode, Crypt
- Encryption: RC4, AES-128, AES-256 (password-protected PDF detection)
- Content stream tokenization
Security hardening (SafeDocs corpus):
- Inline nesting depth cap: 256
- XRef chain depth cap: 64
- Page count cap: 100,000
- Flate/LZW/predictor output cap: 64 MB
- File size limit: 256 MB
- Thread stack size: 8 MB
Purpose: Content stream interpretation — converts PDF operators into rendering commands.
Key abstractions:
Devicetrait — rendering backend interface (rasterization, text extraction)- Graphics state machine — tracks CTM, color space, clipping, text state
- Glyph rendering via
skrifa(modern font parsing) +kurbo(2D geometry)
Purpose: Font parsing, CMap handling, glyph metrics.
Key types:
CMap— CMap parser withlookup_bf_string()andlookup_cid_code()BfString— EitherChar(char)orString(String)for Unicode mapping- Font types: Type1, TrueType, CFF, OpenType
- Perfect hashing (
phf) for built-in CMap tables
Purpose: Pure Rust rasterizer using vello_cpu (vector graphics backend).
Pipeline:
Content stream → pdf-interpret (Device) → vello_cpu scene → bitmap
| Crate | Format | Notes |
|---|---|---|
hayro-ccitt |
CCITT Group 3/4 | No dependencies, pure codec |
hayro-jbig2 |
JBIG2 | Memory-safe decoder |
hayro-jpeg2000 |
JPEG2000 | Optional SIMD support |
The XFA engine implements the complete XFA 3.3 specification for XML Forms Architecture processing.
Spec: XFA 3.3 §3 (Object Models)
DOM hierarchy:
xfa (root)
├── config → Configuration DOM
├── datasets
│ ├── data → Data DOM (dataGroup / dataValue)
│ └── dataDescription → Data Description DOM
├── form → Form DOM (merge result)
├── layout → Layout DOM
└── template → Template DOM
Key capabilities:
- SOM (Scripting Object Model) path resolution:
xfa.form.subform[3].field[*] - Wildcard and predicate support in SOM expressions
- Arena-allocated node trees for performance
- CRUD operations on Template and Data DOM nodes
Spec: XFA 3.3 §25 (FormCalc Specification)
Pipeline: Source → Lexer → Parser (recursive descent) → AST → Interpreter
Built-in functions (90+):
| Category | Functions |
|---|---|
| Arithmetic | Abs, Avg, Ceil, Count, Floor, Max, Min, Mod, Round, Sum |
| Date/Time | Date, Date2Num, Num2Date, Time, Time2Num + 7 others |
| String | At, Concat, Left, Len, Replace, Substr + 13 others |
| Financial | Apr, Pmt, Pv, Rate, Term + 5 others |
| Logical | If, Choose, Oneof, Within, Eval, Null |
SOM integration: FormCalc scripts resolve and mutate DOM nodes via the SOM bridge.
Spec: XFA 3.3 §4 (Box Model), §8 (Layout for Growable Objects)
Layout modes:
- Positioned — absolute coordinates within containers
- Flowed — flow-based:
tb,lr-tb,rl-tb - Tables — rows, cells, column spanning
Features:
- Box Model (margins, borders, padding, content areas)
- Dynamic sizing (
minH,maxH,minW,maxWconstraints) - Occur rules (repeating subforms based on
min/max/initial) - Pagination and content splitting across pages
- Leaders/trailers (headers/footers per page)
- Rich text rendering with text wrapping and font metrics
- Scripting integration (layout reacts to FormCalc calculations)
JSON serialization of XFA layout output via serde + indexmap (ordered maps).
The pdf-xfa crate provides the integration layer that connects XFA layout to PDF rendering:
XFA Template XML
↓ extract::extract_xfa_from_bytes()
XFA Packets (template, datasets, config, locale)
↓ font_bridge::XfaFontResolver
Font Resolution (embedded fonts → system fonts → fallbacks)
↓ template_parser::parse_template()
Form Tree + Layout Engine
↓ flatten::flatten_xfa_to_pdf()
Flattened PDF (static PDF with embedded fonts, images)
Purpose: Resolves XFA <font typeface="..."> declarations to actual font data.
Resolution order:
- Fonts embedded in the source PDF (via
extract_embedded_fonts()) - System fonts found on disk (TTF/OTF/TTC/OTC)
- Base font name stripping (e.g., "Arial-Bold" → "Arial")
- Fallback fonts: Helvetica → Arial → DejaVuSans → LiberationSans
Key types:
ResolvedFont— parsed font with metrics (upem, ascender, descender)XfaFontSpec— XFA font attributes (typeface, weight, posture, size)XfaFontResolver— resolver with embedded/system font caches
Font metrics injection:
// Resolved metrics injected into FontMetrics
resolved_widths: Option<Vec<u16>> // per-glyph widths (1000-unit scale)
resolved_upem: Option<u16> // units-per-em (typically 1000)
resolved_ascender: Option<i16> // typographic ascender
resolved_descender: Option<i16> // typographic descenderPurpose: Converts XFA image data (JPEG/PNG) into PDF Image XObject dictionaries.
Supported formats:
- JPEG (embedded directly via
/Filter /DCTDecode) - PNG (decoded → FlateDecode compressed, alpha via SMask)
Key functions:
detect_image_format()— magic byte detection (JPEG:FF D8 FF, PNG:89 50 4E 47)embed_jpeg()/embed_png()— create Image XObject in lopdf documentrender_image_ops()— PDF content streamq cm Do Qoperators
Purpose: Converts LayoutDom into PDF content stream operators for overlay rendering.
Coordinate mapping:
- XFA: top-left origin (y grows downward)
- PDF: bottom-left origin (y grows upward)
CoordinateMapper::xfa_to_pdf_y()performs the conversion
Content stream generation:
generate_page_overlay()— single page withPageOverlay { content_stream, images }generate_all_overlays()— all pages via iterator- Text rendering with
BT ... ETblocks,Tdpositioning,Tj/TJtext - Border rendering with
re(rectangle),S(stroke), rounded corners via Bezier curves - Image rendering via
Do(paint XObject)
Resolved metrics integration:
resolve_font_ref()— selects/XFA_F0for embedded fonts,/F1//F2//F3for Base14build_font_metrics()— injectsresolved_widths/resolved_upemintoFontMetrics
Entry point: flatten_xfa_to_pdf(pdf_bytes: &[u8]) -> Result<Vec<u8>>
Pipeline:
- Extract XFA packets from PDF
- Parse template XML → Form Tree
- Resolve fonts (embedded → system → fallback)
- Run layout engine →
LayoutDom - Generate overlays per page with resolved metrics
- Embed resolved fonts as PDF Font objects
- Merge overlays onto source PDF pages
- Return flattened PDF bytes
Purpose: Unified high-level API for PDF documents. Central integration point for all SDK capabilities.
Key modules:
| Module | Purpose |
|---|---|
document |
PdfDocument — unified document handle |
render |
Page rasterization with configurable DPI, color, rotation |
text |
Text extraction with positioned characters, CMap-aware Unicode |
thumbnail |
Fast thumbnail generation |
geometry |
Page bounds, MediaBox/CropBox/BleedBox/TrimBox, rotation |
Dependencies: Integrates pdf-syntax, pdf-interpret, pdf-render, pdf-forms, pdf-xfa.
Standard: ISO 32000-2 §12.7 (Interactive Forms)
Architecture:
FieldTree— Arena-allocated field hierarchy (optimized for deep nesting)FormAccesstrait — unified facade over field tree- Field types: Text, Checkbox, RadioButton, Dropdown, ListBox, PushButton, Submit, Reset
Capabilities:
- AcroForm dictionary parsing and field tree construction
- Default Appearance (DA) parsing and appearance stream generation
- Field validation, calculation, and format scripts
- Form flattening — converting fields to static content
- Form value persistence — save field values back to PDF (#300)
- Programmatic field creation — AcroForm field builder API (#301)
Standard: ISO 32000-2 §12.5 (Annotations)
Supported annotation types (all 12.5 types):
- Markup: Text (sticky note), Highlight, Underline, StrikeOut, Squiggly
- Geometric: Line, Square, Circle, Polygon, PolyLine, Ink
- Document: Link (URI, GoTo, GoToR), FreeText, Stamp, FileAttachment, Popup
Write support (feature-gated via write):
- Annotation creation with builder pattern (#302–#305)
- Appearance stream generation for all types
- lopdf-backed serialization
Purpose: PDF mutation operations using lopdf as the write backend.
Modules:
| Module | Capability | Issue |
|---|---|---|
page_ops |
Merge, split, insert, delete, rearrange pages | #194 |
encrypt |
Encryption, decryption, password protection | #195 |
watermark |
Text and image overlay watermarks | #196 |
optimize |
PDF compression and optimization | #197 |
bookmarks |
Bookmark/outline reading and creation | #198 |
headers |
Headers, footers, Bates numbering | #309 |
content_editor |
Content stream round-trip (decode → manipulate → encode) | #310 |
text_run |
CMap-aware text run extraction from content streams | #311 |
text_replace |
Find-and-replace text in content streams | #312 |
image_insert |
Add JPEG/PNG images to pages (feature: image-insert) |
#313 |
downsample |
Reduce DPI of embedded images (feature: image-insert) |
#314 |
font_subset |
Font subsetting via subsetter crate (feature: font-subset) |
#315 |
pdfa_xmp |
PDF/A XMP metadata repair via xmp-writer |
#317 |
pdfa_fonts |
PDF/A font embedding and subsetting | #318 |
pdfa_colorspace |
Color space normalization, OutputIntent injection | #319 |
pdfa_cleanup |
Transparency flattening, JS/EmbeddedFiles removal | #320 |
Content Editor architecture:
PDF page content stream (bytes)
↓ lopdf::content::Content::decode()
Vec<Operation> ← ContentEditor wraps this
↓ GraphicsStateTracker records state snapshots
↓ Manipulation: remove, replace, insert operations
↓ ContentEditor::encode()
Modified content stream (bytes)
↓ write_editor_to_page()
Updated PDF page
Text Run extraction:
Content stream → ContentEditor → Operations
↓
FontMap (per-page font resources + ToUnicode CMaps)
↓
extract_text_runs() → Vec<TextRun>
↓
Each TextRun: { text, ops_range, font_name, font_size, x, y, width }
Font encoding support:
Builtin— single-byte (Latin-1 range, WinAnsiEncoding)IdentityH— 2-byte CID font (Identity-H CMap)CustomCMap— parsed ToUnicode CMap- Reverse CMap lookup for text replacement (Unicode → character code)
Purpose: Content extraction from PDF documents.
Capabilities:
- Image extraction (embedded images as raw bytes + metadata) (#201)
- Positioned text extraction (characters with bounding boxes) (#202)
- Full-text search with page-level results (#202)
PositionedChar— character + bounding box[x0, y0, x1, y1]
Purpose: GDPR-compliant permanent content removal.
Architecture (dual-layer):
Layer 1: Visual redaction (Redactor)
├── Draw colored rectangles over redacted areas
├── Optional overlay text (e.g., "[REDACTED]")
└── Metadata stripping
Layer 2: Content stream surgery (search_and_redact)
├── Text pattern matching (exact + regex)
├── Positioned char → bounding rectangle computation
├── ContentEditor removes matching text operations
└── Combined: overlay + removal = permanent redaction
Key types:
RedactionArea— page number + bounding rect + color + overlayRedactor— applies redaction areas to a lopdf DocumentRedactSearchOptions— case sensitivity, regex, fill color, page filterSearchRedactReport— matches found, areas redacted, operations removed
Purpose: OCR for scanned PDFs. Pluggable engine design with multiple backends.
Backends:
| Backend | Feature flag | Crate | Description |
|---|---|---|---|
| Tesseract | tesseract |
leptess |
Rust bindings to Tesseract OCR engine |
| PaddleOCR | paddle |
ort + ndarray |
ONNX Runtime-based pipeline (no C++ dependencies) |
PaddleOCR pipeline (#399–#401):
Input image
↓ DBNet text detection model (ONNX) (#399)
↓ → bounding box proposals → NMS filtering
↓ Angle classifier (0°/180° rotation detection) (#401)
↓ SVTR text recognition model (ONNX) + CTC decode (#400)
↓ → character probabilities → greedy decode → Unicode text
↓
Vec<OcrWord> { text, confidence, bbox }
Model management (#401):
- Automatic model download from PaddleOCR repository
- Local cache at
~/.cache/paddle-ocr/(viadirs-next) - Three ONNX models: detection (DBNet), recognition (SVTR), angle classifier
Key types:
OcrEnginetrait — pluggable backend interfacePaddleOcrEngine— PaddleOCR ONNX pipelineTesseractEngine— Tesseract wrapperOcrConfig— DPI, language, engine selectionmake_searchable()— converts scanned PDF to searchable PDF
Purpose: Validate and generate standards-conformant PDFs.
Standards supported:
| Standard | ISO | Validation | Generation |
|---|---|---|---|
| PDF/A-1a, 1b | ISO 19005-1 | Yes | Yes |
| PDF/A-2a, 2b, 2u | ISO 19005-2 | Yes | Yes |
| PDF/A-3a, 3b, 3u | ISO 19005-3 | Yes | Yes |
| PDF/A-4 | ISO 19005-4 | Yes | Yes |
| PDF/UA-1 | ISO 14289-1 | Yes | Yes (#322) |
| PDF/X-1a, 3, 4 | ISO 15930 | Yes (#321) | Yes (#321) |
PDF/A validation architecture:
Pdf (pdf-syntax)
↓ ObjectCache (pre-collected objects, single parse)
↓ detect_pdfa_level() from XMP metadata
↓
Per-clause checks (§6.1.x through §6.12.x):
├── §6.1: File structure (header, trailer, xref, streams)
├── §6.2: Graphics (color spaces, rendering intents, halftone)
├── §6.3: Fonts (embedding, encoding, metrics)
├── §6.4: Transparency
├── §6.5: Annotations (flags, appearances)
├── §6.6: Actions (forbidden actions)
├── §6.7: Metadata (XMP, document info)
├── §6.8: Logical structure (tagged PDF)
├── §6.9: Optional content
└── §6.10-12: Additional constraints per PDF/A part
↓
ComplianceReport { issues: Vec<ComplianceIssue> }
Performance optimizations:
ObjectCache— pre-collects all objects once to avoid repeated O(n) parsingnew_bounded()— skips caching for PDFs with >20K objectsMaybeRef— checks direct values without resolving indirect references- Bounded struct tree walking (max depth 100, max nodes 10,000)
- Inline image scan capped at 1 MB content / 200 images per page
PDF/A conversion pipeline (non-conformant → conformant):
Input PDF (lopdf Document)
↓ pdfa_xmp: inject/repair XMP metadata (#317)
↓ pdfa_fonts: embed and subset all fonts (#318)
↓ pdfa_colorspace: normalize color spaces, inject OutputIntent (#319)
↓ pdfa_cleanup: remove JS, embedded files, flatten transparency (#320)
↓
PDF/A-conformant output
PDF/UA generation (#322):
- Structure tree generation with role mappings
- Tagged PDF creation with reading order
- Alt text and accessibility metadata
Compliance test results (veraPDF oracle):
- Baseline: 1,383 failures
- After 10 optimization iterations: 526 failures
- 62% reduction in false negatives
Standards: PAdES (ETSI EN 319 142), CMS (RFC 5652), X.509, RFC 3161
Validation capabilities:
- PAdES baseline signature validation (#176)
- Certificate chain validation with OCSP/CRL revocation checking (#177)
- DocMDP + FieldMDP permission handling (#178)
- Signature appearance rendering + LTV embedding (#179)
Signing capabilities:
PdfSignertrait +Pkcs12Signer— pluggable signing with PKCS#12 identity loading (#396)- CMS SignedData DER builder — manual RFC 5652 construction with signed attributes (#396)
- Two-pass PDF signing —
sign_pdf()/sign_pdf_incremental()with ByteRange placeholder injection (#398) - DocMDP certification signatures with configurable permission levels (#398)
- Visible signature rectangles with appearance streams (#398)
- Incremental (append-only) signing preserving existing signatures (#398)
- RFC 3161 TSA timestamp embedding for PAdES-T compliance (#397)
- LTV embedding (PAdES B-LT, B-LTA) (#308)
Signing architecture:
PKCS#12 (.p12/.pfx)
↓ Pkcs12Signer::from_pkcs12()
↓ Detects key type (RSA, ECDSA P-256/P-384) from PKCS#8 AlgorithmIdentifier
↓
sign_pdf(pdf_bytes, signer, options)
↓ Pass 1: Prepare PDF with /Contents placeholder (lopdf)
↓ Build sig dict, AcroForm, widget annotation
↓ Optional: DocMDP certification, visible signature rect
↓ Serialize → locate placeholders in byte stream
↓ Pass 2: Patch /ByteRange, hash byte ranges
↓ CMS SignedData construction (cms_builder)
↓ Hex-encode and inject into /Contents
↓
Signed PDF (validates with pdf-syntax validation pipeline)
Key modules:
| Module | Purpose |
|---|---|
signer |
PdfSigner trait, Pkcs12Signer (RSA/ECDSA), key type detection |
cms_builder |
DER encoding helpers, CMS SignedData construction (RFC 5652) |
sign |
sign_pdf(), sign_pdf_incremental(), ByteRange injection, DocMDP |
tsa |
RFC 3161 timestamp request/response, TSA token embedding |
cms |
CMS parsing for validation |
chain |
Certificate chain verification |
docmdp |
DocMDP/FieldMDP permission handling |
ltv |
Long-Term Validation support |
Crypto stack (pure Rust, RustCrypto):
| Algorithm | Crate | Usage |
|---|---|---|
| SHA-256, SHA-384, SHA-1 | sha2, sha1 |
Hash computation |
| RSA PKCS#1 v1.5 | rsa |
Signature verification/creation |
| ECDSA P-256 | p256, ecdsa |
Elliptic curve signatures |
| ECDSA P-384 | p384 |
Extended elliptic curve |
| X.509 | spki, der |
Certificate parsing |
| PKCS#12 | p12 |
Identity loading (.p12/.pfx) |
| PKCS#8 | pkcs8 |
Private key parsing |
Standards: FDF (PDF spec §12.7.8), XFDF (ISO 19444-1), ZUGFeRD/Factur-X (EN 16931)
Capabilities:
- FDF import/export (#203)
- XFDF import/export (#203)
- ZUGFeRD/Factur-X e-invoicing XML generation (#205)
- Business rule validation against EN 16931 (#226)
| Crate | Direction | Format | Key Dependencies | Issue |
|---|---|---|---|---|
pdf-docx |
PDF → DOCX | Office Open XML | quick-xml, zip |
#323 |
pdf-xlsx |
PDF → XLSX | Office Open XML | rust_xlsxwriter |
#324 |
pdf-pptx |
PDF → PPTX | Office Open XML | quick-xml, zip |
#325 |
Conversion pipeline:
PDF → pdf-extract (text + images + positions) → layout analysis → target format
Purpose: Visual page-level PDF comparison (#327).
Algorithm: SSIM (Structural Similarity Index) for perceptual image comparison. Generates diff images highlighting changes.
Headless Chrome wrapper for HTML-to-PDF conversion (#326).
All bindings wrap pdf-engine (and select crates) through language-specific FFI mechanisms:
pdf-engine (Rust core)
│
┌───────────────┼───────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ pdf-capi │ │pdf-python│ │ pdf-node │
│ extern"C"│ │ PyO3 │ │ napi-rs │
└────┬─────┘ └──────────┘ └──────────┘
│
┌──────┼──────┐
▼ ▼ ▼
.NET Java Swift ← Consume C API
P/Inv JNI wrapper
| Binding | Crate | Mechanism | Status |
|---|---|---|---|
| C | pdf-capi |
extern "C" + cdylib + staticlib |
Done |
| Python | pdf-python |
PyO3 v0.24, built via maturin |
Done |
| Node.js | pdf-node |
napi-rs, async API, TypeScript typings | Done |
| WASM | xfa-wasm |
wasm-bindgen, runs in browser | Done (base) |
| Binding | Mechanism | Issue |
|---|---|---|
| Java | JNI via C API | #335 |
| .NET | P/Invoke via C API | #336 |
| iOS (Swift) | Swift wrapper over C API | #337 |
| Android (Kotlin) | Kotlin wrapper via JNI | #338 |
| WASM extended | Add rendering, annotations, signing | #339 |
Comprehensive documentation and example code for all bindings (#340).
Purpose: Native desktop PDF viewer/editor comparable to Adobe Acrobat Pro.
Stack: Tauri v2 (Rust backend + WebView frontend) with pdf-engine for rendering.
Architecture:
┌──────────────────────────────────────────┐
│ Tauri WebView │
│ ┌────────────────────────────────────┐ │
│ │ React/Svelte Frontend │ │
│ │ ├── PDF Viewport (canvas) │ │
│ │ ├── Thumbnail Sidebar (#329) │ │
│ │ ├── Annotation Toolbar (#331) │ │
│ │ └── File Manager UI (#333) │ │
│ └─────────────┬──────────────────────┘ │
│ │ IPC (Tauri commands) │
│ ┌─────────────┴──────────────────────┐ │
│ │ Rust Backend │ │
│ │ ├── pdf-engine (render, text) │ │
│ │ ├── pdf-annot (annotations) │ │
│ │ ├── lopdf (mutations) │ │
│ │ └── pdf-sign (signatures) │ │
│ └────────────────────────────────────┘ │
└──────────────────────────────────────────┘
Features:
| Feature | Description | Issue |
|---|---|---|
| Window shell | Window, menu bar, PDF viewport | #328 |
| Thumbnails | Sidebar with page previews | #329 |
| Text selection | Select and copy to clipboard | #330 |
| Annotations | Toolbar with property panel | #331 |
| Platform-native print support | #332 | |
| Undo/Redo | Operation stack + file management | #333 |
| Theming | Keyboard shortcuts + dark mode | #334 |
Purpose: Multi-tool CLI binary with subcommands.
Binaries:
xfa-cli— main CLI entry pointxfa-collector— corpus data collectionedge-case-report/edge-case-analyzer— edge case analysisaccuracy-report— rendering accuracy reportingcorpus-render— batch rendering
Purpose: Async HTTP API server for PDF processing.
Stack: Axum + Tokio (async runtime).
┌─────────────────────────────────────────────────────────────────┐
│ xfa-test-runner │
│ ┌──────────────┐ ┌──────────────┐ ┌───────────────────────┐ │
│ │ Corpus │ │ Oracles │ │ Results Database │ │
│ │ Manager │ │ │ │ │ │
│ │ │ │ veraPDF 1.28 │ │ SQLite per run │ │
│ │ 181K PDFs │ │ PDFium │ │ Trend tracking │ │
│ │ 32K stress │ │ Poppler │ │ Regression detection │ │
│ │ 974 curated │ │ pdftotext │ │ Oracle result cache │ │
│ └───────────────┘ └──────────────┘ └───────────────────────┘ │
│ │
│ 25 test modules, 4 tiers: │
│ Fast (7): parse, metadata, geometry, bookmarks, │
│ signatures, form_fields, annotations │
│ Standard (4): + render, text_extract, compliance, search │
│ Full (14): + text_oracle, metadata_oracle, manipulation, │
│ images, sign_verify, sign_roundtrip, form_write, │
│ annot_create, content_roundtrip, text_replace, │
│ redact, pdfa_convert, ocr, render_oracle │
│ Oracle (2): text_oracle, metadata_oracle │
└─────────────────────────────────────────────────────────────────┘
| Crate | Test modules | Tier |
|---|---|---|
pdf-syntax |
parse, metadata, content_roundtrip | Fast/Full |
pdf-interpret |
render, text_extract | Standard |
pdf-font |
render, pdfa_convert | Standard/Full |
cff-parser |
pdfa_convert (CID width fix #423) | Full |
hayro-ccitt/jbig2/jpeg2000 |
images | Full |
pdf-engine |
geometry, bookmarks, manipulation | Fast/Full |
pdf-forms |
form_fields, form_write | Fast/Full |
pdf-annot |
annotations, annot_create | Fast/Full |
pdf-sign |
signatures, sign_verify, sign_roundtrip | Fast/Full |
pdf-compliance |
compliance, pdfa_convert | Standard/Full |
pdf-manip |
manipulation, content_roundtrip, text_replace, redact, pdfa_convert | Full |
pdf-extract |
text_extract, search, text_oracle | Standard/Full |
pdf-redact |
redact | Full |
pdf-ocr |
ocr | Full |
pdfium-ffi-bridge |
render_oracle | Full (feature-gated) |
lopdf |
content_roundtrip, manipulation, pdfa_convert | Full |
The measurement corpus is not part of this repository, and the machine that
used to host it no longer exists: the Hetzner VPS was cancelled on 24-08-2026
and its address has since been reassigned. The address is deliberately not
repeated here -- it now answers for somebody else, and a reader who copies it
out of an architecture document points traffic at a stranger. scripts/ci/
carries a guard that refuses to let a connecting script name a literal host
for the same reason.
The corpus itself is described by shape rather than by mount point, so this table stays true wherever it is hosted:
| Component | Details |
|---|---|
| Main corpus | ~181K PDFs |
| Stressful corpus | 32,574 SafeDocs PDFs |
| veraPDF suite | the tagged veraPDF conformance set |
| Skip list | 18 entries, in the internal tree |
- 32,574 PDFs processed
- 32,190 pass / 190 fail / 191 skip / 3 timeout / 0 crashes
- 6 crashers found and fixed: page tree bomb, xref recursion (×2), predictor OOM, crypto bounds, oversized file
| Issue | Description |
|---|---|
| #349 | --rerun-failures flag for targeted reruns |
| #350 | Per-test timeout instead of per-PDF |
| #351 | Adaptive timeout escalation per tier |
| #352 | Structural content stream size guard |
| #353 | Shared per-page content stream cache |
| #354 | Show applicable pass rate metric |
| #355 | Log profiling data on timeout |
| #356 | Two-phase validation (structural → content) |
| #357 | --affected-by filter for targeted reruns |
| #358 | Incremental results via content hashing |
| #359 | Structured crash forensics table in database |
| Crate | Purpose |
|---|---|
xfa-golden-tests |
Visual regression: render → PNG → pixel diff against Adobe Reader |
pdf-bench |
Criterion benchmarks: pdf_parse, xfa_operations |
pdf-diff |
SSIM-based visual PDF comparison |
fuzz/ |
cargo-fuzz harness for parser fuzzing |
pdf-syntax → pdf-interpret → pdf-render → pdf-engine → bindings/apps
↓
pdf-font
xfa-dom-resolver → formcalc-interpreter → xfa-layout-engine → xfa-json
↓
pdf-xfa → pdf-engine
lopdf → pdf-forms (AcroForm write)
→ pdf-annot (annotation write)
→ pdf-manip (pages, fonts, encryption, PDF/A conversion)
→ pdf-redact (content removal)
→ pdf-sign (signature creation)
pdf-extract (text/images) → pdf-redact (GDPR)
→ pdf-ocr (scanned PDFs)
→ pdf-docx / pdf-xlsx / pdf-pptx (conversions)
| Crate | Depended on by |
|---|---|
pdf-syntax |
6+ internal crates |
lopdf |
10+ internal crates |
pdf-engine |
6+ internal crates + all bindings |
xfa-dom-resolver |
5 internal crates |
| Crate | Depends on |
|---|---|
xfa-cli |
12+ workspace crates |
pdf-engine |
5 workspace crates |
pdfium-ffi-bridge |
6 workspace crates |
| Crate | Version | Purpose |
|---|---|---|
lopdf |
0.39 | PDF read-write mutation |
roxmltree |
0.20 | Read-only XML DOM (XFA, XFDF) |
thiserror |
2 | Error type derivation |
image |
0.25 | Bitmap I/O (PNG, JPEG) |
flate2 |
1 | Deflate compression |
regex |
1 | Text pattern matching |
| Crate | Version | Purpose |
|---|---|---|
vello_cpu |
0.0.6 | CPU vector rasterizer |
skrifa |
0.40 | Modern font parsing |
kurbo |
0.13 | 2D geometry primitives |
ttf-parser |
0.25 | Font metrics |
| Crate | Purpose |
|---|---|
aes (0.8) |
AES-256 block cipher (used by lopdf for PDF encryption) |
cbc (0.1) |
CBC mode for AES streams |
sha2, sha1 |
Hash computation (SHA-256 for AES-256 key derivation; SHA-1 for legacy RC4) |
rand (0.9) |
Cryptographically random key/IV generation |
rsa |
RSA signatures |
p256, p384, ecdsa |
Elliptic curve signatures |
spki, der |
X.509 certificate parsing |
p12 |
PKCS#12 identity loading |
pkcs8 |
Private key parsing |
| Crate | Version | Purpose |
|---|---|---|
ort |
2.0.0-rc.12 | ONNX Runtime bindings (PaddleOCR inference) |
ndarray |
0.17 | N-dimensional arrays for model I/O |
leptess |
0.14 | Tesseract OCR bindings |
| Crate | Version | Purpose |
|---|---|---|
ureq |
2 | TSA timestamp requests (pdf-sign) |
ureq |
3 | ONNX model download (pdf-ocr) |
| Crate | Version | Purpose |
|---|---|---|
subsetter |
0.2 | Font subsetting |
xmp-writer |
0.3 | XMP metadata generation |
cff-parser |
0.2 (local fork) | CFF/Type2 font parsing; local fork adds CID glyph_width() fix (#423) |
| Crate | Version | Purpose |
|---|---|---|
pyo3 |
0.24 | Python FFI |
napi |
— | Node.js FFI |
wasm-bindgen |
— | WebAssembly FFI |
tauri |
2 | Desktop app framework |
| Crate | Purpose |
|---|---|
criterion |
Benchmarking |
pixelmatch |
Pixel-level image comparison |
tempfile |
Test file management |
- No
unsafein application code (only in FFI boundary crates) - All PDF parsing is bounds-checked — malformed PDFs cannot cause UB
- Arena-allocated data structures prevent use-after-free
| Resource | Limit | Reason |
|---|---|---|
| File size | 256 MB | Prevent OOM on oversized files |
| Decompressed stream | 64 MB | Prevent zip bomb attacks |
| Page count | 100,000 | Prevent page tree bombs |
| XRef chain depth | 64 | Prevent xref recursion |
| Inline nesting | 256 | Prevent content stream recursion |
| Struct tree depth | 100 | Prevent compliance recursion |
| Thread stack | 8 MB | Prevent stack overflow on deep recursion |
Write (encrypt):
- AES-256 (PDF 2.0, V=5, R=6, /CFM /AESV3) — primary, all bindings (Python, Node.js, Java)
- RC4-128 (V=2, R=3) — legacy, available via
EncryptionVersion::V2 - RC4-40 (V=1, R=2) — legacy, available via
EncryptionVersion::V1
Read (decrypt):
- AES-256, AES-128, RC4-128, RC4-40 — all handled by lopdf's
Document::decrypt() pdf-syntaxsupports RC4 revisions 2–4 only; AES-256-encrypted PDFs must be opened via lopdf
Implementation: lopdf::aes256_encryption_state(owner_pw, user_pw, perms) → doc.encrypt(&state) → doc.save(). Each encrypted stream uses a fresh random IV (AES-256-CBC). Decision: D008.
pdf-redact provides permanent content removal:
- Visual overlay (colored rectangles)
- Content stream surgery (operation removal)
- Metadata stripping
- No recoverable data left in output
- Zero-copy parsing —
pdf-syntaxborrows from input buffer, no allocation for object access - Lazy object resolution — objects parsed on demand, not upfront
- ObjectCache — pre-collects objects for compliance checking (single O(n) pass)
- MaybeRef — checks direct values without resolving indirect references
- vello_cpu — modern CPU rasterizer with SIMD support
- Lazy page loading — pages rendered on demand
- Thumbnail caching — pre-computed low-res page previews
- Parallel rendering — independent pages can render concurrently
- phf (perfect hash function) — O(1) lookup for built-in CMap tables
- Font subsetting — reduces embedded font size to only used glyphs
- Graceful degradation — argstack underflow returns defaults instead of panicking
- Tiered execution — fast/standard/full test tiers
- Resume support —
--resumecontinues interrupted corpus runs - Content hashing — skip unchanged PDFs in incremental runs (#358)
--limit N— cap PDF count for quick validation
| Phase | Description | Issues |
|---|---|---|
| Epic 0 | Project foundation, CI/CD, test infrastructure | #1–#4 |
| Epic 1 | XFA DOM/SOM resolution | #5–#9 |
| Epic 2 | FormCalc interpreter (90+ built-in functions) | #10–#19 |
| Epic 3 | XFA layout engine (Box Model, pagination, reflow) | #20–#32 |
| Epic 4 | Native PDF I/O and rendering (pure Rust) | #33–#38 |
| Epic 5 | Persistence and security (UR3 signatures) | #39–#42 |
| Epic 6 | Validation, benchmarks, edge case hardening | #43–#46 |
| Fase A | Workspace restructure, hayro fork integration | #143–#148 |
| Fase B | AcroForm engine (field tree, appearance, flattening) | #149–#156 |
| Fase C | Annotation engine (all ISO 32000-2 types) | #157–#161 |
| Fase D | XFA integration (packet extraction, rendering bridge) | #162–#165 |
| Fase E | Test corpus and fuzzing infrastructure | #166–#169 |
| Fase F | Rendering pipeline (pages, text extraction, thumbnails) | #170–#175 |
| Fase G | Digital signatures (PAdES, certificate chains, LTV) | #176–#179 |
| Fase H | Compliance (PDF/A validation + conversion, PDF/UA, tagged PDF) | #180–#183 |
| Fase I | C API (PDFium-compatible interface) | #184–#185 |
| Fase J | Python bindings (PyO3 + PyPI) | #186–#187 |
| Fase K | WASM + CLI tools | #188–#190 |
| Fase L | Node.js bindings (napi-rs + npm) | #191–#192 |
| Fase M | PDF manipulation (merge, split, encrypt, watermark, compress) | #194–#198 |
| Fase N | Content intelligence (OCR, redaction, extraction, search) | #199–#202 |
| Fase O | Data exchange (FDF/XFDF, ZUGFeRD/Factur-X) | #203–#205 |
| SDK Core 1 | Write APIs (forms, annotations, signatures, headers) | #300–#309 |
| SDK Core 2 | Content engine (content editor, text runs, text replace, redact) | #310–#316 |
| SDK Core 3 | Compliance conversion + document conversions | #317–#327 |
| Signing | PdfSigner + PKCS#12, CMS builder, two-pass signing, DocMDP, TSA timestamps | #396–#398 |
| OCR | PaddleOCR pipeline: DBNet detection, SVTR recognition, angle classifier, model management | #399–#401 |
| CFF fork | Local cff-parser fork with CID glyph_width() fix (FDSelect→FDArray→PrivateDict) |
#423 |
| Issue | Feature | Status |
|---|---|---|
| #328 | Tauri desktop shell (window, menu, viewport) | Done |
| #329 | Thumbnail sidebar | Done |
| #330 | Text selection and copy | Done |
| #331 | Annotation toolbar with property panel | Open |
| #332 | Print support (platform-native) | Open |
| #333 | Undo/Redo stack and file management | Open |
| #334 | Keyboard shortcuts and dark mode | Open |
| Issue | Binding | Status |
|---|---|---|
| #335 | Java (JNI) | Open |
| #336 | .NET (P/Invoke) | Open |
| #337 | iOS (Swift) | Open |
| #338 | Android (Kotlin) | Open |
| #339 | WASM extended (rendering, annotations, signing) | Open |
| #340 | API documentation for all bindings | Open |
| Issue | Feature | Status |
|---|---|---|
| #239 | Corpus expansion (GovDocs1 + SafeDocs full) | Open |
| #349–#359 | Test runner improvements (11 issues) | Open |
| #433 | Test coverage matrix: corpus augmentation, manipulation roundtrip, tier docs | Partial (see §15.1a) |
This document serves as the single source of truth for the technical architecture of XFA-Native-Rust. Update it as new features are implemented or architectural decisions change.