Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Interactive Forms (AcroForms) and Annotations

rust-pdf-box provides a robust engine for creating, inspecting, filling, and flattening interactive PDF forms (AcroForms) and annotations (Links, Highlights, and Notes).


1. Overview & Architecture

Interactive PDF forms are rooted in the document catalog dictionary (/Root) under the /AcroForm entry. Each AcroForm contains:

  • /Fields: An array of field dictionaries (PDFormField).
  • /NeedAppearances: A boolean indicating whether viewers should regenerate appearance streams.
  • /DA: Default appearance string containing font and color commands (e.g., /Helv 10 Tf 0 g).
Document Catalog (/Root)
 └── /AcroForm
      ├── /Fields [ Ref(10 0 R), Ref(11 0 R) ]
      ├── /DA "(/Helv 10 Tf 0 g)"
      └── /NeedAppearances true

Annotations reside directly on individual pages under /Annots and link visual geometry (/Rect) with actions (such as URI navigation) or form field widgets (/Subtype /Widget).


2. Reading and Inspecting Form Fields

You can query all form fields present in a document:

#![allow(unused)]
fn main() {
use rust_pdf_box::prelude::*;

let mut doc = PdfDocument::open("sample_form.pdf")?;

if let Some(form) = doc.inner.catalog_mut()?.acro_form()? {
    let fields = form.fields(&doc.inner)?;
    for field in &fields {
        println!("Field Name: {}", field.name);
        println!("  Type: {:?}", field.field_type);
        println!("  Value: {:?}", field.value);
        println!("  Read-only: {}", field.is_read_only());
    }
}
}

Supported Field Types

Field TypePDF Type CodeDescription
FormFieldType::Text/TxSingle-line or multi-line text input fields
FormFieldType::Button/BtnPushbuttons, checkboxes (/Yes or /Off), and radio buttons
FormFieldType::Choice/ChDropdown combo boxes and multi-selection list boxes
FormFieldType::Signature/SigCryptographic signature placeholders
FormFieldType::UnknownCustomVendor-specific or specialized field types

3. Modifying Field Values

To set or update form field values programmatically:

#![allow(unused)]
fn main() {
use rust_pdf_box::prelude::*;

let mut doc = PdfDocument::open("sample_form.pdf")?;

if let Some(mut form) = doc.inner.catalog_mut()?.acro_form()? {
    // Fill text fields
    form.set_field_value(&mut doc.inner, "FullName", "Jane Doe")?;
    form.set_field_value(&mut doc.inner, "Email", "jane.doe@techwasti.com")?;
    form.set_field_value(&mut doc.inner, "Comments", "Expedited delivery requested.")?;

    // Check a checkbox (typically "Yes" or "Off")
    form.set_field_value(&mut doc.inner, "SubscribeNewsletter", "Yes")?;
}

doc.save("filled_form.pdf")?;
}

4. Form Flattening

Form flattening converts interactive widgets into static, non-editable vector graphics directly rendered onto the page content streams, and removes the /AcroForm catalog entry.

Why Flatten?

  • Security & Immutability: Prevents recipients from tampering with filled data in legal contracts and invoices.
  • Universal Rendering: Ensures consistent appearance across third-party mobile viewers and print drivers that do not evaluate AcroForm appearances.
  • Archival Compliance: Essential for PDF/A long-term archiving standards.

How to Flatten:

#![allow(unused)]
fn main() {
use rust_pdf_box::prelude::*;

let mut doc = PdfDocument::open("filled_form.pdf")?;

if let Some(mut form) = doc.inner.catalog_mut()?.acro_form()? {
    // Burns all field values into page content streams and clears widget annotations
    form.flatten(&mut doc.inner)?;
}

doc.save("contract_permanent.pdf")?;
}

5. Adding Annotations to Pages

You can attach clickable URI links to arbitrary page rectangles:

#![allow(unused)]
fn main() {
use rust_pdf_box::prelude::*;
use rust_pdf_box::interactive::PDAnnotation;

let mut doc = PdfDocument::create();
let page_idx = doc.add_page(PDRectangle::A4);

// Create a clickable link rectangle: (x, y, width, height)
let link = PDAnnotation::link(
    PDRectangle::new(50.0, 700.0, 200.0, 20.0),
    "https://techwasti.com"
);

// Register annotation on the page
doc.inner.page_mut(page_idx)?.add_annotation(&mut doc.inner, link)?;
doc.save("document_with_links.pdf")?;
}