zenpdf 0.2.0

PDF page renderer via hayro with page selection and render bounds
Documentation

zenpdf CI crates.io lib.rs docs.rs license

Pure Rust PDF page renderer built on hayro. Renders PDF pages to PixelBuffer<Rgba<u8>> (straight-alpha sRGB RGBA8).

#![forbid(unsafe_code)]

Quick start

use zenpdf::{render_page, RenderBounds};

let pdf_data = std::fs::read("document.pdf").unwrap();

// Render page 0 at 150 DPI
let page = render_page(&pdf_data, 0, &RenderBounds::Dpi(150.0)).unwrap();
println!("{}x{}", page.buffer.width(), page.buffer.height());

// Fit within 1920px wide
let page = render_page(&pdf_data, 0, &RenderBounds::FitWidth(1920)).unwrap();

Render bounds

Control output pixel dimensions with RenderBounds:

Variant Description
Scale(f32) Multiplier on native 72 DPI dimensions. 2.0 = 144 DPI.
Dpi(f32) Render at a specific DPI. 72.0 is native, 300.0 for print.
FitWidth(u32) Scale to fit the given width, preserving aspect ratio.
FitHeight(u32) Scale to fit the given height, preserving aspect ratio.
FitBox { width, height } Scale to fit within a bounding box, preserving aspect ratio.
Exact { width, height } Force exact pixel dimensions (may distort).

Multi-page rendering

use zenpdf::{render_pages, PdfConfig, PageSelection, RenderBounds};

# let pdf_data = vec![];

let config = PdfConfig {
    pages: PageSelection::Range { start: 0, end: 4 },
    bounds: RenderBounds::Dpi(300.0),
    background: [255, 255, 255, 255], // opaque white
    render_annotations: true,
    ..PdfConfig::default()
};

let pages = render_pages(&pdf_data, &config).unwrap();
for page in &pages {
    println!("page {}: {}x{}", page.index, page.buffer.width(), page.buffer.height());
}

zencodec integration

With the zencodec feature (enabled by default), zenpdf implements zencodec::decode::DecoderConfig for use in codec-agnostic image pipelines.

Default decode renders page 0. Use with_start_frame_index() on the job to select a different page.

use std::borrow::Cow;
use zencodec::decode::{Decode, DecodeJob, DecoderConfig};
use zenpdf::{PdfDecoderConfig, RenderBounds};

let config = PdfDecoderConfig::new()
    .with_bounds(RenderBounds::Dpi(150.0));

let pdf_data = std::fs::read("document.pdf").unwrap();
let output = config.job()
    .decoder(Cow::Borrowed(&pdf_data), &[])
    .unwrap()
    .decode()
    .unwrap();

println!("{}x{}", output.width(), output.height());

Resource limits are enforced when set via with_limits() on the job — input size, output dimensions, and pixel count are all checked before rendering begins.

Features

Feature Default Description
zencodec Yes Implements zencodec::decode::DecoderConfig for codec-agnostic pipelines

Dependencies

All dependencies are permissive (MIT, Apache-2.0, Zlib, BSD-3-Clause, Unicode-3.0). No copyleft in the dependency tree.

Image tech I maintain

State of the art codecs* zenjpeg · zenpng · zenwebp · zengif · zenavif (rav1d-safe · zenrav1e · zenavif-parse · zenavif-serialize) · zenjxl (jxl-encoder · zenjxl-decoder) · zentiff · zenbitmaps · heic · zenraw · zenpdf · ultrahdr · mozjpeg-rs · webpx
Compression zenflate · zenzop
Processing zenresize · zenfilters · zenquant · zenblend
Metrics zensim · fast-ssim2 · butteraugli · resamplescope-rs · codec-eval · codec-corpus
Pixel types & color zenpixels · zenpixels-convert · linear-srgb · garb
Pipeline zenpipe · zencodec · zencodecs · zenlayout · zennode
ImageResizer ImageResizer (C#) — 24M+ NuGet downloads across all packages
Imageflow Image optimization engine (Rust) — .NET · node · go — 9M+ NuGet downloads across all packages
Imageflow Server The fast, safe image server (Rust+C#) — 552K+ NuGet downloads, deployed by Fortune 500s and major brands

* as of 2026

General Rust awesomeness

archmage · magetypes · enough · whereat · zenbench · cargo-copter

And other projects · GitHub @imazen · GitHub @lilith · lib.rs/~lilith · NuGet (over 30 million downloads / 87 packages)

License

Dual-licensed: AGPL-3.0 or commercial.

I've maintained and developed open-source image server software — and the 40+ library ecosystem it depends on — full-time since 2011. Fifteen years of continual maintenance, backwards compatibility, support, and the (very rare) security patch. That kind of stability requires sustainable funding, and dual-licensing is how we make it work without venture capital or rug-pulls. Support sustainable and secure software; swap patch tuesday for patch leap-year.

Our open-source products

Your options:

  • Startup license — $1 if your company has under $1M revenue and fewer than 5 employees. Get a key →
  • Commercial subscription — Governed by the Imazen Site-wide Subscription License v1.1 or later. Apache 2.0-like terms, no source-sharing requirement. Sliding scale by company size. Pricing & 60-day free trial →
  • AGPL v3 — Free and open. Share your source if you distribute.

See LICENSE-COMMERCIAL for details.

AI-Generated Code Notice

Developed with Claude (Anthropic). Not all code manually reviewed. Review critical paths before production use.