A practical guide for developers using the PDFluent SDK to build document automation and processing pipelines in Rust.
Generate thousands of invoices, process incoming PDFs, fill forms, add watermarks, and run PDF pipelines in CI/CD — all from a single Rust binary with no external dependencies.
use pdfluent::{PdfDocument, WatermarkOptions};
fn main() -> pdfluent::Result<()> {
let mut doc = PdfDocument::open("template.pdf")?;
doc.form_mut()
.set_text("customer_name", "ACME Corp")?
.set_text("date", "2026-01-15")?;
doc.add_watermark("PROCESSED", WatermarkOptions::centered().opacity(0.15))?;
doc.save("filled.pdf")?;
Ok(())
}Automate PDF document processing at scale with PDFluent: extract text, split/merge pages, apply redactions, and convert to PDF/A — all in pure Rust.
use pdfluent::PdfDocument;
fn main() -> pdfluent::Result<()> {
let doc = PdfDocument::open("invoice.pdf")?;
// Positioned text blocks: text + bounding box + page
for block in doc.text_with_layout()? {
println!("p{} {:?} {}", block.page, block.bbox, block.text);
}
Ok(())
}Create invoices, receipts, reports, and templated documents from data. Pure Rust, no Java, no Python, no native dependencies.
use pdfluent::{PdfDocument, Page, Font, Color};
fn generate_invoice(order: &Order) -> Vec<u8> {
let mut doc = Document::new();
let mut page = Page::a4();
// Title
page.add_text(
&format!("Invoice #{}", order.id),
Font::helvetica_bold(24),
Position::new(50.0, 780.0),
);
// Line items table
let mut y = 700.0;
for item in &order.items {
page.add_text(
&item.description,
Font::helvetica(11),
Position::new(50.0, y),
);
page.add_text(
&format!("€ {:.2}", item.price),
Font::helvetica(11),
Position::new(480.0, y),
);
y -= 20.0;
}
// Footer
page.add_text(
&format!("Total: € {:.2}", order.total),
Font::helvetica_bold(13),
Position::new(50.0, y - 20.0),
);
doc.add_page(page);
doc.save_bytes()
}Lossless PDF merge and split in Rust — bookmarks, page labels, and named destinations preserved.
use pdfluent::{PdfDocument, PdfMerger, BookmarkMergeStrategy};
fn main() -> pdfluent::Result<()> {
let merged = PdfMerger::new()
.add(PdfDocument::open("chapter1.pdf")?)
.add(PdfDocument::open("chapter2.pdf")?)
.add(PdfDocument::open("chapter3.pdf")?)
.with_bookmarks(BookmarkMergeStrategy::Concat)
.with_page_labels(true)
.build()?;
merged.save("book_complete.pdf")?;
println!("Pages: {}", merged.page_count());
Ok(())
}Extract pages, split at bookmarks, or divide by content pattern. Batch split thousands of documents with bookmark and label preservation.
use pdfluent::PdfDocument;
fn main() -> pdfluent::Result<()> {
let doc = PdfDocument::open("report.pdf")?;
// Split into single-page documents
for (i, page) in doc.split_pages()?.into_iter().enumerate() {
page.save(format!("page-{}.pdf", i + 1))?;
}
// Or extract a contiguous range (0-based, end-exclusive)
doc.extract_pages(0..5)?.save("first-five.pdf")?;
Ok(())
}Compress images, remove duplicate streams, and optimize cross-reference tables. Reduce file size by 40-80% on typical documents.
use pdfluent::{PdfDocument, CompressOptions};
fn main() -> pdfluent::Result<()> {
let mut doc = PdfDocument::open("large.pdf")?;
let report = doc.compress(CompressOptions::strict())?;
println!("streams compressed: {}", report.streams_compressed);
println!("streams deduplicated: {}", report.streams_deduplicated);
doc.save("compressed.pdf")?;
Ok(())
}Send PDFs to system printers or generate print-ready output for PostScript and PCL workflows. No GUI needed.
use pdfluent::{Sdk, print::{PrintOptions, DuplexMode, PrintRange}};
fn main() -> pdfluent::Result<()> {
let sdk = Sdk::new()?;
let doc = sdk.open("invoice.pdf")?;
let opts = PrintOptions::builder()
.printer_name("HP_LaserJet_M404")
.copies(1)
.duplex(DuplexMode::LongEdge)
.page_range(PrintRange::All)
.collate(true)
.build();
let job = doc.print(opts)?;
println!("Print job ID: {}", job.id());
println!("Status: {:?}", job.wait_for_completion()?);
Ok(())
}Create PDF portfolios containing embedded files. Extract attachments from existing documents. Handle PDF/A-3 with embedded XML invoices.
use pdfluent::{Sdk, portfolio::{PortfolioOptions, EmbeddedFile}};
fn main() -> pdfluent::Result<()> {
let sdk = Sdk::new()?;
let mut doc = sdk.open("invoice.pdf")?;
// Attach a ZUGFeRD XML file for PDF/A-3 e-invoicing
let xml_bytes = std::fs::read("zugferd_invoice.xml")?;
let attachment = EmbeddedFile::builder()
.name("ZUGFeRD-invoice.xml")
.mime_type("application/xml")
.description("ZUGFeRD 2.1 invoice data")
.relationship(pdfluent::portfolio::Relationship::Alternative)
.data(xml_bytes)
.build();
let opts = PortfolioOptions::builder()
.add(PdfDocument::open(attachment)?)
.conform_to_pdfa3b(true)
.build();
let output = doc.embed_files(opts)?;
output.save("invoice_pdfa3.pdf")?;
println!("Attachments: {}", output.attachment_count());
Ok(())
}No native dependencies. No JVM. No DLLs. PDFluent runs on Lambda, Cloudflare Workers, and Fly.io straight from a single Rust binary.
use lambda_runtime::{run, service_fn, Error, LambdaEvent};
use pdfluent::PdfDocument;
use serde::{Deserialize, Serialize};
#[derive(Deserialize)]
struct Request {
/// Base64-encoded PDF bytes
pdf_b64: String,
}
#[derive(Serialize)]
struct Response {
page_count: usize,
}
async fn handler(event: LambdaEvent<Request>) -> Result<Response, Error> {
let bytes = base64::decode(&event.payload.pdf_b64)?;
let doc = Document::open_bytes(&bytes)?;
Ok(Response { page_count: doc.page_count() })
}
#[tokio::main]
async fn main() -> Result<(), Error> {
run(service_fn(handler)).await
}