pdfrum 0.1.1

A composable PDF library built in Rust
Documentation
[package]
name = "pdfrum"
description = "A composable PDF library built in Rust"
version.workspace = true
edition.workspace = true
rust-version.workspace = true
license.workspace = true
repository.workspace = true
keywords = ["pdf", "render", "parse", "text", "graphics"]
categories = ["parser-implementations", "graphics", "text-processing", "multimedia::images"]

# docs.rs renders the full API, including every optional-feature type.
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]

# Copied from `[workspace.lints]` rather than `workspace = true`: Cargo
# forbids mixing the inherit flag with extra keys, and this crate adds one
# clippy lint of its own. Keep the two tables in step.
[lints.rust]
unsafe_code = "forbid"
missing_docs = "warn"

[lints.clippy]
unwrap_used = "deny"
expect_used = "deny"
panic = "deny"
pedantic = { level = "warn", priority = -1 }
module_name_repetitions = "allow"
must_use_candidate = "allow"
# Boolean parameters that mean "which mode" are enums on this crate's
# surface. `struct_excessive_bools` stays allowed on engine option structs
# that mirror oracle flag words (`pdfrum_render::RenderOptions`).
fn_params_excessive_bools = "deny"

[features]
# One rasterizer by default, so `cargo add pdfrum` renders; none with
# `default-features = false`, for a build that only parses, extracts, reads
# forms or edits. Every backend is a feature named after its rasterizer, and
# the GPU one is never in the default set.
default = ["vello-cpu", "edit", "forms", "codecs-all", "system-fonts"]
vello-cpu = ["dep:pdfrum-raster-vello-cpu"]
tiny-skia = ["dep:pdfrum-raster-tinyskia"]
agg = ["dep:pdfrum-raster-agg"]
vello-gpu = ["dep:pdfrum-raster-vello"]

# The subsystems a reader can leave out: `edit` is saving, editing and the
# font subsetter behind it; `forms` is the widget state machine. JavaScript
# needs widgets to act on, so it implies `forms`.
edit = ["dep:pdfrum-edit"]
forms = ["dep:pdfrum-form"]

# The document's own JavaScript, actually run — `pdfrum-form`'s `javascript`
# feature, forwarded.
#
# What it brings: `boa_engine` and the ~116 crates behind it, pure Rust and
# zero `-sys`. Default-off: executing untrusted script is a different
# security proposition from rendering, and most PDF work does not need it.
#
# The facade forwards the flag and owns no engine: `boa_engine` is not a
# dependency of this crate under any feature, and `ScriptCascade` lives in
# `pdfrum-form`.
javascript = ["forms", "pdfrum-form/javascript"]
# Markdown and layout-preserving text from a page: `pdfrum-markdown`, the
# structure tree where there is one and typography where there is not.
markdown = ["dep:pdfrum-markdown"]
# SVG export: `pdfrum-svg`'s `SvgBackend`, a `RasterBackend` wrapper that
# records the walk as vectors while a real rasterizer keeps painting, plus the
# report naming every region it had to fall back to pixels for. Default-off
# because an SVG is a second output format rather than part of reading a PDF,
# and because the backend is a wrapper the caller chooses to put in the way —
# a build that never exports one should not carry it.
svg-export = ["dep:pdfrum-svg"]

# An SVG drawn into a page as vectors, through `Canvas::draw_svg` inline or
# `DocEdit::compile_svg` once into a Form XObject. Needs `edit`. Default-off
# and separate from `svg-export`: import costs `usvg`; export does not.
svg-import = ["edit", "pdfrum-edit/svg-import", "dep:usvg"]

# `<text>` in an imported SVG, converted to outlines. Separate from
# `svg-import` because `usvg/text` pulls a second font stack (`rustybuzz`,
# `ttf-parser`, a second `fontdb`). Faces come from the caller through
# `SvgFonts`; `usvg`'s `system-fonts` / `memmap-fonts` stay off.
svg-text = ["svg-import", "pdfrum-edit/svg-text", "usvg/text"]

# The specialised image codecs. Flate and JPEG are always in; these three
# are what a build that will never meet them can leave out.
codecs-all = ["jpeg2000", "jbig2", "ccitt"]

# Substitute a missing font from the host's installed ones; off, the bundled
# base-14 faces alone answer. Never compiled into a WebAssembly build.
system-fonts = ["pdfrum-font/system-fonts"]
jpeg2000 = ["pdfrum-page/jpeg2000"]
jbig2 = ["pdfrum-page/jbig2"]
ccitt = ["pdfrum-page/ccitt", "pdfrum-filters/ccitt"]

# `Pixmap::encode_png` and `Pixmap::save_png`, for a caller who wants a file
# without choosing an encoder.
png = ["pdfrum-render/png"]

# The whole-render stage timers, forwarded down to `pdfrum-page` where the
# accumulator lives and across to `pdfrum-doc`, which times the annotation
# pass's five stages. Default-off, and it is not a published capability: the
# flag exists so `pdfrum-bench`'s `profile` binary can measure the pipeline
# `Page::paint` runs, and it adds no public item to this crate.
profiling = ["pdfrum-page/profiling", "pdfrum-doc/profiling"]

# Every published capability except the GPU rasterizer and the internal
# `profiling` timers. `vello-gpu` stays out because it pulls `wgpu`; a
# caller who wants that names it. `docs.rs` still uses `all-features`.
full = [
    "vello-cpu",
    "tiny-skia",
    "agg",
    "edit",
    "forms",
    "javascript",
    "markdown",
    "svg-export",
    "svg-import",
    "svg-text",
    "png",
    "codecs-all",
    "system-fonts",
]

[dependencies]
pdfrum-common.workspace = true
pdfrum-object.workspace = true
pdfrum-parser.workspace = true
# The facade names `pdfrum_crypt::Permissions` in `Document::permissions`,
# so it depends on the crate that owns the type rather than laundering it
# through `pdfrum-parser`.
pdfrum-crypt.workspace = true
pdfrum-font.workspace = true
pdfrum-page.workspace = true
pdfrum-filters.workspace = true
pdfrum-render.workspace = true
# The rasterizers, every one optional and each behind the feature of its
# name; `vello-cpu` is the default. `Page::render` takes the backend as an
# argument, so the facade compiles with none of them.
pdfrum-raster-vello-cpu = { workspace = true, optional = true }
pdfrum-raster-tinyskia = { workspace = true, optional = true }
pdfrum-raster-agg = { workspace = true, optional = true }
pdfrum-raster-vello = { workspace = true, optional = true }
pdfrum-text.workspace = true
pdfrum-doc.workspace = true
pdfrum-markdown = { workspace = true, optional = true }
pdfrum-svg = { workspace = true, optional = true }
pdfrum-form = { workspace = true, optional = true }
pdfrum-edit = { workspace = true, optional = true }
# SVG import, behind `svg-import`. Defaults off: `text`, `system-fonts`
# and `memmap-fonts` would pull a second font stack.
usvg = { workspace = true, optional = true }
kurbo.workspace = true
peniko.workspace = true
thiserror.workspace = true


[dev-dependencies]
# The facade spawns no thread and builds no pool; `rayon` is what the
# parallel-render example and the test that pins it use, and nothing a
# `cargo add pdfrum` caller compiles.
rayon.workspace = true
# Encoding a pixmap is not the engine's job — the facade hands out pixels and
# the examples turn them into files.
png.workspace = true

# The other two CPU rasterizers. `tests/facade.rs` asserts every backend
# renders the same page at the same size.
pdfrum-raster-tinyskia.workspace = true
pdfrum-raster-agg.workspace = true

# Already a normal dependency; an integration test is its own crate.
pdfrum-render.workspace = true

# Filter chain, for `tests/canvas.rs` reading back a flate-compressed stream.
pdfrum-filters.workspace = true
# Ingestion round trip (`tests/svg_ingest.rs`): render the fixture SVG with
# a second implementation and score our page against it. Dev-only.
resvg.workspace = true
# An integration test is its own crate and can only `use` what the manifest
# lists for it: `tests/svg_ingest.rs` names `Diagnostics` to render the page
# it ingested into. Already a normal dependency of this crate.
pdfrum-common.workspace = true
# The 44-file benchmark corpus, for `tests/pdfa_oracle.rs`. It is the same
# list `pdfrum-svg`'s round trip scores over, so the two oracle stories
# describe the same documents. A leaf crate with no dependencies of its own.
pdfrum-corpus.workspace = true

# Which features each integration test needs. The three not listed —
# signatures, searchex, thumbnails — run on any feature set; the rest
# exercise rendering, editing or forms, or name their types.
[[test]]
name = "attachments"
required-features = ["vello-cpu", "edit", "forms"]

[[test]]
name = "canvas"
required-features = ["vello-cpu", "edit", "forms"]

[[test]]
name = "embed_image"
required-features = ["vello-cpu", "edit", "forms"]

[[test]]
name = "facade"
required-features = ["vello-cpu", "edit", "forms"]

[[test]]
name = "flatten"
required-features = ["vello-cpu", "edit", "forms"]

[[test]]
name = "form_actions"
required-features = ["vello-cpu", "edit", "forms"]

[[test]]
name = "form_choice"
required-features = ["vello-cpu", "edit", "forms"]

[[test]]
name = "form_listbox"
required-features = ["vello-cpu", "edit", "forms"]

[[test]]
name = "form_routing"
required-features = ["vello-cpu", "edit", "forms"]

[[test]]
name = "form_scripts"
required-features = ["vello-cpu", "edit", "forms"]

[[test]]
name = "form_substitution"
required-features = ["vello-cpu", "edit", "forms"]

[[test]]
name = "form_tab"
required-features = ["vello-cpu", "edit", "forms"]

[[test]]
name = "form_toggle"
required-features = ["vello-cpu", "edit", "forms"]

[[test]]
name = "load_font"
required-features = ["vello-cpu", "edit", "forms"]

[[test]]
name = "load_font_subset"
required-features = ["vello-cpu", "edit", "forms"]

[[test]]
name = "mutation"
required-features = ["vello-cpu", "edit", "forms"]

[[test]]
name = "prepared_page"
required-features = ["vello-cpu", "edit", "forms"]

[[test]]
name = "owned"
required-features = ["vello-cpu", "edit", "forms"]

[[test]]
name = "subset"
required-features = ["vello-cpu", "edit", "forms"]

# The examples render, edit or both; none runs on the headless set.
[[example]]
name = "extract-text"
required-features = ["vello-cpu", "edit", "forms"]

[[example]]
name = "header-rule"
required-features = ["vello-cpu", "edit", "forms"]

[[example]]
name = "fill-form-and-save"
required-features = ["vello-cpu", "edit", "forms"]

[[example]]
name = "parallel-render"
required-features = ["vello-cpu", "edit", "forms"]

[[example]]
name = "render-to-png"
required-features = ["vello-cpu", "edit", "forms"]

[[example]]
name = "subset_dump"
required-features = ["vello-cpu", "edit", "forms"]

[[example]]
name = "watermark"
required-features = ["vello-cpu", "edit", "forms"]

[[test]]
name = "reexports"
required-features = ["vello-cpu", "edit", "forms"]

[[test]]
name = "construct_enums"
required-features = ["vello-cpu", "edit", "forms"]

[[test]]
name = "svg_export"
required-features = ["vello-cpu", "svg-export"]

[[test]]
name = "svg_ingest"
required-features = ["svg-import", "tiny-skia"]

[[test]]
name = "pdfa_oracle"
required-features = ["vello-cpu", "edit", "forms"]

[[test]]
name = "svg_form"
required-features = ["svg-import"]

[[test]]
name = "limits"
required-features = ["vello-cpu"]

[[test]]
name = "metadata"
required-features = ["edit"]

[[test]]
name = "pdfa_convert"
required-features = ["edit"]

[[test]]
name = "stamp"
required-features = ["vello-cpu", "edit"]

[[test]]
name = "thumbnails"
required-features = ["vello-cpu"]

[[test]]
name = "traits"
required-features = ["vello-cpu"]