How-to guides/Document Structure

Add bookmarks (outline) to a PDF in Rust

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.

rust
use pdfluent::PdfDocument;
use pdfluent::structure::Outline;

fn main() -> pdfluent::Result<()> {
    let mut doc = PdfDocument::open("report.pdf")?;
    doc.set_outlines(&[
        Outline::new("Introduction", 0),
        Outline::new("Results", 4),
    ])?;
    doc.save("bookmarked.pdf")?;
    Ok(())
}

Step by step

1

Add PDFluent to your project

Add the pdfluent crate to Cargo.toml.

rust
[dependencies]
pdfluent = "1.0.0-beta.8"
2

Open the PDF

Load the PDF you want to add bookmarks to. The document must already exist; bookmarks reference page indices in the file.

rust
use pdfluent::PdfDocument;

let mut doc = PdfDocument::open("manual.pdf")?;
println!("Pages: {}", doc.page_count());
3

Build the outline structure

Create an Outline and add OutlineItem entries. Each item needs a title and a target page index (zero-based). Nest children with .child().

rust
use pdfluent::structure::Outline;

let mut part1 = Outline::new("Part I: Basics", 2);
part1.children.push(Outline::new("Chapter 1", 2));
part1.children.push(Outline::new("Chapter 2", 6));

let mut part2 = Outline::new("Part II: Advanced", 10);
part2.children.push(Outline::new("Chapter 3", 10));
part2.children.push(Outline::new("Chapter 4", 14));

let outline = vec![
    Outline::new("Cover", 0),
    Outline::new("Table of Contents", 1),
    part1,
    part2,
    Outline::new("Index", 18),
];
4

Set the outline on the document

Call set_outline() to replace any existing bookmark tree with the new one. The previous outline is discarded.

rust
doc.set_outlines(&outline)?;
5

Save the document

Write the PDF with the new bookmark tree to disk.

rust
doc.save("manual_with_bookmarks.pdf")?;
println!("Bookmarks written.");

Notes and tips

  • Page indices in OutlineItem are zero-based. Page 1 in the viewer is index 0.
  • Nesting depth is unlimited, but most PDF viewers display up to 3-4 levels in the outline panel.
  • set_outline() replaces the entire outline. To append to an existing outline, read it first with doc.outline(), modify the tree, then set it back.
  • OutlineItem also accepts a named destination with .destination("dest_name") instead of a page index.

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