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.4.tar.gz (91.0 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.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.4 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64

ferropdf-0.2.4-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.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.4 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

ferropdf-0.2.4-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.4-cp311-cp311-win_amd64.whl (2.3 MB view details)

Uploaded CPython 3.11Windows x86-64

ferropdf-0.2.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.4 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

ferropdf-0.2.4-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.4-cp311-cp311-macosx_11_0_arm64.whl (2.1 MB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

ferropdf-0.2.4-cp311-cp311-macosx_10_12_x86_64.whl (2.2 MB view details)

Uploaded CPython 3.11macOS 10.12+ x86-64

ferropdf-0.2.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.4 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ x86-64

ferropdf-0.2.4-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.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.4 MB view details)

Uploaded CPython 3.9manylinux: glibc 2.17+ x86-64

ferropdf-0.2.4-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.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.4 MB view details)

Uploaded CPython 3.8manylinux: glibc 2.17+ x86-64

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

File metadata

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

File hashes

Hashes for ferropdf-0.2.4.tar.gz
Algorithm Hash digest
SHA256 0f3b78692cfd30897522ba331b274d7f7faf20ec6571d6551c6d577d6c828c10
MD5 4e464dae8b8ee2a994ce0d9f9f4187d6
BLAKE2b-256 676aa1e4b55af68ec5a0b68f2e35b268e8e784578c3011dd13f2319aba951429

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 390e57a071254576736b911de671d5e12b400b99493d367ba77e0e926311ba6c
MD5 beb77a098007c54cab9698d1e896d5ce
BLAKE2b-256 3957795039ff4aca309dbd7afafe0a88142bc778a6803b3d0de1d655cac0447f

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 07345ac5665a6eb7599a1f57db6f5ae0f7b5fba4ed3e74ad3bd2f0531f723085
MD5 f7a1a024f20cbb2d0af08c93fdfd3270
BLAKE2b-256 1bffd0548761bc8bd7d0b83c2870e4966cd6d5c82e0f00ed045ecd1a028c8c98

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 9a2dee116ea5dadae9923afcfec904607edabed587df903033cab3d55b0fd5ce
MD5 62ae992d63ac2e1633014f144b86ec40
BLAKE2b-256 aa35a47e4c530da33738bf647117bf1eaea2e4998ca3e9ad6cd7ef53835bae93

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 a42c9809f35016334ed407b76e4308c8a1604edc060996100572ec4cf5d1d9bf
MD5 937c416a3d44f5f234870a05207396df
BLAKE2b-256 ef7c897edd82518d0cb4a6a5ca111663073f932904fc3a4010163bbf0b2601fc

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.4-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 a72bf91657ad1424279ec4f86355af210dc024d904867734b8d505067af8770a
MD5 8228c4c87d0b0240570cbc5fdb5866a2
BLAKE2b-256 42dd689d094c34198535052643a7b6d842fa5b8524645974405f5b08b77c2069

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 b2b06219037ffae4a9ee4d9ae48981487adf003f12b9209dbbe958e8676da98b
MD5 093aaa0b285b61e72fa7f353df37fb4e
BLAKE2b-256 cf9d57216bb5f896c21a1c2ac6bc59f673a61deb3e07c2dbbe84b8ad1cbf1630

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 dadfbb68957f5b9faf1dc53619c699aed877139666939a226b1ea34f9191e917
MD5 c8f93f753a46d0bbc37e4e11e15f20dc
BLAKE2b-256 233ff9d0b79b5291976bbd3401a1bc1e459db6fea34c55b5dc5dcdfda9bd8fa6

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.4-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 c8916f27b2af56d1240e317a5b49b6d44642fe655683ec375dfdf53037bcf56f
MD5 1b733d5941def1ca50a6707eeaaeec29
BLAKE2b-256 51591fc3d6b124a01a95a03bfdcb217a1ce17f2a0a6ff1c8adfa51f7620f0a13

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.4-cp311-cp311-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 2441678de50c3113636dc515ebd5a34559ac8ad6bbeea40b2fb7213dbc82d474
MD5 746ee32170d4b752c91a9f9074645adb
BLAKE2b-256 bff188de116cf7f2d65ddf4c045c22227f26c96a791afe4c358116d9d38867a3

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 dbbda503403816ce6ea7ca84b4cca78ab23a06c8a06a44431eaec1d5124d84bb
MD5 743c01cc2d21c782bba1b5a2fe217322
BLAKE2b-256 d99909406767273850671a7c4a7c1a8d19c15bc400dd18f67645f656d58562d1

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 f795cb90d0b7188c5a6786c14d4d9022ecadd13a5265c339d3e04ae63aa8d378
MD5 c20f39ff4986dff5ea1f94d28ea4373a
BLAKE2b-256 b33de9f06d16e462b4907b9d95665bd0ddd0bd605c7a4831d4b0a59f6a8ca447

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 6e17ae1b6558b5b10d2de6624e3158a8ccb2b7487e65f97aa941839fbfbee90f
MD5 a3d29657af2872e2e98a473d21da2766
BLAKE2b-256 310a0c1b9357b5a61c921b8dcb6ea90a133859dd104d130642cd8f03bcdb5958

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 ecbabdb74aae3b1365ef2deaa7c0702ac3b32fc027f523d7cb3cab8815147beb
MD5 055f50f8069a61e97f06ad805cbbb258
BLAKE2b-256 3e08ac88c310b84c38d657003c5a4e18cc17da7a6a07cdcf1041fbff18cf34c3

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 ec94b8a5a8a9b059786b553242afe8d7e7d384c12ab7114547847f52a45cd89f
MD5 d185174e6afb2ad6971512c3716a637e
BLAKE2b-256 3feed4fa18664ceffdca9b126a19a04c3f0f3c5403e7e61530b9d3f22f793ae7

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 47ce40b257b742b568462e663bd5f9ec42c332ffbea4b57e67a741e0d05298b9
MD5 82864292042711646218bd5f07964022
BLAKE2b-256 1b34b2c31f61364db50371cc48f5b6cf95fac2b2dfc623eb819cc8c4acf4df87

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