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.7.tar.gz (94.6 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.7-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.7-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.7-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.7-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.7-cp311-cp311-win_amd64.whl (2.3 MB view details)

Uploaded CPython 3.11Windows x86-64

ferropdf-0.2.7-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.7-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.7-cp311-cp311-macosx_11_0_arm64.whl (2.2 MB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

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

Uploaded CPython 3.11macOS 10.12+ x86-64

ferropdf-0.2.7-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.7-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.7-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.7-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.7-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.7-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.7.tar.gz.

File metadata

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

File hashes

Hashes for ferropdf-0.2.7.tar.gz
Algorithm Hash digest
SHA256 03811c39afbf9ef7981c80a6706f3403b7d02e310aa3dbb3c5512d99bab14c1a
MD5 eabd0456a7e2eb09ad569f9a3df211fe
BLAKE2b-256 3f103a7b4f4a818540a5cbee1ad2b3adff8fd4c2fffb643ed31aa58028421bab

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 9f69073c32adc2a686645008a3b28ed0fdef4399a52180399d2e11e47fc2b41b
MD5 3ca2220c8c36217864233bc7a851dc79
BLAKE2b-256 b4e918668d186a03ca315ea792e23f5a00c01bc449f420b9a6b5669aeca39653

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 3e836b9c183475482ca343bce990204aa90dd6c832ca9c879472af89d90af525
MD5 9f66e7bdbbbf6c6260c62950c2d55a34
BLAKE2b-256 06b3cea17e4e281d2cfd001d932b15fbfbd45350996846e70c0742aa9a836b1e

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 7036b0889f59fe696d293769f92fb8cc5ecd7b4a64c821cdda8656bbe449f7e0
MD5 b9d03cb9e00d560c49401cf2e88ec41b
BLAKE2b-256 28f136131d272461084f82ad037e17b41cd04b934e319f1d1f98e16711d73e05

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 c1243fc6bc3ed20741ae98a9d04a3c1d6b9e16ebfa746e15a81de2fe550ca0cf
MD5 f0d776c12fec0f137d34569a8a002f3a
BLAKE2b-256 cc9f88c2d6d8fadbfa1c8a5ed4a9ccc7ea43be021e9d0d10db570c11dfe6585e

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.7-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 7ac64bf527c88b1262a9cfef5e4e19c926e3a38a4c132c18ca1d40fe02dde75d
MD5 c78373c4cc251754df071b8c77bd58a2
BLAKE2b-256 6dc19d29c67b48075e445bf6d8d21a62653cf4d894dc2643edd703dbb579d61c

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 a5c127aa674bfb7504b32431c8368269a1cfde633754ba6f603db8d135732381
MD5 7b6dba524291163ab225aec76a4559d7
BLAKE2b-256 276ff83e14a2f104f3ddadd681e5c44e2ef3f99b5ff48f008f76335acadfe3e0

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 ac42f5871a161d4a38d97af83d52523ca934ed454195de58c5b0805db7748383
MD5 eb56da7abc9aef0f675071dbb0a3866a
BLAKE2b-256 56e521b47eb881b0f89359e3c121c09cdc91af6d907b7a1336159ce26906447b

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.7-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 a6ad9efcb3868a68b5e4f4569c485d687fc97d01b77f26984585727630476769
MD5 83c4ebd3bd85453c6665cadae62971b1
BLAKE2b-256 9aa816512b13867b2bf8f4c4826c706d516df67d9ed5d4a4a1c38f77075a660d

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.7-cp311-cp311-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 75caf56e26e73dc7b162ea90fef73bee7b27cdd224a3f7e2c0c5213aa3e81f10
MD5 606b3023ffab24bc92001f3ac75e249c
BLAKE2b-256 7aa6e1fa0ed8803331e9a003add909c49886a0738b7b8679b00e0d291bc898fb

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 46d64bbc64dae6d5d2cc13c0f06abbe32db14e1c017e7cc73287817a6e310f3e
MD5 291ece481669b05d6f61faa8771491c2
BLAKE2b-256 3c18306fc779a7e66cec1fc2f80a99defc6c8b03b9d5074f39407c4622a79c67

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 79321fb48b8da43cdff370a5e057d5faf17ad5d940b6bb7fcb2926e943bb7362
MD5 c99071d43dc5d0d57af5a04623e6e60d
BLAKE2b-256 4bb7f0d763fba29e098ee1cf3a4bac9539a914a0c62648411a6b2c3967c1d88e

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 2ad1700cf8153f671cdd447ffa26c6417d73d5e950e842e648f286489b2df1ff
MD5 e8d03ed3308c327944d10fbf36c95781
BLAKE2b-256 57b6b6cf5aa9541a1091d16c02cdf35ac97b13a8d8acaa72843bbbf06a28c9b5

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 cf5247de597500d3c164f273b8896f5314c2b8953dadbfd388f736f46d6844a6
MD5 50aa281d66553cdb9b386fcf93c73773
BLAKE2b-256 7d3ef851b4d3ca88529ee6a4c41994bd826811193bb8bf19d6f5920c0359bd7f

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 8ab66ad288c4b7d6301176419b7101b65ada2d96eb6bfc41ecac38bcc874337c
MD5 5304b173d988f84f4c47571450e8bf5d
BLAKE2b-256 b2c1fcb5f56d59612c0571e4046db5ac76f262fdec36f7396696b516062a180e

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 c1221d2459909829a1d70d09636b39c09a4cf9aab35bdac2a6eca6faa5f02e60
MD5 f0e8d228aa297cbe6c400026b5aa34d9
BLAKE2b-256 db9d3d935da8b33b53934ee495342759dba5a9854d58847e61f4eb715df698d7

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