Skip to main content

Fast HTML to PDF — Rust-powered, 10x faster than WeasyPrint

Project description

ferropdf

Fast HTML-to-PDF for Python — Rust-powered, up to 13x faster than WeasyPrint.

CI PyPI Python License: MIT


Why ferropdf?

Most Python HTML-to-PDF libraries are slow. ferropdf is a native Rust engine exposed as a Python package via PyO3 — it renders complex invoices, reports, and dashboards in milliseconds, not seconds.

Feature ferropdf WeasyPrint
Speed (invoice) ~25ms ~330ms
GIL Released during render Held
Async-safe Yes (FastAPI, Django) No
Font subsetting Automatic Manual
Install pip install ferropdf System deps required

Benchmarks on Linux x86_64, median of 20 runs, reusable engine with font cache.


Install

pip install ferropdf

Pre-built wheels for Linux (x86_64, aarch64), macOS (x86_64, ARM), and Windows (x86_64).
Python 3.8 – 3.13 supported.


Quick start

One-shot rendering

import ferropdf

# HTML string → PDF bytes
pdf = ferropdf.from_html("<h1>Hello, World!</h1>")

# With options
pdf = ferropdf.from_html(
    "<h1>Invoice</h1><p>Total: $1,234</p>",
    options=ferropdf.Options(page_size="Letter", margin="25mm"),
)

# Write directly to disk
ferropdf.write_pdf("<h1>Report</h1>", "report.pdf")

# From an HTML file
pdf = ferropdf.from_file("templates/invoice.html")

Reusable engine (recommended for servers)

from ferropdf import Engine, Options

engine = Engine(Options(page_size="A4", margin="20mm"))

# Font database is cached — subsequent renders are faster
pdf1 = engine.render("<h1>Invoice #1</h1>")
pdf2 = engine.render("<h1>Invoice #2</h1>")

API reference

Options

ferropdf.Options(
    page_size="A4",         # A4, Letter, Legal, A3, Tabloid, ...
    margin="20mm",          # CSS margin (mm, pt, px)
    base_url=None,          # Resolve relative paths in CSS
    title=None,             # PDF metadata
    author=None,            # PDF metadata
)

Engine

engine = ferropdf.Engine(options=None)
engine.render(html: str) -> bytes         # Render HTML to PDF bytes
engine.render_file(path: str) -> bytes    # Render from file

The engine caches fonts internally — create once, render many times.

Functions

Function Description
from_html(html, base_url=None, options=None) -> bytes Render HTML string to PDF
from_file(path, options=None) -> bytes Render HTML file to PDF
write_pdf(html, output_path, base_url=None, options=None) Render and write to disk

Exceptions

All exceptions inherit from ferropdf.FerroError (itself a RuntimeError):

  • ParseError — HTML/CSS parsing failure
  • LayoutError — Layout computation failure
  • FontError — Font loading/resolution failure
  • RenderError — PDF generation failure

Framework integration

Django

# views.py
from ferropdf.contrib.django import PdfResponse

def invoice(request, pk):
    context = {"invoice_id": pk, "items": get_items(pk)}
    return PdfResponse("invoice.html", context, request=request)

PdfResponse renders a Django template to PDF. Pass inline=False to force download instead of browser preview.

FastAPI

# main.py
from ferropdf.contrib.fastapi import pdf_response

@app.get("/invoice/{id}/pdf")
async def invoice_pdf(id: int):
    html = templates.get_template("invoice.html").render(invoice_id=id)
    return await pdf_response(html, filename=f"invoice-{id}.pdf")

pdf_response is async — rendering runs in a thread executor with the GIL released, so it won't block your event loop.


CSS support

ferropdf uses industry-standard libraries for parsing and layout — not a hand-rolled engine.

Layout

Feature Status
Block layout Supported
Flexbox (flex-direction, flex-wrap, gap, justify-content, align-items) Supported
Tables (<table>, <thead>, <tbody>, <tr>, <td>) Supported
width, height (px, %, em) Supported
margin, padding (px, mm, em, auto) Supported
box-sizing: border-box Supported
CSS Grid Not yet
float Not yet

Typography

Feature Status
font-family (system fonts, fallbacks) Supported
font-size (px, pt, mm, em, rem) Supported
font-weight (normal, bold, 100–900) Supported
font-style (normal, italic) Supported
line-height Supported
text-align (left, center, right) Supported
@font-face Not yet

Visual

Feature Status
color, background-color (hex, rgb, rgba) Supported
border (width, style, color) Supported
border-radius Supported
opacity Not yet
box-shadow Not yet

Page

Feature Status
Multi-page documents Supported
Page sizes (A0–A10, Letter, Legal, Tabloid, B-series) Supported
Configurable margins Supported
PDF metadata (title, author) Supported
@page rules Planned

Architecture

ferropdf is built as a modular Rust workspace with 6 crates:

HTML string
  ↓  ferropdf-parse      (html5ever + cssparser)
DOM tree + Stylesheets
  ↓  ferropdf-style       (Mozilla's selectors crate — cascade, specificity, inheritance)
Style tree
  ↓  ferropdf-layout      (Taffy flexbox engine + cosmic-text shaping)
Layout tree
  ↓  ferropdf-page        (pagination into discrete pages)
Pages
  ↓  ferropdf-render      (pdf-writer — font subsetting, compression, embedding)
PDF bytes
Crate Role Key dependency
ferropdf-core Shared types: DOM, styles, geometry, errors
ferropdf-parse HTML & CSS parsing html5ever, cssparser
ferropdf-style CSS cascade, specificity, inheritance selectors (Mozilla)
ferropdf-layout Box layout + text shaping taffy, cosmic-text
ferropdf-page Pagination across pages
ferropdf-render PDF generation, font embedding pdf-writer, subsetter

Python bindings are via PyO3 + maturin.


Performance

Font subsetting + caching means:

  • First render: loads system fonts + builds cache (~100ms)
  • Subsequent renders: 15–30ms for typical documents
  • PDF sizes: small, because only used glyphs are embedded

The Engine class keeps the font cache alive — ideal for web servers handling many requests.


Examples

The examples/ directory includes:

  • basic.py — Hello world, styled report card, invoice
  • FastAPI app — Invoice, report, receipt, dashboard, letter endpoints
  • Django app — Same templates with Django views

Run the FastAPI example:

cd examples/fastapi_app
pip install fastapi uvicorn jinja2
uvicorn main:app --reload
# Visit http://localhost:8000/invoice/42/pdf

Development

# Clone and setup
git clone https://github.com/MoncefMak/ferropdf.git
cd ferropdf
python -m venv .venv && source .venv/bin/activate
pip install maturin pytest

# Build and install locally
maturin develop --release

# Run tests
cargo test --no-default-features   # Rust tests
pytest tests/ -v                   # Python tests

# Lint
cargo fmt --all --check
cargo clippy --workspace -- -D warnings
cargo audit

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ferropdf-0.2.9.tar.gz (94.9 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

ferropdf-0.2.9-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.5 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64

ferropdf-0.2.9-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (2.3 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ ARM64

ferropdf-0.2.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.5 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

ferropdf-0.2.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (2.3 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ ARM64

ferropdf-0.2.9-cp311-cp311-win_amd64.whl (2.3 MB view details)

Uploaded CPython 3.11Windows x86-64

ferropdf-0.2.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.5 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

ferropdf-0.2.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (2.3 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ ARM64

ferropdf-0.2.9-cp311-cp311-macosx_11_0_arm64.whl (2.2 MB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

ferropdf-0.2.9-cp311-cp311-macosx_10_12_x86_64.whl (2.3 MB view details)

Uploaded CPython 3.11macOS 10.12+ x86-64

ferropdf-0.2.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.5 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ x86-64

ferropdf-0.2.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (2.3 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ ARM64

ferropdf-0.2.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.5 MB view details)

Uploaded CPython 3.9manylinux: glibc 2.17+ x86-64

ferropdf-0.2.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (2.3 MB view details)

Uploaded CPython 3.9manylinux: glibc 2.17+ ARM64

ferropdf-0.2.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.5 MB view details)

Uploaded CPython 3.8manylinux: glibc 2.17+ x86-64

ferropdf-0.2.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (2.3 MB view details)

Uploaded CPython 3.8manylinux: glibc 2.17+ ARM64

File details

Details for the file ferropdf-0.2.9.tar.gz.

File metadata

  • Download URL: ferropdf-0.2.9.tar.gz
  • Upload date:
  • Size: 94.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: maturin/1.12.6

File hashes

Hashes for ferropdf-0.2.9.tar.gz
Algorithm Hash digest
SHA256 720b0350dda304a5a5a2659804046c9eef22c37304f568bd853fdd9e59cf0e52
MD5 a109addaaa51155a04bacf6c275cf411
BLAKE2b-256 630c481346f794bef6bb9df72b48e930340922b68302e61821c6e4de2bdf400d

See more details on using hashes here.

File details

Details for the file ferropdf-0.2.9-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for ferropdf-0.2.9-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 11e1541913491b3621a270d92b464a581eb7c9970eb1b3ac63d37518395eb7b9
MD5 eff5f453b817e1423de6872ca9b0e695
BLAKE2b-256 82c221aa5dfc707168f5cff95907c36b06e158d0ae070b63866bd4f5ecdeedfb

See more details on using hashes here.

File details

Details for the file ferropdf-0.2.9-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for ferropdf-0.2.9-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 4afbf5fb2bc260a43a4a487a4e2f908748150ec6c688423f16f0147d26eb590d
MD5 bb44bfa76019c3c9fa445d808de3fb54
BLAKE2b-256 db4fd1abe51046bf583bb91fad8d7b2d16ec49c9c7b644ce0af39190cd077ad8

See more details on using hashes here.

File details

Details for the file ferropdf-0.2.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for ferropdf-0.2.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 f3812fc9cf55ec071fbe464b79772c204fcea2db3d1c84d9deecf744768e2be9
MD5 e8b6748fb86324e9b17ff9e134704332
BLAKE2b-256 6b906565272a754b0030b109ecee118c15a2702c7615d479f0b6d5308423fdf3

See more details on using hashes here.

File details

Details for the file ferropdf-0.2.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for ferropdf-0.2.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 60ae2303ab65be1bb2e53631f7afc47994bc1ac0544d7e07581e1718ec9a382e
MD5 5a418756c855d5796d183c29da50015c
BLAKE2b-256 513ef0a0d220eb9646c82b2eebde073b92182937d0aa6f3a25c3285e1aeaa098

See more details on using hashes here.

File details

Details for the file ferropdf-0.2.9-cp311-cp311-win_amd64.whl.

File metadata

File hashes

Hashes for ferropdf-0.2.9-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 a4468e6ea2b1c4e351b95dcc26cdb137f48f0b7f161d5b36e39c09f343423298
MD5 203178929ba6660341c1e34cb7df7ee9
BLAKE2b-256 8f87181a34410be069c47df84c8c7550e2fdd78fa7e5a8b52f912fb9e2f47967

See more details on using hashes here.

File details

Details for the file ferropdf-0.2.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for ferropdf-0.2.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 1311f8cca0a028152f6f9eae9a638cd6674c97cf2f99e08985f4d078d3c41982
MD5 9a5483f5a376cc0bcd9252b931ae48ce
BLAKE2b-256 9fdc9a747942efa7de35f2e3b75bbabdb320caf1182f09a8a53fce5efe0c34fe

See more details on using hashes here.

File details

Details for the file ferropdf-0.2.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for ferropdf-0.2.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 ad8a1d7f0bad7ca4d7b8d68eb370d4a03ef24ea1542e407488bbd34c8c83378c
MD5 7f4916d4855dee6783b91557664650f6
BLAKE2b-256 2d246691639e92238e3e47a2fbf6c886f5d4aadf1552e66677c28e69b18c3ab3

See more details on using hashes here.

File details

Details for the file ferropdf-0.2.9-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for ferropdf-0.2.9-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 cb7bfe5c88017d9dba6310cd35e96ea7c12115f6452c5237260c1e4f47aca092
MD5 61345d0ba86a4eb5839d36c08b9f7715
BLAKE2b-256 ad70c0127bc50997398552572caca14e0ad272949c6b4d0b3b883c17b43bfe5d

See more details on using hashes here.

File details

Details for the file ferropdf-0.2.9-cp311-cp311-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for ferropdf-0.2.9-cp311-cp311-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 4d1139a038c8723e9486a32b62dc6b723fb841bbcefe22e81514f4a8216c22b9
MD5 71a185f305d1d8f22d3bb0e476c18c5e
BLAKE2b-256 801ec71c42c7df773a33286a7aa046d52fdd854cf0c4ad12145c757bb3199b23

See more details on using hashes here.

File details

Details for the file ferropdf-0.2.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for ferropdf-0.2.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 023ee922e8ecbe87921fc503f4862911b647f7e9005ff6fd5f805d1248a0f460
MD5 8b7c1a50a0baad3980693cacc3abb7d3
BLAKE2b-256 ebacf1b4d124887ae15405dddb960d85342afa624bf89d29adfaede4c4716dc6

See more details on using hashes here.

File details

Details for the file ferropdf-0.2.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for ferropdf-0.2.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 8712c110ae8ae4e8ba7500f50e76227faecc5e40b27fc2a361e6874752668cf0
MD5 ec4e5e1a25b1c63814d872ea13676acf
BLAKE2b-256 00850882d7942dc0df40bd7cb2b82744aea9050952fc00e09322c5f90e99c145

See more details on using hashes here.

File details

Details for the file ferropdf-0.2.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for ferropdf-0.2.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 ef0e4275577921ad46d903303c11574e8c09d7097d6ccc558cff244885c68e0c
MD5 99e1214791839d9fb9e32c6694f480c5
BLAKE2b-256 428bc30e1d0ba255fcdcf78a1ec685308dcb1e5ba5647e7988dba54b054761f1

See more details on using hashes here.

File details

Details for the file ferropdf-0.2.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for ferropdf-0.2.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 036903330f99e5629a72a3b40cf014b42cfec831afcd836f925c880543eff48e
MD5 d59719c7823cebb5d44d609d8609c95a
BLAKE2b-256 16ac33c2467815a0a01809118e152b3e3361b69a67ba70ac663092cf1a2de732

See more details on using hashes here.

File details

Details for the file ferropdf-0.2.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for ferropdf-0.2.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 c8efc0a2f4f806f31f201eb35c00e11bff4730b268d02f16b58553e638288f18
MD5 a8ba526f7c9fad0981e3e3b764bf2bd0
BLAKE2b-256 33b6e14c284899fb0d996f06ff5d786eb75fd59d087aac37f32c279515fbaafc

See more details on using hashes here.

File details

Details for the file ferropdf-0.2.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for ferropdf-0.2.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 3de8a80f76ad8464809eff2cffc912af797e083476029836caeae20d8b210e1c
MD5 2b54d2d9df9029367d8b63267554b6af
BLAKE2b-256 ce929d07720fe4c12b0bdb95fb276927ae69bcee431a36adfe2ebadecbda9e97

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page