How-to guides/PDF Generation

Convert HTML to PDF in Rust

PDFluent connects to a headless browser via its browser bridge to render HTML to PDF. This gives you accurate CSS rendering, web fonts, and SVG support.

Not in the current release. This capability is not part of the published PDFluent SDK; the example below does not compile against the current release. See the changelog for what ships today.
rust
use pdfluent::HtmlToPdf;

fn main() -> pdfluent::Result<()> {
    let html = r#"
        <!DOCTYPE html>
        <html>
          <head>
            <style>
              body { font-family: sans-serif; padding: 40px; }
              h1   { color: #1a1a1a; }
              .total { font-weight: bold; color: #2563eb; }
            </style>
          </head>
          <body>
            <h1>Invoice #INV-2024-042</h1>
            <p>Due: 2024-05-01</p>
            <p class="total">Total: EUR 1,200.00</p>
          </body>
        </html>
    "#;

    let pdf_bytes = HtmlToPdf::new()
        .page_size_a4()
        .margin_mm(20.0)
        .render_html(html)?;

    std::fs::write("invoice.pdf", &pdf_bytes)?;
    println!("Saved invoice.pdf ({} bytes)", pdf_bytes.len());
    Ok(())
}

Step by step

1

Add PDFluent with the html feature and install the browser bridge

The html feature requires a Chromium or Chrome installation on the machine. PDFluent calls it via the Chrome DevTools Protocol (CDP). Install the browser bridge with the provided CLI helper.

rust
# Cargo.toml
[dependencies]
pdfluent = { version = "0.9", features = ["html"] }

# Install Chromium for the bridge (Linux)
apt-get install -y chromium-browser

# macOS
brew install --cask chromium

# Or set a custom Chrome path via environment variable
# PDFLUENT_CHROME_PATH=/usr/bin/google-chrome
2

Render an HTML string to PDF bytes

HtmlToPdf::new() launches a headless browser, loads the HTML, and triggers the browser print-to-PDF function. The bytes are returned in memory.

rust
use pdfluent::HtmlToPdf;

let html = "<h1>Hello, PDF</h1><p>This is a test.</p>";

let pdf_bytes = HtmlToPdf::new()
    .page_size_a4()
    .margin_mm(15.0)
    .render_html(html)?;

std::fs::write("output.pdf", &pdf_bytes)?;
3

Render a URL to PDF

render_url() navigates to a URL and waits for the page to fully load before printing. Useful for reports served from a local web server.

rust
let pdf_bytes = HtmlToPdf::new()
    .page_size_a4()
    .wait_for_idle_ms(1000)   // wait 1 s for JS to finish
    .render_url("http://localhost:3000/invoice/42")?;

std::fs::write("invoice-42.pdf", &pdf_bytes)?;
4

Render an HTML file from disk

Pass a file:// URL or use render_file(). All relative paths (images, CSS) must be resolvable from the file location.

rust
let pdf_bytes = HtmlToPdf::new()
    .page_size_a4()
    .render_file("/tmp/invoice.html")?;

std::fs::write("invoice.pdf", &pdf_bytes)?;
5

Set custom print options

Control page size, margins, header/footer, and background printing.

rust
use pdfluent::{HtmlToPdf, PageSize};

let pdf_bytes = HtmlToPdf::new()
    .page_size(PageSize::Letter)
    .margin_top_mm(15.0)
    .margin_bottom_mm(15.0)
    .margin_left_mm(20.0)
    .margin_right_mm(20.0)
    .print_background(true)
    .header_template("<div style='font-size:10px'>Report</div>")
    .footer_template("<div style='font-size:10px'>Page <span class='pageNumber'></span></div>")
    .render_html(&html)?;

Notes and tips

  • PDFluent uses the Chrome DevTools Protocol (CDP) to control the browser. Chromium or Chrome must be installed. There is no bundled browser.
  • The browser bridge is a separate process. First render takes 300-800 ms for browser startup. Subsequent renders on the same HtmlToPdf instance reuse the browser process and take 50-200 ms.
  • For server deployments without a display, run Chrome with --no-sandbox --disable-gpu flags. These are set automatically by PDFluent on Linux.
  • CSS page breaks (@page, break-before, break-after) are respected by Chromium and appear correctly in the output PDF.
  • For pure programmatic PDF generation without a browser dependency, use PdfDocument::new() and add content directly. See the Create a PDF from Scratch guide.

Why PDFluent for this

Pure Rust

No JVM, no runtime, no DLL dependencies. Ships as a single native binary or WASM module.

Memory safe

Rust's ownership model prevents buffer overflows and use-after-free. No segfaults in PDF parsing.

Runs anywhere

Same code runs server-side, in Docker, on AWS Lambda, on Cloudflare Workers, or in the browser via WASM.

Frequently asked questions