High-performance HTML5 to PDF renderer built in Rust
Project description
Fullbleed
Deterministic, dependency-free HTML/CSS-to-PDF generation in Rust, with a Python-first CLI and Python engine bindings.
License: AGPLv3 for OSS use; commercial license available for proprietary/closed-source production.
- Install:
pip install fullbleed - Try:
fullbleed init . && python report.py - Outputs:
output/report.pdf - Deterministic + reproducible (
--repro-record/--repro-check) - Agent-safe JSON schemas (
--json-only,--schema)
Positioning
Fullbleed is a deterministic, offline-first document rendering engine for transactional/VDP pipelines (not a browser, not a hosted web-to-print SaaS).
HTML and CSS are used as a familiar DSL for layout, styling, and data placement in transactional documents.
This README is the canonical usage guide for:
fullbleedCLI (human workflows + machine/agent automation)fullbleedPython bindings (PdfEngine,AssetBundle, batch APIs)
Additional focused references are in docs/:
docs/install-non-technical.md(step-by-step setup for non-technical users)docs/css-coverage.md(validated CSS coverage, parity status, and active gaps)docs/README.mddocs/engine.mddocs/python-api.mddocs/ui-accessibility.mddocs/cli.mddocs/pdf-templates.md
What You Get
- No headless browser requirement for PDF generation.
- Deterministic render pipeline with optional SHA256 output hashing.
- Reproducibility workflow via
--repro-recordand--repro-check. - PDF
1.7as the production-stable default target. - Rust-native PDF template composition for VDP/transactional overlays.
- Native Rust image emission for overlay and finalized compose outputs (
--emit-image) without external PDF raster runtime dependencies. - Feature-driven page-to-template binding with per-page deterministic compose plans.
- Structured JSON result schemas for CI and AI agents.
- Offline-first asset model with explicit remote opt-in.
- Remote project template registry workflows (
new list,new search,new remote). - Python-first extension surface for hackability and custom workflows.
- Python render calls release the GIL while Rust rendering executes.
- Rayon-backed parallelism for batch rendering and selected internal engine workloads.
Concurrency Model
- Python binding render methods release the GIL during Rust execution (
py.allow_threads(...)in the bridge). - Parallel batch APIs are explicitly Rayon-backed (
render_pdf_batch_parallel(...)and parallel-to-file variants). - The engine also uses Rayon in selected internal hotspots (for example table layout and JIT paint paths).
- Do not assume every single-document render path will fully saturate all cores end-to-end.
Install
New to Python or setting up on a fresh machine? Start with docs/install-non-technical.md.
python -m pip install fullbleed
From a local wheel:
python -m pip install C:\path\to\fullbleed-0.6.5-cp311-cp311-win_amd64.whl
Platform artifact policy:
- Linux (
manylinux) and Windows wheels are built as release artifacts. - Linux wheel builds are smoke-tested in Ubuntu/WSL during release prep.
- macOS wheel artifacts are built in CI, but are currently maintainer-untested.
- If macOS wheel behavior differs from your environment, open an issue and include
fullbleed doctor --json.
Verify command surface:
fullbleed --help
fullbleed capabilities --json
fullbleed doctor --json
60-Second Quick Start (Project Happy Path)
Initialize project scaffold:
fullbleed init .
fullbleed init now vendors Bootstrap (5.0.0) into vendor/css/bootstrap.min.css,
vendors Bootstrap Icons (1.11.3) into vendor/icons/bootstrap-icons.svg,
vendors inter into vendor/fonts/Inter-Variable.ttf, writes license notices
(vendor/css/LICENSE.bootstrap.txt, vendor/icons/LICENSE.bootstrap-icons.txt, vendor/fonts/LICENSE.inter.txt),
and seeds assets.lock.json with pinned hashes.
The scaffolded report.py also runs a component mount smoke validation before
main render and writes output/component_mount_validation.json (fails fast on
missing glyphs, placement overflow, or CSS miss signals parsed from debug logs).
Scaffolded components now include components/primitives.py with reusable
layout/content helpers (Stack, Row, Text, table/list helpers, key/value rows, etc.).
Each scaffolded project also includes SCAFFOLDING.md, which should be your
first read before restructuring components.
Install additional project assets (defaults to ./vendor/... in project context):
fullbleed assets install inter --json
Bootstrap baseline note:
- We target Bootstrap (
5.0.0) as the default styling baseline for project workflows. - Re-run
fullbleed assets install bootstrap --jsononly if you want to explicitly refresh/bootstrap-manage outsideinit.
Render using the scaffolded component pipeline:
python report.py
Expected artifacts from scaffolded report.py:
output/report.pdfoutput/report_page1.png(or equivalent page preview from engine image APIs)output/component_mount_validation.jsonoutput/css_layers.json
Project Bootstrap Templates (fullbleed new)
Use local starters:
fullbleed new local invoice ./my-invoice
fullbleed new local statement ./my-statement
fullbleed new local accessible ./my-accessible-doc
Discover remote starters from registry:
fullbleed new list --json
fullbleed new search i9 --tag vdp --json
fullbleed new remote i9-stamped-vdp ./i9-job --json
fullbleed new local accessible is the verbose accessibility-first starter and
demonstrates the fullbleed.accessibility runtime surface (engine verifier,
PMR, PDF/UA-targeted seed checks, and non-visual trace artifacts).
Optional registry override (for private/canary registries):
fullbleed new list --registry https://example.com/manifest.json --json
or:
set FULLBLEED_TEMPLATE_REGISTRY=https://example.com/manifest.json
fullbleed new search statement --json
Scaffold-First Workflow (Recommended)
fullbleed init is designed for component-first authoring rather than a single large HTML template.
Typical scaffold layout:
.
|-- SCAFFOLDING.md
|-- COMPLIANCE.md
|-- report.py
|-- components/
| |-- fb_ui.py
| |-- primitives.py
| |-- header.py
| |-- body.py
| |-- footer.py
| `-- styles/
| |-- primitives.css
| |-- header.css
| |-- body.css
| `-- footer.css
|-- styles/
| |-- tokens.css
| `-- report.css
|-- vendor/
| |-- css/
| |-- fonts/
| `-- icons/
`-- output/
Best-practice authoring model:
- Read
SCAFFOLDING.mdfirst for project conventions. - Keep composition and data loading in
report.py. - Keep reusable component building blocks in
components/primitives.py. - Keep section markup in
components/header.py,components/body.py,components/footer.py. - Keep component-local styles in
components/styles/*.css. - Keep page tokens/composition styles in
styles/tokens.cssandstyles/report.css.
Recommended CSS layer order:
styles/tokens.csscomponents/styles/primitives.csscomponents/styles/header.csscomponents/styles/body.csscomponents/styles/footer.cssstyles/report.css
Recommended iteration loop:
- Edit data loading + component props in
report.py. - Edit component markup in
components/*.py. - Edit styles in
components/styles/*.cssandstyles/*.css. - Run
python report.py. - Review
output/report_page1.png,output/component_mount_validation.json, andoutput/css_layers.json.
Optional scaffold diagnostics:
FULLBLEED_DEBUG=1to emit JIT traces.FULLBLEED_PERF=1to emit perf traces.FULLBLEED_EMIT_PAGE_DATA=1to persist page data JSON.FULLBLEED_IMAGE_DPI=144(or higher) for preview resolution.FULLBLEED_VALIDATE_STRICT=1for stricter validation gates in CI.
One-off Quick Render (No Project Scaffold)
Render inline HTML/CSS with reproducibility artifacts:
fullbleed --json render \
--html-str "<html><body><h1>Hello</h1></body></html>" \
--css-str "body{font-family:sans-serif}" \
--emit-manifest build/render.manifest.json \
--emit-jit build/render.jit.jsonl \
--emit-perf build/render.perf.jsonl \
--deterministic-hash build/render.sha256 \
--repro-record build/render.repro.json \
--out output/hello.pdf
--deterministic-hash writes the output PDF SHA-256 by default; when --emit-image is enabled, it writes an artifact-set digest (fullbleed.artifact_digest.v1) over PDF SHA-256 plus ordered page-image SHA-256 hashes. JSON outputs expose outputs.deterministic_hash_mode (pdf_only or artifact_set_v1), with outputs.artifact_sha256 and outputs.image_sha256 when images are emitted.
Re-run and enforce reproducibility against a stored record:
fullbleed --json render \
--html templates/report.html \
--css templates/report.css \
--repro-check build/render.repro.json \
--out output/report.rerun.pdf
Generate PNG page artifacts from an existing validation render:
fullbleed --json verify \
--html templates/report.html \
--css templates/report.css \
--emit-pdf output/report.verify.pdf \
--emit-image output/report_verify_pages \
--image-dpi 200
Compile-only plan (no render):
fullbleed --json plan \
--html templates/report.html \
--css templates/report.css
Template compose planning (no finalize write):
fullbleed --json plan \
--html templates/overlay.html \
--css templates/overlay.css \
--template-binding config/template_binding.json \
--templates config/template_catalog.json \
--emit-compose-plan output/compose_plan.json
PDF Template Composition (VDP / Transactional)
When overlaying variable data onto a source PDF, use the built-in Rust template compose path.
Minimal CLI auto-compose flow:
fullbleed --json render \
--html templates/overlay.html \
--css templates/overlay.css \
--asset templates/source.pdf --asset-kind pdf --asset-name source-template \
--template-binding config/template_binding.json \
--templates config/template_catalog.json \
--out output/composed.pdf
Compose image semantics:
- In template auto-compose mode,
--emit-imagePNGs are rasterized from finalized composed pages and reportoutputs.image_mode=composed_pdf. - In non-compose
render/verifyruns,--emit-imagereportsoutputs.image_mode=overlay_document.
Minimal template_binding example:
{
"default_template_id": "source-template",
"feature_prefix": "fb.feature.",
"by_feature": {
"front": "source-template",
"back_blank": "source-template"
}
}
Python API compose flow:
import fullbleed
engine = fullbleed.PdfEngine(template_binding=binding_spec)
overlay_bytes, _page_data, _bindings = engine.render_pdf_with_page_data_and_template_bindings(html, css)
open("output/overlay.pdf", "wb").write(overlay_bytes)
plan_result = engine.plan_template_compose(
html,
css,
[("source-template", "templates/source.pdf")],
0.0,
0.0,
)
plan = [
(
row["template_id"],
row["template_page"],
row["overlay_page"],
row["dx"],
row["dy"],
)
for row in plan_result["plan"]
]
fullbleed.finalize_compose_pdf(
[("source-template", "templates/source.pdf")],
plan,
"output/overlay.pdf",
"output/composed.pdf",
annotation_mode="link_only", # optional: link_only | none | carry_widgets
)
See docs/pdf-templates.md and examples/template-flagging-smoke/ for full production examples.
CLI Command Map
| Command | Purpose | JSON Schema |
|---|---|---|
render |
Render HTML/CSS to PDF with optional PNG page artifacts | fullbleed.render_result.v1 |
verify |
Validation render path with optional PDF and PNG emits | fullbleed.verify_result.v1 |
plan |
Compile/normalize inputs into manifest + warnings | fullbleed.plan_result.v1 |
run |
Render using Python module/file engine factory | fullbleed.run_result.v1 |
inspect pdf |
Inspect PDF metadata and composition compatibility | fullbleed.inspect_pdf.v1 |
inspect pdf-batch |
Inspect multiple PDFs with per-file status | fullbleed.inspect_pdf_batch.v1 |
inspect templates |
Inspect template catalog metadata/compatibility | fullbleed.inspect_templates.v1 |
compliance |
License/compliance report for legal/procurement | fullbleed.compliance.v1 |
debug-perf |
Summarize perf JSONL logs | fullbleed.debug_perf.v1 |
debug-jit |
Filter/inspect JIT JSONL logs | fullbleed.debug_jit.v1 |
doctor |
Runtime capability and health checks | fullbleed.doctor.v1 |
capabilities |
Machine-readable command/engine capabilities | fullbleed.capabilities.v1 |
assets list |
Installed and optional remote packages | fullbleed.assets_list.v1 |
assets info |
Package details + hashes/sizes | fullbleed.assets_info.v1 |
assets install |
Install builtin/remote package | fullbleed.assets_install.v1 |
assets verify |
Validate package and optional lock constraints | fullbleed.assets_verify.v1 |
assets lock |
Write/update assets.lock.json |
fullbleed.assets_lock.v1 |
cache dir |
Cache location | fullbleed.cache_dir.v1 |
cache prune |
Remove old cached packages | fullbleed.cache_prune.v1 |
init |
Initialize project scaffold | fullbleed.init.v1 |
new |
Create starter template files or query/install remote templates | fullbleed.new_template.v1, fullbleed.new_list.v1, fullbleed.new_search.v1, fullbleed.new_remote.v1 |
Schema discovery for any command/subcommand:
fullbleed --schema render
fullbleed --schema assets verify
fullbleed --schema inspect pdf
fullbleed --schema inspect templates
CLI Flags That Matter Most
Global machine flags:
--json: structured result payload to stdout--json-only: implies--jsonand--no-prompts--schema: emit schema definition and exit--no-prompts: disable interactive prompts--config: load defaults from a config file--log-level error|warn|info|debug: control CLI log verbosity--no-color: disable ANSI color output--version: print CLI version and exit
Render/verify/plan key flags:
- Inputs:
--html,--html-str,--css,--css-str--htmlaccepts.svgfiles for direct SVG-document rendering;--html-straccepts inline SVG markup. - Page setup:
--page-size,--page-width,--page-height,--margin,--page-margins - Engine toggles:
--reuse-xobjects,--svg-form-xobjects,--svg-raster-fallback,--shape-text,--unicode-support,--unicode-metrics - PDF/compliance:
--pdf-version,--pdf-profile,--color-space,--document-lang,--document-titleStable default is--pdf-version 1.7for shipping workflows. Output intent metadata (--output-intent-identifier|--output-intent-info|--output-intent-components) requires--output-intent-icc. - Watermarking:
--watermark-text,--watermark-html,--watermark-image,--watermark-layer,--watermark-semantics,--watermark-opacity,--watermark-rotation - Artifacts:
--emit-jit,--emit-perf,--emit-glyph-report,--emit-page-data,--emit-compose-plan,--emit-image,--image-dpi,--deterministic-hash - Assets:
--asset,--asset-kind,--asset-name,--asset-trusted,--allow-remote-assets - Profiles:
--profile dev|preflight|prod - Fail policy:
--fail-on overflow|missing-glyphs|font-subst|budget - Fallback policy:
--allow-fallbacks(keeps fallback diagnostics, but does not failmissing-glyphs/font-substgates) - Reproducibility:
--repro-record <path>,--repro-check <path> - Budget thresholds:
--budget-max-pages,--budget-max-bytes,--budget-max-ms - Release gates:
doctor --strict,compliance --strict --max-audit-age-days <n> - Commercial attestation (compliance):
--license-mode commercial,--commercial-licensed,--commercial-license-id,--commercial-license-file
SVG Workflows
Fullbleed supports SVG in three practical CLI paths:
- Direct SVG document render via
--html <file.svg> - Inline SVG markup via
--html-str "<svg ...>...</svg>" - Referenced SVG assets via
--asset <file.svg>(kind auto-infers tosvg)
Standalone SVG file to PDF:
fullbleed --json render \
--html artwork/badge.svg \
--out output/badge.pdf
Inline SVG markup to PDF:
fullbleed --json render \
--html-str "<svg xmlns='http://www.w3.org/2000/svg' width='200' height='80'><rect width='200' height='80' fill='#0d6efd'/><text x='16' y='48' fill='white'>Hello SVG</text></svg>" \
--out output/inline-svg.pdf
HTML template with explicit SVG asset registration:
fullbleed --json render \
--html templates/report.html \
--css templates/report.css \
--asset assets/logo.svg \
--asset-kind svg \
--out output/report.pdf
SVG render behavior flags:
--svg-form-xobjects/--no-svg-form-xobjects--svg-raster-fallback/--no-svg-raster-fallback
Machine discovery:
fullbleed capabilities --json
Inspect the svg object in fullbleed.capabilities.v1 for SVG support metadata.
Per-Page Templates (page_1, page_2, page_n)
Fullbleed uses ordered page templates internally. In docs, this is easiest to think of as:
page_1: first page templatepage_2: second page templatepage_n: repeating template for later pages
Configuration mapping:
- CLI
--page-marginskeys:1,2, ... and optional"n"(or"each"alias). - Python
PdfEngine(page_margins=...): same key model. - Missing numeric pages fall back to the base
margin. - The last configured template repeats for remaining pages.
Minimal CLI example:
{
"1": {"top": "12mm", "right": "12mm", "bottom": "12mm", "left": "12mm"},
"2": {"top": "24mm", "right": "12mm", "bottom": "12mm", "left": "12mm"},
"n": {"top": "30mm", "right": "12mm", "bottom": "12mm", "left": "12mm"}
}
fullbleed --json render \
--html templates/report.html \
--css templates/report.css \
--page-margins page_margins.json \
--header-each "Statement continued - Page {page} of {pages}" \
--out output/report.pdf
Minimal Python example:
import fullbleed
engine = fullbleed.PdfEngine(
page_width="8.5in",
page_height="11in",
margin="12mm",
page_margins={
1: {"top": "12mm", "right": "12mm", "bottom": "12mm", "left": "12mm"}, # page_1
2: {"top": "24mm", "right": "12mm", "bottom": "12mm", "left": "12mm"}, # page_2
"n": {"top": "30mm", "right": "12mm", "bottom": "12mm", "left": "12mm"} # page_n
},
header_first="Account Statement",
header_each="Statement continued - Page {page} of {pages}",
footer_last="Final page",
)
Note:
- CLI currently exposes
--header-each/--footer-each(and--header-html-each/--footer-html-each). - For
first/lastheader/footer variants (header_first,header_last,footer_first,footer_last), use the Python API.
Asset Workflow (CLI)
List installed + available packages:
fullbleed assets list --available --json
Install builtin assets:
fullbleed assets install bootstrap
fullbleed assets install bootstrap-icons
# `@bootstrap` / `@bootstrap-icons` are also supported aliases
PowerShell note:
- Quote
@aliases (for example"@bootstrap") to avoid shell parsing surprises.
Install remote asset package:
fullbleed assets install inter
Install broad Unicode fallback package (larger font payload):
fullbleed assets install noto-sans
Install to a custom vendor directory:
fullbleed assets install bootstrap --vendor ./vendor
Install to global cache:
fullbleed assets install inter --global
Install common barcode fonts (license-safe defaults):
fullbleed assets install libre-barcode-128
fullbleed assets install libre-barcode-39
fullbleed assets install libre-barcode-ean13-text
Verify against lock file with strict failure:
fullbleed assets verify inter --lock --strict --json
Preview cache cleanup without deleting files:
fullbleed cache prune --max-age-days 30 --dry-run --json
Notes:
- Builtin packages accept both plain and
@references (bootstrap==@bootstrap,bootstrap-icons==@bootstrap-icons,noto-sans==@noto-sans). noto-sansis available as a builtin fallback package, but it is intentionally larger thaninter; use it when your document requires broader glyph coverage.- Project installs default to
./vendor/when project markers are present (assets.lock.json,report.py, orfullbleed.tomlin CWD). - If no project markers are found,
assets installdefaults to global cache unless--vendoris explicitly set. - Do not hardcode cache paths like
%LOCALAPPDATA%/fullbleed/cache/...; useassets install --jsonand consumeinstalled_to. - Installed assets include license files in typed vendor directories (for example
vendor/fonts/,vendor/css/). assets lock --addis currently aimed at builtin package additions.- Barcode packages in the remote registry are currently OFL-1.1 families from Google Fonts (
Libre Barcode). - USPS IMB fonts are not currently auto-installable via
assets install; use local vetted font files and track licensing separately.
Bootstrap Vendoring
Bootstrap builtin package details:
- Package:
bootstrap(alias:@bootstrap) - Bundled version:
5.0.0 - Asset kind: CSS (
bootstrap.min.css) - Default install location:
vendor/css/bootstrap.min.css(project mode) - License:
MIT - License source:
https://raw.githubusercontent.com/twbs/bootstrap/v5.0.0/LICENSE
Bootstrap Icons builtin package details:
- Package:
bootstrap-icons(alias:@bootstrap-icons) - Bundled version:
1.11.3 - Asset kind: SVG sprite (
bootstrap-icons.svg) - Default install location:
vendor/icons/bootstrap-icons.svg(project mode) - License:
MIT - License source:
https://raw.githubusercontent.com/twbs/icons/v1.11.3/LICENSE
Bootstrap notes:
- Bootstrap is vendored and installable through the asset pipeline.
- Bootstrap CSS is consumed as an explicit local asset (
--asset @bootstraporAssetBundle); external HTML<link rel="stylesheet">is not an execution path. - Bootstrap preflight examples remain useful smoke examples, but they are not the canonical source of CSS parity claims.
Validated CSS Coverage
For the full, maintained coverage statement, see docs/css-coverage.md.
Summary as of February 21, 2026:
- Tracked CSS modules:
22 - Module state:
22/22 in_progress - Full CSS fixture lane:
85/85passing - Parity status check: green (
tools/generate_css_parity_status.py --check --json) - Canonical validation artifact:
_css_working/css_parity_status.json - Canonical validation artifact:
_css_working/tmp/fixture_full_latest.json - Canonical validation artifact:
_css_working/css_broad_coverage_sprint_s14.md
Current validated behavior includes first-class parser -> evaluator -> calculator -> layout/paint coverage across broad static-document CSS domains (values math, layout primitives, pagination/fragmentation baselines, transforms phase-1, gradient/effects subsets, and deterministic diagnostics).
Known gap categories are explicitly tracked for the final parity push:
- filter/backdrop-filter function breadth beyond current subset
- clip-path shapes beyond
inset(...) - blend-mode and isolation breadth
- multi-shadow list semantics
- multi-layer background compositing
- table layout edge semantics hardening
run Command (Python Factory Interop)
run lets the CLI use a Python-created engine instance.
report.py:
import fullbleed
def create_engine():
return fullbleed.PdfEngine(page_width="8.5in", page_height="11in", margin="0.5in")
CLI invocation:
fullbleed --json run report:create_engine \
--html-str "<h1>From run</h1>" \
--css templates/report.css \
--out output/report.pdf
Entrypoint formats:
module_name:factory_or_enginepath/to/file.py:factory_or_engine
Python API Quick Start
import fullbleed
engine = fullbleed.PdfEngine(
page_width="8.5in",
page_height="11in",
margin="0.5in",
pdf_version="1.7",
pdf_profile="none",
color_space="rgb",
)
html = "<html><body><h1>Invoice</h1><p>Hello.</p></body></html>"
css = "body { font-family: sans-serif; }"
bytes_written = engine.render_pdf_to_file(html, css, "output/invoice.pdf")
print(bytes_written)
Register local assets with AssetBundle:
import fullbleed
bundle = fullbleed.AssetBundle()
bundle.add_file("vendor/css/bootstrap.min.css", "css", name="bootstrap")
bundle.add_file("vendor/fonts/Inter-Variable.ttf", "font", name="inter")
engine = fullbleed.PdfEngine(page_width="8.5in", page_height="11in")
engine.register_bundle(bundle)
engine.render_pdf_to_file("<h1>Styled</h1>", "", "output/styled.pdf")
Python API Signatures (Runtime-Verified)
These signatures are verified from the installed package via inspect.signature(...).
PdfEngine constructor:
PdfEngine(
page_width=None,
page_height=None,
margin=None,
page_margins=None,
font_dirs=None,
font_files=None,
reuse_xobjects=True,
svg_form_xobjects=False,
svg_raster_fallback=False,
unicode_support=True,
shape_text=True,
unicode_metrics=True,
pdf_version=None,
pdf_profile=None,
output_intent_icc=None,
output_intent_identifier=None,
output_intent_info=None,
output_intent_components=None,
color_space=None,
document_lang=None,
document_title=None,
header_first=None,
header_each=None,
header_last=None,
header_x=None,
header_y_from_top=None,
header_font_name=None,
header_font_size=None,
header_color=None,
header_html_first=None,
header_html_each=None,
header_html_last=None,
header_html_x=None,
header_html_y_from_top=None,
header_html_width=None,
header_html_height=None,
footer_first=None,
footer_each=None,
footer_last=None,
footer_x=None,
footer_y_from_bottom=None,
footer_font_name=None,
footer_font_size=None,
footer_color=None,
watermark=None,
watermark_text=None,
watermark_html=None,
watermark_image=None,
watermark_layer="overlay",
watermark_semantics="artifact",
watermark_opacity=0.15,
watermark_rotation=0.0,
watermark_font_name=None,
watermark_font_size=None,
watermark_color=None,
paginated_context=None,
jit_mode=None,
debug=False,
debug_out=None,
perf=False,
perf_out=None,
)
Module exports:
PdfEngineAssetBundleAssetAssetKindWatermarkSpec(kind, value, layer='overlay', semantics=None, opacity=0.15, rotation_deg=0.0, font_name=None, font_size=None, color=None)concat_css(parts)vendored_asset(source, kind, name=None, trusted=False, remote=False)inspect_pdf(path)inspect_template_catalog(templates)finalize_stamp_pdf(template, overlay, out, page_map=None, dx=0.0, dy=0.0)finalize_compose_pdf(templates, plan, overlay, out, annotation_mode='link_only')fetch_asset(url)
PdfEngine methods:
| Method | Return shape |
|---|---|
register_bundle(bundle) |
None |
render_pdf(html, css, deterministic_hash=None) |
bytes |
render_pdf_to_file(html, css, path, deterministic_hash=None) |
int (bytes written) |
render_image_pages(html, css, dpi=150) |
list[bytes] |
render_image_pages_to_dir(html, css, out_dir, dpi=150, stem=None) |
list[str] |
render_finalized_pdf_image_pages(pdf_path, dpi=150) |
list[bytes] |
render_finalized_pdf_image_pages_to_dir(pdf_path, out_dir, dpi=150, stem=None) |
list[str] |
render_pdf_with_glyph_report(html, css) |
(bytes, list) |
render_pdf_with_page_data(html, css) |
(bytes, page_data_or_none) |
render_pdf_with_page_data_and_glyph_report(html, css) |
(bytes, page_data_or_none, glyph_report_list) |
render_pdf_with_page_data_and_template_bindings(html, css) |
(bytes, page_data_or_none, template_bindings_or_none) |
render_pdf_with_page_data_and_template_bindings_and_glyph_report(html, css) |
(bytes, page_data_or_none, template_bindings_or_none, glyph_report_list) |
plan_template_compose(html, css, templates, dx=0.0, dy=0.0) |
dict |
render_pdf_batch(html_list, css, deterministic_hash=None) |
bytes |
render_pdf_batch_parallel(html_list, css, deterministic_hash=None) |
bytes |
render_pdf_batch_to_file(html_list, css, path, deterministic_hash=None) |
int |
render_pdf_batch_to_file_parallel(html_list, css, path, deterministic_hash=None) |
int |
render_pdf_batch_to_file_parallel_with_page_data(html_list, css, path, deterministic_hash=None) |
(bytes_written, page_data_list) |
render_pdf_batch_with_css(jobs, deterministic_hash=None) |
bytes |
render_pdf_batch_with_css_to_file(jobs, path, deterministic_hash=None) |
int |
When deterministic_hash is set, engine writes PDF SHA-256 to the provided file path.
AssetBundle methods:
add_file(path, kind, name=None, trusted=False, remote=False)add(asset)assets_info()css()
Python Examples (Smoke-Checked)
Text watermark + diagnostics:
import fullbleed
engine = fullbleed.PdfEngine(
page_width="8.5in",
page_height="11in",
margin="0.5in",
pdf_version="1.7",
watermark_text="INTERNAL",
watermark_layer="overlay",
watermark_semantics="artifact",
watermark_opacity=0.12,
watermark_rotation=-32.0,
debug=True,
debug_out="build/invoice.jit.jsonl",
perf=True,
perf_out="build/invoice.perf.jsonl",
)
html = "<h1>Invoice</h1><p>Status: Ready</p>"
css = "h1{margin:0 0 8px 0} p{margin:0}"
written = engine.render_pdf_to_file(html, css, "output/invoice_watermarked.pdf")
print("bytes:", written)
Batch render + glyph/page-data checks:
import fullbleed
engine = fullbleed.PdfEngine(page_width="8.5in", page_height="11in", margin="0.5in")
jobs = [
("<h1>Batch A</h1><p>Alpha</p>", "h1{color:#0d6efd}"),
("<h1>Batch B</h1><p>Beta</p>", "h1{color:#198754}"),
]
written = engine.render_pdf_batch_with_css_to_file(jobs, "output/batch.pdf")
print("batch bytes:", written)
pdf_bytes, glyph_report = engine.render_pdf_with_glyph_report("<p>Hello</p>", "")
print("glyph entries:", len(glyph_report))
pdf_bytes, page_data = engine.render_pdf_with_page_data("<p>Hello</p>", "")
print("page data available:", page_data is not None)
Transactional Header/Footer + Totals
Minimal, self-contained Python example (no external template files) showing:
- Continued headers on page 2+.
- Per-page subtotal footer expansion via
{sum:items.amount}. - Final-page grand total footer expansion via
{total:items.amount}. - Structured
page_datatotals for automation and reconciliation checks.
from pathlib import Path
import fullbleed
rows = []
for i in range(1, 121): # enough rows to force multiple pages
amount = 10.00 + ((i * 7) % 23) + 0.25
rows.append(
f'<tr data-fb="items.amount={amount:.2f}">'
f"<td>2026-01-{(i % 28) + 1:02d}</td>"
f"<td>Txn {i:03d}</td>"
f'<td class="num">${amount:.2f}</td>'
"</tr>"
)
html = f"""<!doctype html>
<html>
<body>
<h1>Monthly Statement</h1>
<table>
<thead>
<tr><th>Date</th><th>Description</th><th class="num">Amount</th></tr>
</thead>
<tbody>
{''.join(rows)}
</tbody>
</table>
</body>
</html>
"""
css = """
body { font-family: sans-serif; font-size: 10pt; color: #111; }
h1 { margin: 0 0 8pt 0; }
table { width: 100%; border-collapse: collapse; }
th, td { padding: 4pt; border-bottom: 1pt solid #e1e1e1; }
thead th { background: #f3f6fa; text-transform: uppercase; font-size: 9pt; }
.num { text-align: right; }
"""
engine = fullbleed.PdfEngine(
page_width="8.5in",
page_height="11in",
margin="12mm",
page_margins={
1: {"top": "12mm", "right": "12mm", "bottom": "12mm", "left": "12mm"},
2: {"top": "28mm", "right": "12mm", "bottom": "12mm", "left": "12mm"},
"n": {"top": "28mm", "right": "12mm", "bottom": "12mm", "left": "12mm"},
},
header_html_each=(
'<div style="display:flex;justify-content:space-between;border-bottom:1pt solid #d9d9d9;">'
'<div style="font-weight:bold;">Acme Ledger</div>'
'<div style="font-size:9pt;color:#444;">Statement Continued - Page {page} of {pages}</div>'
"</div>"
),
header_html_x="12mm",
header_html_y_from_top="6mm",
header_html_width="186mm",
header_html_height="10mm",
paginated_context={"items.amount": "sum"},
footer_each="Subtotal (Page {page}): ${sum:items.amount}",
footer_last="Grand Total: ${total:items.amount}",
footer_x="12mm",
footer_y_from_bottom="8mm",
)
pdf_bytes, page_data = engine.render_pdf_with_page_data(html, css)
Path("output_transactional_minimal.pdf").write_bytes(pdf_bytes)
assert page_data["page_count"] >= 2
assert page_data["totals"]["items.amount"]["value"] == sum(
p["items.amount"]["value"] for p in page_data["pages"]
)
print("Wrote output_transactional_minimal.pdf")
print("Page count:", page_data["page_count"])
print("Grand total:", page_data["totals"]["items.amount"]["formatted"])
API note:
- For transactional running totals (
paginated_context) and HTML header/footer placement (header_html_*,footer_html_*), use the PythonPdfEngineAPI path. - The CLI currently exposes direct text header/footer flags (
--header-each,--footer-each) for simpler cases.
CLI watermark parity example:
fullbleed --json render \
--html-str "<h1>Watermark probe</h1><p>hello</p>" \
--css-str "body{font-family:sans-serif}" \
--watermark-text "INTERNAL" \
--watermark-layer overlay \
--watermark-opacity 0.12 \
--watermark-rotation -32 \
--out output/watermark_probe.pdf
Reference-Image Parity Workflow (Practical)
When targeting a design reference image (for example reference image exports), this loop has worked well:
- Start from
fullbleed initso CSS/font/icon baselines are vendored and pinned. - For scaffolded projects, run
python report.pyand setFULLBLEED_IMAGE_DPIas needed for sharper previews. - For direct CLI template rendering, register assets through the CLI (
--asset ...) orAssetBundle. - Iterate with image artifacts enabled:
fullbleed --json render \
--profile preflight \
--html templates/invoice.html \
--css templates/invoice.css \
--asset vendor/css/bootstrap.min.css --asset-kind css --asset-name bootstrap \
--asset vendor/icons/bootstrap-icons.svg --asset-kind svg --asset-name bootstrap-icons \
--asset vendor/fonts/Inter-Variable.ttf --asset-kind font --asset-name inter \
--emit-image output/pages_png \
--emit-jit output/render.jit.jsonl \
--emit-perf output/render.perf.jsonl \
--out output/render.pdf
- Use
--repro-record/--repro-checkonce your layout stabilizes.
Practical tips:
- Compare against full-page exports when available.
- Keep a fixed preview DPI (for example
144or200) across iterations. - Commit PNG baselines for repeatable visual checks.
Public Golden Regression Suite
Launch-grade render regression coverage is available under goldens/ with three fixtures:
invoicestatementmenu
Golden contract assets:
- Expected hashes:
goldens/expected/golden_suite.expected.json - Expected PNG baselines:
goldens/expected/png/<case>/<case>_page1.png
Run against committed expectations:
python goldens/run_golden_suite.py verify
Refresh baselines intentionally:
python goldens/run_golden_suite.py generate
Human + AI Operating Mode
Recommended automation defaults:
fullbleed --json-only render ...
Why this is agent-safe:
- For command-execution JSON payloads,
schemais always present. - Parser usage errors (
exit=2) are emitted by argparse as usage text, not JSON payloads. okindicates success/failure without parsing text.- Optional artifacts are explicitly named in
outputs. - Schema introspection is available at runtime (
--schema).
Example parse loop:
import json, subprocess
proc = subprocess.run(
[
"fullbleed", "--json-only", "render",
"--html", "templates/report.html",
"--css", "templates/report.css",
"--out", "output/report.pdf",
],
capture_output=True,
text=True,
check=False,
)
payload = json.loads(proc.stdout)
assert payload["schema"] == "fullbleed.render_result.v1"
assert payload["ok"] is True
print(payload["outputs"]["pdf"])
MACHINE_CONTRACT.v1
{
"schema": "fullbleed.readme_contract.v1",
"package": "fullbleed",
"cli_entrypoint": "fullbleed",
"dev_cli_entrypoint": "python -m fullbleed_cli.cli",
"python_module": "fullbleed",
"json_discriminator": "schema",
"core_commands": [
"render",
"verify",
"plan",
"debug-perf",
"debug-jit",
"run",
"finalize",
"inspect",
"compliance",
"doctor",
"capabilities",
"assets",
"cache",
"init",
"new"
],
"result_schemas": [
"fullbleed.render_result.v1",
"fullbleed.verify_result.v1",
"fullbleed.plan_result.v1",
"fullbleed.run_result.v1",
"fullbleed.inspect_pdf.v1",
"fullbleed.inspect_pdf_batch.v1",
"fullbleed.inspect_templates.v1",
"fullbleed.compose_plan.v1",
"fullbleed.compliance.v1",
"fullbleed.capabilities.v1",
"fullbleed.doctor.v1",
"fullbleed.assets_list.v1",
"fullbleed.assets_info.v1",
"fullbleed.assets_install.v1",
"fullbleed.assets_verify.v1",
"fullbleed.assets_lock.v1",
"fullbleed.cache_dir.v1",
"fullbleed.cache_prune.v1",
"fullbleed.init.v1",
"fullbleed.new_template.v1",
"fullbleed.new_list.v1",
"fullbleed.new_search.v1",
"fullbleed.new_remote.v1",
"fullbleed.debug_perf.v1",
"fullbleed.debug_jit.v1",
"fullbleed.repro_record.v1",
"fullbleed.error.v1"
],
"artifact_flags": [
"--emit-manifest",
"--emit-jit",
"--emit-perf",
"--emit-glyph-report",
"--emit-page-data",
"--emit-compose-plan",
"--emit-image",
"--image-dpi",
"--deterministic-hash",
"--repro-record",
"--repro-check"
],
"fail_on": ["overflow", "missing-glyphs", "font-subst", "budget"],
"budget_flags": ["--budget-max-pages", "--budget-max-bytes", "--budget-max-ms"],
"profiles": ["dev", "preflight", "prod"],
"pdf_version_default": "1.7",
"known_exit_codes": {
"0": "success",
"1": "command-level validation/operational failure",
"2": "argparse usage error",
"3": "CLI runtime/input error wrapper"
}
}
Important Behavior Notes
render --jsoncannot be combined with--out -(stdout PDF bytes).verifydefaults to stdout PDF unless--emit-pdfis provided; for machine mode, use--emit-pdf <path>.--emit-image <dir>writes per-page PNGs as<stem>_pageN.png(stem comes from--out/--emit-pdf, orrenderwhen streaming PDF to stdout).- In template auto-compose runs,
--emit-imageartifacts are rasterized from finalized composed pages and reportoutputs.image_mode=composed_pdf; otherwiseimage_mode=overlay_document. outputs.deterministic_hash_modeispdf_onlyby default andartifact_set_v1when image artifacts are emitted.- If both
--emit-page-dataand--emit-glyph-reportare set, current engines use a combined API and render once; older engines without that API fall back to a double render. - Production target is PDF
1.7. runaccepts--html-strwithout requiring--html.runemits a one-time AGPL/commercial licensing reminder; suppress with--no-license-warnor by activating commercial attestation (FULLBLEED_LICENSE_MODE=commercial+FULLBLEED_COMMERCIAL_LICENSED=1).initnow scaffoldsCOMPLIANCE.mdfor project-level release review.compliance --jsonemits machine-readable legal/procurement diagnostics.--watermark-layer underlayis accepted as a legacy alias and normalized tobackground.--emit-manifestincludes awatermarkobject withtext|html|image|layer|semantics|opacity|rotation|enabled.--fail-on overflowis enforced from placement data and may auto-enable internal JIT planning.--fail-on font-substis enforced using missing glyph and fallback diagnostics.--allow-fallbacksallows fallback diagnostics to remain informational formissing-glyphs/font-substgates while still reporting them in JSON output.--fail-on budgetrequires at least one budget threshold flag.--repro-checkfails on input/hash drift and lock hash mismatches when lock data is available.--pdf-profile pdfx4enforces embedded-font constraints; CLI errors include an actionable hint to add an embeddable font asset.argparseusage errors exit with code2and emit usage text (not JSON), even when--jsonis present.
Related Docs
- Agent workflow guide:
llm.txt - CLI JSON contract quick reference:
cli_schema.md - CLI epoch/spec:
CLI_EPOCH.md - PDF template/XObject composition guide:
docs/pdf-templates.md - Licensing guide:
LICENSING.md - Third-party notices:
THIRD_PARTY_LICENSES.md - Living docs example project:
examples/living_docs_atlas/README.md - Roofing invoice parity example:
examples/roofing_invoice/README.md - Iconography smoke example:
examples/iconography_test/README.md - Public golden regression suite:
goldens/README.md - Escambia ledger API:
_escambia/sqlite_ledger_api.md
License
Fullbleed is dual-licensed:
- Open-source option:
AGPL-3.0-only(LICENSE) - Commercial option:
LicenseRef-Fullbleed-Commercial(LICENSING.md)
SPDX expression:
-
AGPL-3.0-only OR LicenseRef-Fullbleed-Commercial -
Copyright notice:
COPYRIGHT -
Third-party notices:
THIRD_PARTY_LICENSES.md -
Practical licensing guide:
LICENSING.md
For license information, please visit fullbleed.dev or email info@fullbleed.dev.
License integrity gate (CI-friendly, no build required):
python tools/check_license_integrity.py --json
Commercial compliance attestation examples:
fullbleed compliance --json \
--license-mode commercial \
--commercial-license-id "ACME-2026-001"
# env-based attestation (useful in CI/containers)
set FULLBLEED_LICENSE_MODE=commercial
set FULLBLEED_COMMERCIAL_LICENSED=1
set FULLBLEED_COMMERCIAL_LICENSE_ID=ACME-2026-001
fullbleed compliance --json
import fullbleed
# Process-local helper for library users and agent runtimes.
fullbleed.activate_commercial_license(
"ACME-2026-001",
company="Acme Corp",
tier="$1,000,001-$10,000,000",
)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fullbleed-0.6.5-cp311-cp311-win_amd64.whl.
File metadata
- Download URL: fullbleed-0.6.5-cp311-cp311-win_amd64.whl
- Upload date:
- Size: 8.0 MB
- Tags: CPython 3.11, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3630035dee8cda5a6b16e9ae34b06d1a97710cd54312e634f2bd04b9b9850e73
|
|
| MD5 |
c372a9b79a0fd40156dbd1815e630abe
|
|
| BLAKE2b-256 |
7fb350c4770012577d4e39a17ca61b94b4b2f37ddac54557c6fbb8cf8b2784c7
|
File details
Details for the file fullbleed-0.6.5-cp311-cp311-manylinux_2_35_x86_64.whl.
File metadata
- Download URL: fullbleed-0.6.5-cp311-cp311-manylinux_2_35_x86_64.whl
- Upload date:
- Size: 8.4 MB
- Tags: CPython 3.11, manylinux: glibc 2.35+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
58f10ca13de77d48ad38f3e9320ec166946a7f27fe90d21ec3430c03bbaa6560
|
|
| MD5 |
f12080faafa1f1a8f83809166e268bae
|
|
| BLAKE2b-256 |
d523bce00a62e2e1df82310e2fb6cdb42ba6ef71bcf3d870a6f79158b0550c1e
|
File details
Details for the file fullbleed-0.6.5-cp310-cp310-manylinux_2_35_x86_64.whl.
File metadata
- Download URL: fullbleed-0.6.5-cp310-cp310-manylinux_2_35_x86_64.whl
- Upload date:
- Size: 8.4 MB
- Tags: CPython 3.10, manylinux: glibc 2.35+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
57f9c8d3d946f8a4b2f792998e8061239bd877be9ad3d3b0dfc7c639b869fa6a
|
|
| MD5 |
88c9fe336248a50b66ac891af6806daf
|
|
| BLAKE2b-256 |
7d42fdbfc3bfeedb726ef7aaecea433ea88a673f048997c9dda21f9faef2acaa
|