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

Uploaded CPython 3.11Windows x86-64

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

Uploaded CPython 3.11macOS 11.0+ ARM64

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

Uploaded CPython 3.11macOS 10.12+ x86-64

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

File metadata

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

File hashes

Hashes for ferropdf-0.2.5.tar.gz
Algorithm Hash digest
SHA256 b8b4dbfba96fd77bf5480c77b8ba5ad38b7b800aedd2c2cac3090d37fabcac72
MD5 964ca86234e17a798c738c7f4d3ca2c9
BLAKE2b-256 daf9d9182c50ec5a141332ea8017604119a6ca50b16a5730586275eb7eb3a36d

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 a3fa9406f2e7b2a317fcee0330dd4bbd27fd91b153e895633f38d0329b414458
MD5 e47c7e64f3e56d39d7dfffd6a444a5a5
BLAKE2b-256 75ddce548628ffb4a08ae28720070bcb706b94f8132fc6f4a5b28c04f7b4b2de

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 0533676b50d177383d3b798afb1587354d2e07b58c0c36045cf1d4bc00b9e749
MD5 7dc3d90c83746eb89d86918848280a6d
BLAKE2b-256 1bab8eba946320fa5d8621fb03d66899d6fcbf7108b7bc5ef9ab291238a936b0

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 ca595c78ac021907ac3dfbcf154736cc016891dd67d6c288942c64d890b1b06c
MD5 c5291f81c7d31202fc9b135769b4cdd7
BLAKE2b-256 26655928973048b5530172bce4ef74aed87e41a1cd8ceead9a8c718e56ea45e3

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 e8830f8649dfc22bca2ccef239c3fba034c3f65b9b1eaf54206d36311dcda0d6
MD5 36af9e2e5ecda9563f497ee22bc12fb9
BLAKE2b-256 81a079911dbb6da3de2d94916e612a4f66af03c2bbda5d140213949cf52d94d1

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.5-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 1437baa8f806eee75dcc4b73a68a3a7fdac8cb9b644e1c2a112218f7de293233
MD5 b3f16117c84ad96e59050a62c7094f05
BLAKE2b-256 cc7b36766d3b52e56140f1bdcc62935bfd5bff9d0b680e51e37ba58308882ece

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 7276eeb09b82fc945d8ca576384bb209672d7254c4d12cd04ceeadf2811befd5
MD5 d340071d1983a890e79d6a57b59efcc5
BLAKE2b-256 3a661bd7c5490b3b326db02ca09eaebbe84140e67ebb176f8271413eab06c278

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 5bc0f9095a2859cc03d58b3806c101cd4fc4df3c19c77a754d6b22f7b52aad6e
MD5 ea45c79d926b128b0ca0d008a59c9494
BLAKE2b-256 43f6b94759d361f77e4c9012357b1b6eb7623251081a6e4a9a782b20b0d95fbb

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.5-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 ee317942f59430dc3128ae2f4101d3f15074d8d072ff25e741ac9bba6813a9b5
MD5 85d45eb7f4f36bfc3437b668d6f0e8ec
BLAKE2b-256 6168460bb92d1e674f0cfbe80e939b6dd51b7d52a01280915432314819d1b561

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.5-cp311-cp311-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 68d97b72daf42fac45250f3d4523fdbd2980c1bf678fbc35778a4746da021380
MD5 526de04419a8c557a9bc80c7b51e37f0
BLAKE2b-256 bec2495a845dd6498d1fb7595d8277c814f31df5b2fd699ecb54847b61c19867

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 11a5d697ff0384ba226ea54802b2a96921abc5e8eea252f7e516f8ccf32fe552
MD5 7fb53c18f8b68ecfde33546893710ba8
BLAKE2b-256 fbeb1a16485b20a77853d7916f474b0aba6050121660ff0b9bcd22b3c3c533f6

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 b7501fc3070416fe24da632b4fc2b1f4ffea4c2c9a892c789f7db12dd521e9c9
MD5 f493922a6f861623c3c02fd96a87a811
BLAKE2b-256 5c2c99422626d5841fcb4281259241ca4accfd26e7e2fcd170b837fbedf4ab0b

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 97b2e70aebe93d81e82ff31a147ef0749f2b0836589e2fa802dfd8150a337bcb
MD5 b48436129a0b795a5f96e1e3d0d0b93b
BLAKE2b-256 23140c9a2a328a1625c1cabb5089a68a5bb9a0bfd8a839d6aa7c9158c0512612

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 b22cd1ed0cc33d57d55a15c22660e56eda29aaa0f79a5e2d247c30b35503b330
MD5 f014f48a30d23eb4986662427a037d30
BLAKE2b-256 efd34671a8159964a4c8fe8f5b18ae01584f3397ef5f22ea6410e21363dba435

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 79e97b0799a659331defca810f1aed34b92c4d1b457125595ed99c8da3223440
MD5 fcffc3b0dd660894ddaec006c0bc0f81
BLAKE2b-256 6fcde6984167da0ed21d314999c579b48a8f2963cde124086ecbdb10e56d78b2

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for ferropdf-0.2.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 07b2868081c7f30d14a3fe248b4eecc79aa490c6ab3ba4164d550e2dc325c16a
MD5 5647ea444f100a778bee67f40274a729
BLAKE2b-256 09aafdd033360db776ad84dd6e75eb797c274a0bfcb67d2702cee2be33e0b144

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