paperforge-pdf 0.2.0

PDF object model, serialization, and parsing
Documentation
# PaperForge

> A comprehensive, pure-Rust PDF generation, editing, inspection, rendering, and document-processing engine.

[![CI](https://github.com/Rohithdgrr/paperforge/actions/workflows/ci.yml/badge.svg)](https://github.com/Rohithdgrr/paperforge/actions)
[![Crates.io](https://img.shields.io/crates/v/paperforge)](https://crates.io/crates/paperforge)
[![Docs.rs](https://docs.rs/paperforge/badge.svg)](https://docs.rs/paperforge)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE-MIT)
[![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE-APACHE)

## Overview

PaperForge is a native Rust alternative to Python ReportLab and fragmented Rust PDF tooling. One coherent API for generating, editing, parsing, rendering, and extracting PDF documents.

## Quick Start

Add to your `Cargo.toml`:

```toml
[dependencies]
paperforge = "0.1"
```

Generate a PDF:

```rust
use paperforge::prelude::*;

fn main() -> Result<(), PdfError> {
    let mut doc = Document::new();

    let page = doc.add_page(PageSize::A4);

    page.text()
        .at(50.mm(), 250.mm())
        .font_size(24.0)
        .write("Hello, Rust!");

    doc.save("hello.pdf")?;
    Ok(())
}
```

## Features

| Feature | Status |
|---------|--------|
| PDF Generation | โœ… |
| PDF Parsing | โœ… |
| PDF Editing | ๐Ÿ”„ (merge/split via CLI + `paperforge-pdf` edit API) |
| Text + Unicode | โœ… |
| Font Embedding | ๐Ÿ”„ (loading scaffold; TTF parsing/subsetting planned) |
| JPEG/PNG Images | โœ… (JPEG pass-through, PNG decode, `/SMask`) |
| Vector Graphics | โœ… |
| Basic Layout | ๐Ÿ”„ |
| Tables | ๐Ÿ”„ |
| Forms | ๐Ÿ”„ |
| Rendering | ๐Ÿ”„ |
| Encryption | ๐Ÿ”„ |
| PDF/A | ๐Ÿ”„ |

## Architecture

```
paperforge/
โ”œโ”€โ”€ paperforge/          # Main public crate
โ”œโ”€โ”€ paperforge-core/     # PDF-independent abstractions
โ”œโ”€โ”€ paperforge-pdf/      # PDF serialization/parsing
โ”œโ”€โ”€ paperforge-layout/   # High-level document layout
โ”œโ”€โ”€ paperforge-fonts/    # Font handling
โ”œโ”€โ”€ paperforge-images/   # Image support
โ”œโ”€โ”€ paperforge-render/   # PDF rendering
โ”œโ”€โ”€ paperforge-forms/    # AcroForm support
โ”œโ”€โ”€ paperforge-annotations/ # Annotations
โ”œโ”€โ”€ paperforge-security/ # Encryption/security
โ”œโ”€โ”€ paperforge-extract/  # Text/image extraction
โ””โ”€โ”€ paperforge-cli/      # CLI tool
```

## Benchmarks

Measured with [criterion](https://github.com/bheisler/criterion.rs) (30 samples, median) on an **AMD Ryzen 5 7235HS / Windows 11** (2026-08-13). Workload: a 100-page A4 text document โ€” one heading and one body line per page โ€” built with each library's high-level (or object-level, for lopdf) API and then parsed from the same in-memory bytes. Every library builds the identical workload. Reproduce with `cargo bench -p paperforge-bench`.

| Benchmark | paperforge | lopdf 0.34 | printpdf 0.7 |
|---|---|---|---|
| Generate 100-page text doc | 1.77 ms | 482 ยตs | 6.45 ms |
| Generate, content compression off | 543 ยตs | 482 ยตs ยน | โ€” |
| Parse 100-page doc (~36 KB) | 423 ยตs | 467 ยตs | โ€” |
| Streaming open (no parse) | 129 ยตs | โ€” | โ€” |
| Output size (100 pages) | 35.9 KB | 27.4 KB | 60.9 KB |

ยน lopdf writes uncompressed streams by default; both columns use each library's default settings.

Notes:

- **Generation beats printpdf by ~3.6ร—.** paperforge (default: flate-compressed content, level 6) generates the 100-page document in 1.77 ms โ€” 3.6ร— faster than printpdf (6.45 ms). lopdf remains the fastest because its default output skips compression entirely and is object-level; with compression disabled paperforge (543 ยตs) is within ~13% of lopdf (482 ยตs) on the same uncompressed workload, down from ~20% in the previous release.
- **Parsing beats lopdf** โ€” 423 ยตs vs 467 ยตs on the same compressed 100-page document.
- **Streaming open is 3.6ร— faster than lopdf's full parse** โ€” 129 ยตs to open a file and have random access to all 205 objects, vs 467 ยตs for lopdf's parse.
- **Output is 1.7ร— smaller than printpdf** (35.9 KB vs 60.9 KB). paperforge's output is also 25% smaller than the previous release (47.7 KB) thanks to a single shared `/Resources` object referenced by every page. lopdf's 27.4 KB is uncompressed object-level output that omits required structure such as the `/Parent` link; paperforge keeps full spec compliance (ISO 32000-1).
- The speedups come from reusing zlib compressor state across content streams (4โ€“6ร— faster flate on many small streams), building content streams into a reused buffer without per-command `format!` allocations, interning common dictionary keys (`/Type`, `/Parent`, โ€ฆ) so dict inserts allocate nothing, `ryu` number formatting for content-stream coordinates, a fast hasher for dictionary keys, and manual integer/number parsing in the parser (no per-number UTF-8 validation or `str::parse`).
- The parse benchmark surfaced a real interop bug: xref table entries were 19 bytes instead of the spec-mandated 20 (ISO 32000-1 ยง7.5.4), which strict parsers such as lopdf reject. Entries are now spec-compliant, locked in by `serializer::tests::xref_entries_are_exactly_20_bytes`.
- Criterion also writes per-run reports and regression tracking to `target/criterion/`.

Full methodology and analysis are in [docs/benchmarks.md](docs/benchmarks.md).

## Feature Flags

```toml
[dependencies]
paperforge = { version = "0.1", features = ["generate", "parse", "layout", "fonts", "images"] }
```

Available features: `generate`, `parse`, `edit`, `layout`, `fonts`, `images`, `render`, `forms`, `annotations`, `security`, `extract`, `svg`.

## License

Dual-licensed under MIT OR Apache-2.0.