Project

ironpress

0.0
The project is in a healthy, maintained state
Convert HTML, CSS, and Markdown to PDF with no browser or system dependencies. Native Rust extension for maximum performance.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Runtime

~> 0.9
 Project Readme
4

Ironpress

Pure rust HTML/CSS/Markdown to PDF converter. No browser, no system dependencies.

Crates.io PyPI Gem npm docs.rs CI codecov deps.rs MSRV License: MIT Downloads WASM Playground Parity

Try it in your browser | Parity dashboard | Wiki

Performance

Document Time Pages/sec
Simple HTML (<h1> + <p>) 16 us 62,500
Styled HTML (CSS, lists, links) 71 us 14,000
Markdown (headings, code, lists) 141 us 7,000
Table (5 rows, styled headers) 341 us 2,900
Full report (tables, flex, progress bars) 587 us 1,700

Chrome headless takes ~2,500 ms per page. ironpress is 4,000x faster.

Quick start

use ironpress::html_to_pdf;

let pdf = html_to_pdf("<h1>Hello</h1><p>World</p>").unwrap();
std::fs::write("output.pdf", pdf).unwrap();
let pdf = ironpress::markdown_to_pdf("# Hello\n\nWorld").unwrap();

CLI

cargo install ironpress

ironpress input.html output.pdf
ironpress document.md output.pdf
ironpress --page-size letter --landscape --margin 54 input.html output.pdf
ironpress --header "Report" --footer "Page {page} of {pages}" input.html output.pdf
echo '<h1>Hello</h1>' | ironpress --stdin output.pdf

Builder API

use ironpress::{HtmlConverter, PageSize, Margin};

let pdf = HtmlConverter::new()
    .page_size(PageSize::LETTER)
    .margin(Margin::uniform(54.0))
    .header("My Document")
    .footer("Page {page} of {pages}")
    .convert("<h1>Custom page</h1>")
    .unwrap();

Features at a glance

Area Highlights Details
HTML 50+ elements: headings, tables, lists, forms, media, <img>, inline <svg> Layout Engine
CSS Flexbox, grid, multi-column, calc(), variables, @media, @page, @font-face CSS Support
Fonts Base-14 PDF fonts, custom TTF embedding with subsetting, system font discovery, Unicode/CJK fallback Font System
Math LaTeX via $...$ / $$...$$: fractions, roots, matrices, Greek, operators Math Engine
SVG Vector rendering: path, shapes, gradients, transforms, clip paths, viewBox Layout Engine
Images JPEG + PNG, data URIs, local files, remote URLs (remote feature) Architecture
PDF PDF 1.4, bookmarks, link annotations, headers/footers, gradients, streaming output PDF Rendering
WASM npm install ironpress - runs 100% client-side in the browser WASM & Playground
Testing 2100+ unit tests, property-based tests, 6 fuzz targets, parity dashboard Testing Strategy

Custom fonts

let pdf = HtmlConverter::new()
    .add_font("Inter", std::fs::read("Inter.ttf").unwrap())
    .convert(r#"<p style="font-family: Inter">Shaped with HarfBuzz</p>"#)
    .unwrap();

Fonts are shaped with rustybuzz, subset to used glyphs only, and embedded as CIDFontType2. Characters outside WinAnsi (CJK, Arabic, emoji) are rendered via automatic Unicode font fallback. See Font System.

Math

The equation $E = mc^2$ is famous.

$$\sum_{k=1}^{n} k = \frac{n(n+1)}{2}$$

Full LaTeX support: fractions, roots, matrices, Greek letters, operators, delimiters, accents. See Math Engine.

WASM

npm install ironpress
import init, { htmlToPdf, markdownToPdf } from 'ironpress';
await init();

const pdf = htmlToPdf('<h1>Hello</h1>');
const blob = new Blob([pdf], { type: 'application/pdf' });

See WASM & Playground.

Security

HTML is sanitized by default: <script>, <iframe>, event handlers, and javascript: URLs are stripped. Resources are sandboxed (local-only by default, 10 MB cap). SVG sanitizer strips dangerous elements. PNG decompression capped at 50 MB. Disable with .sanitize(false) if you trust the input.

How it works

HTML/Markdown → Sanitize → Parse (html5ever) → Style cascade → Layout engine → PDF 1.4

See Architecture for the full pipeline.

License

MIT