Build a nested bookmark outline and attach it to any PDF. Bookmarks appear in the navigation panel of PDF viewers and make long documents easier to navigate.
use pdfluent::{PdfDocument, Outline, OutlineItem};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut doc = PdfDocument::open("report.pdf")?;
let outline = Outline::new()
.add(OutlineItem::new("Introduction").page(0))
.add(OutlineItem::new("Chapter 1: Setup").page(2)
.child(OutlineItem::new("Installation").page(3))
.child(OutlineItem::new("Configuration").page(5)))
.add(OutlineItem::new("Chapter 2: Usage").page(8))
.add(OutlineItem::new("Conclusion").page(14));
doc.set_outline(outline)?;
doc.save("report_with_bookmarks.pdf")?;
Ok(())
}Add the pdfluent crate to Cargo.toml.
[dependencies]
pdfluent = "0.9"Load the PDF you want to add bookmarks to. The document must already exist; bookmarks reference page indices in the file.
use pdfluent::PdfDocument;
let mut doc = PdfDocument::open("manual.pdf")?;
println!("Pages: {}", doc.page_count());Create an Outline and add OutlineItem entries. Each item needs a title and a target page index (zero-based). Nest children with .child().
use pdfluent::{Outline, OutlineItem};
let outline = Outline::new()
.add(OutlineItem::new("Cover").page(0))
.add(OutlineItem::new("Table of Contents").page(1))
.add(OutlineItem::new("Part I: Basics").page(2)
.child(OutlineItem::new("Chapter 1").page(2))
.child(OutlineItem::new("Chapter 2").page(6)))
.add(OutlineItem::new("Part II: Advanced").page(10)
.child(OutlineItem::new("Chapter 3").page(10))
.child(OutlineItem::new("Chapter 4").page(14)))
.add(OutlineItem::new("Index").page(18));Call set_outline() to replace any existing bookmark tree with the new one. The previous outline is discarded.
doc.set_outline(outline)?;Write the PDF with the new bookmark tree to disk.
doc.save("manual_with_bookmarks.pdf")?;
println!("Bookmarks written.");No JVM, no runtime, no DLL dependencies. Ships as a single native binary or WASM module.
Rust's ownership model prevents buffer overflows and use-after-free. No segfaults in PDF parsing.
Same code runs server-side, in Docker, on AWS Lambda, on Cloudflare Workers, or in the browser via WASM.