pdf-writer Documentation

repository·main·Indexed 20 days ago

https://github.com/typst/pdf-writer

A step-by-step PDF construction library (v0.15.0) that uses a builder pattern to create PDF objects in a strongly typed and memory-efficient manner. It provides a hierarchical API via the Pdf struct to manage document buffers and specialized writers for creating catalogs, page trees, annotations, actions, and layout attributes.

Tokens
20.9K
Snippets
49
Records
112
Agent score
73%

What's inside pdf-writer

  1. How the pdf-writer API works

    main

    The pdf-writer API uses a hierarchical, step-by-step approach to constructing PDF documents. The entry point is the Pdf struct, which manages a single large internal buffer for the entire document.

    To create specific PDF objects, you call methods on the top-level Pdf writer. These methods return specialized writers that follow a consistent pattern:

    1. They borrow the main buffer mutably.
    2. They expose a builder pattern to write individual fields in a strongly typed manner.
    3. They finalize the object automatically when the specialized writer is dropped.

    While most writers borrow from the parent to minimize allocations, some specialized builders (like the one for Content streams) maintain their own internal buffers.

  2. Use the Sides<T> helper for rectangular values

    main

    The Sides<T> struct is a helper for writing values that apply to the four sides of a rectangle (before, after, start, end), as required by the PDF specification.

    It automatically handles the distinction between a single uniform value and an array of four distinct values.

    Creation

    • Sides::new(before, after, start, end): Create with specific values.
    • Sides::from_array([before, after, start, end]): Create from a 4-element array.
    • Sides::uniform(value): Create with the same value for all four sides.

    Usage in Writers

    Many layout methods accept Sides<T> to simplify writing:

    • border_color(color: Sides<[f32; 3]>)
    • border_style(style: Sides<LayoutBorderStyle>)
    • border_thickness(thickness: Sides<f32>)
    • padding(padding: Sides<f32>)
    • table_border_style(style: Sides<LayoutBorderStyle>)
    • table_padding(padding: Sides<f32>)
    // Example: Setting a uniform padding of 10.0
    layout_attrs.padding(Sides::uniform(10.0));
    
    // Example: Setting non-uniform padding
    layout_attrs.padding(Sides::new(5.0, 10.0, 2.0, 2.0));
  3. How XObjects work in pdf-writer

    main

    XObjects (External Objects) allow for the reuse of content and images within a PDF. The library provides specialized writers for different types of XObjects:

    1. Image XObjects: Used for image data. They require dimensions (Width, Height) and bit depth (BitsPerComponent), and typically a ColorSpace.
    2. Form XObjects: Used to encapsulate reusable content streams. They require a bounding box (BBox) and can contain their own Resources and Group settings.
    3. Group XObjects: Used to define transparency and isolation settings for a collection of objects.
    4. Reference XObjects: Used to point to pages in external documents.

    Most XObject writers implement Deref to the underlying Stream, allowing you to use standard stream writing methods (like pair) directly on the XObject writer.

  4. Implement Tagged PDF Structure Trees

    main

    For accessibility and structured documents (required for many PDF/A profiles), use StructTreeRoot and StructElement to build a document structure tree.

    StructTreeRoot

    Created via Catalog::struct_tree_root(). It manages the mapping of elements and their hierarchy:

    • child(id: Ref) / children(): Defines the immediate children.
    • id_tree(): Maps element identifiers to objects.
    • parent_tree(): Maps structure elements to their content items.
    • role_map(): Maps custom names to standard roles.
    • class_map(): Maps attribute classes.

    StructElement

    Created via StructTreeRoot::child() or similar. Represents a specific semantic unit (e.g., a paragraph or heading):

    • kind(role: StructRole): Sets the semantic role for PDF 1.7 and below.
    • kind_2(role: StructRole2, pdf_2_ns: Ref): Sets the role for PDF 2.0 using a namespace.
    • custom_kind(name: Name): Sets a custom role name.
    • parent(parent: Ref): Sets the parent element (Required).
    • id(id: Str): Sets the element identifier.
    • title(title: impl TextStrLike): Sets a title for the element.
    • lang(lang: TextStr): Sets the language for the element.
    • alt(alt: impl TextStrLike): Provides an alternative description (e.g., for screen readers).
  5. Configure annotation appearance with Appearance and AppearanceEntry

    main

    To control how an annotation is visually presented, use the appearance() method on an Annotation to get an Appearance writer. This allows you to define different visual states:

    • normal(): Sets the /N (normal) appearance.
    • rollover(): Sets the /R (hover) appearance.
    • alternate(): Sets the /D (down/pressed) appearance.

    Each of these returns an AppearanceEntry, which can be configured in two ways:

    1. As a stream: Use .stream(id: Ref) to provide an indirect reference to a FormXObject containing the appearance stream.
    2. As a subdictionary: Use .streams() to start writing a dictionary containing indirect references to multiple FormXObjects.
    annotation.appearance()
        .normal()
        .stream(form_xobject_ref);
  6. Low-level PDF writing constraints

    main

    The pdf-writer crate is a low-level tool. Users are responsible for:

    • ID Management: The crate does not allocate or validate indirect reference IDs. You must ensure IDs are unique.
    • Schema Validation: The crate does not check if you have written all required fields for a specific PDF object. You must refer to the PDF specification to ensure your generated document is valid.
  7. Define additional actions for different PDF elements

    main

    The AdditionalActions struct allows you to define event-based actions (like mouse clicks, focus changes, or page visibility) for various PDF components. The available methods depend on the context of the element being configured:

    For Annotations

    • annot_curser_enter(): Triggered when the cursor enters the active area (/E).
    • annot_cursor_exit(): Triggered when the cursor exits the active area (/X).
    • annot_mouse_press(): Triggered on mouse button press (/D).
    • annot_mouse_release(): Triggered on mouse button release (/U).
    • annot_page_open(): Triggered when the page containing the annotation is opened (/PO).
    • annot_page_close(): Triggered when the page is closed (/PC).
    • annot_page_visible(): Triggered when the page becomes visible (/PV).
    • annot_page_invisible(): Triggered when the page is no longer visible (/PI).

    For Widget Annotations (Form Fields)

    • widget_focus(): Triggered when the annotation receives input focus (/Fo).
    • widget_focus_loss(): Triggered when the annotation loses input focus (/Bl).

    For Page Objects

    • page_open(): Triggered when the page is opened (/O).
    • page_close(): Triggered when the page is closed (/C).

    For Form Fields

    • form_calculate_partial(): Triggered when a character is modified (/K).
    • form_format(): Triggered before a field is formatted (/F).
    • form_validate(): Triggered when the field's value is changed (/V).
    • form_calculate(): Triggered to recalculate the value when another field changes (/C).

    For Document Catalog

    • cat_before_close(): Before closing the document (/WC).
    • cat_before_save(): Before saving the document (/WS).
    • cat_after_save(): After saving the document (/DS).
    • cat_before_print(): Before printing the document (/WP).
    • cat_after_print(): After printing the document (/DP).
  8. Create a minimal PDF with a single A4 page

    main

    To create a PDF, you must define indirect reference IDs using Ref, use the Pdf struct to build the document hierarchy (Catalog, Page Tree, and Pages), and finally call .finish() to generate the byte stream for writing to a file.

    This example demonstrates creating a single, empty A4 page (595.0 x 842.0 points) with no resources.

    use pdf_writer::{Pdf, Rect, Ref};
    
    // Define some indirect reference ids we'll use.
    let catalog_id = Ref::new(1);
    let page_tree_id = Ref::new(2);
    let page_id = Ref::new(3);
    
    // Write a document catalog and a page tree with one A4 page that uses no resources.
    let mut pdf = Pdf::new();
    pdf.catalog(catalog_id).pages(page_tree_id);
    pdf.pages(page_tree_id).kids([page_id]).count(1);
    pdf.page(page_id)
        .parent(page_tree_id)
        .media_box(Rect::new(0.0, 0.0, 595.0, 842.0))
        .resources();
    
    // Finish with cross-reference table and trailer and write to file.
    std::fs::write("target/empty.pdf", pdf.finish())?;
  9. Reference: FieldFlags

    main

    Bitflags describing various characteristics of a form field (/Ff).

    bitflags! {
        pub struct FieldFlags: u32 {
            const READ_ONLY = 1;
            const REQUIRED = 2;
            const NO_EXPORT = 1 << 2;
            const DO_NOT_SPELL_CHECK = 1 << 22;
    
            // Button specific
            const NO_TOGGLE_TO_OFF = 1 << 14;
            const RADIO = 1 << 15;
            const PUSHBUTTON = 1 << 16;
            const RADIOS_IN_UNISON = 1 << 25;
    
            // Text field specific
            const MULTILINE = 1 << 12;
            const PASSWORD = 1 << 13;
            const FILE_SELECT = 1 << 20;
            const DO_NOT_SCROLL = 1 << 23;
            const COMB = 1 << 24;
            const RICH_TEXT = 1 << 25;
    
            // Choice field specific
            const COMBO = 1 << 17;
            const EDIT = 1 << 18;
            const SORT = 1 << 19;
            const MULTI_SELECT = 1 << 21;
            const COMMIT_ON_SEL_CHANGE = 1 << 26;
        }
    }
  10. Reference: SigFlags

    main

    Bitflags describing document-level characteristics related to signature fields.

    bitflags! {
        pub struct SigFlags: u32 {
            const SIGNATURES_EXIST = 1;
            const APPEND_ONLY = 2;
        }
    }
  11. Configure FieldAttributes for form controls

    main

    The FieldAttributes struct (PDF 1.6+) defines the appearance and role of form fields.

    Methods:

    • role(role: FieldRole): Sets the /Role attribute (e.g., Button, CheckBox, RadioButton, TextField, ListBox).
    • checked(checked: FieldState, pdf2: bool): Sets the /checked (PDF 1.6+) or /Checked (PDF 2.0+) attribute.
    • description(desc: impl TextStrLike): Sets the /Desc attribute.