Implementing Bates Numbering in Rust — Stamping Every Page of a Legal Document

All tests run on an 8-year-old MacBook Air.

Bates numbering is a sequential stamp applied to every page of a legal document — “EXHIBIT-0001”, “EXHIBIT-0002” — so every page can be uniquely referenced in court.

It sounds simple. The PDF implementation…


This content originally appeared on DEV Community and was authored by hiyoyo

All tests run on an 8-year-old MacBook Air.

Bates numbering is a sequential stamp applied to every page of a legal document — "EXHIBIT-0001", "EXHIBIT-0002" — so every page can be uniquely referenced in court.

It sounds simple. The PDF implementation has a few gotchas.

The basic approach

For each page, inject a text operator into the content stream at a fixed position:

pub fn apply_bates(
    doc: &mut Document,
    prefix: &str,
    start: u32,
    digits: usize,
    position: BatesPosition,
) -> Result<(), lopdf::Error> {
    let pages: Vec = doc.page_iter().collect();

    for (i, page_id) in pages.iter().enumerate() {
        let number = format!("{}{:0>width$}", prefix, start + i as u32, width = digits);
        let (x, y) = position.coordinates_for_page(doc, *page_id);

        let stamp = format!(
            "q BT /HiyokoF1 9 Tf 0 0 0 rg {} {} Td ({}) Tj ET Q\n",
            x, y, number
        );

        append_to_page_content(doc, *page_id, stamp.as_bytes())?;
    }

    Ok(())
}

The font embedding problem

/HiyokoF1 in that content stream references a font resource. If the font isn't in the page's resource dictionary, viewers will substitute or error.

You need to embed a font reference in every page's Resources:

pub fn ensure_font_resource(
    doc: &mut Document,
    page_id: ObjectId,
    font_id: ObjectId,
) -> Result<(), lopdf::Error> {
    let page = doc.get_object_mut(page_id)?.as_dict_mut()?;

    let resources = page
        .get_mut(b"Resources")
        .and_then(|r| r.as_dict_mut())
        .ok_or(lopdf::Error::DictKey)?;

    let fonts = resources
        .entry(b"Font".to_vec())
        .or_insert_with(|| Object::Dictionary(Dictionary::new()))
        .as_dict_mut()?;

    fonts.set(b"HiyokoF1", Object::Reference(font_id));
    Ok(())
}

Miss this step and your stamps are invisible.

Position logic

Bottom-right is the legal standard. But page dimensions vary — A4, Letter, custom sizes — so you can't hardcode coordinates.

pub fn bottom_right(doc: &Document, page_id: ObjectId) -> (f64, f64) {
    let (width, height) = get_page_size(doc, page_id);
    (width - 72.0, 36.0)  // 1-inch from right, 0.5-inch from bottom
}

Result

Prefix, start number, zero-padding width, position — fully configurable. Processes a 500-page document in under a second.

Hiyoko PDF Vault → https://hiyokoko.gumroad.com/l/HiyokoPDFVault
X → @hiyoyok


This content originally appeared on DEV Community and was authored by hiyoyo


Print Share Comment Cite Upload Translate Updates
APA

hiyoyo | Sciencx (2026-04-26T01:15:20+00:00) Implementing Bates Numbering in Rust — Stamping Every Page of a Legal Document. Retrieved from https://www.scien.cx/2026/04/26/implementing-bates-numbering-in-rust-stamping-every-page-of-a-legal-document/

MLA
" » Implementing Bates Numbering in Rust — Stamping Every Page of a Legal Document." hiyoyo | Sciencx - Sunday April 26, 2026, https://www.scien.cx/2026/04/26/implementing-bates-numbering-in-rust-stamping-every-page-of-a-legal-document/
HARVARD
hiyoyo | Sciencx Sunday April 26, 2026 » Implementing Bates Numbering in Rust — Stamping Every Page of a Legal Document., viewed ,<https://www.scien.cx/2026/04/26/implementing-bates-numbering-in-rust-stamping-every-page-of-a-legal-document/>
VANCOUVER
hiyoyo | Sciencx - » Implementing Bates Numbering in Rust — Stamping Every Page of a Legal Document. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2026/04/26/implementing-bates-numbering-in-rust-stamping-every-page-of-a-legal-document/
CHICAGO
" » Implementing Bates Numbering in Rust — Stamping Every Page of a Legal Document." hiyoyo | Sciencx - Accessed . https://www.scien.cx/2026/04/26/implementing-bates-numbering-in-rust-stamping-every-page-of-a-legal-document/
IEEE
" » Implementing Bates Numbering in Rust — Stamping Every Page of a Legal Document." hiyoyo | Sciencx [Online]. Available: https://www.scien.cx/2026/04/26/implementing-bates-numbering-in-rust-stamping-every-page-of-a-legal-document/. [Accessed: ]
rf:citation
» Implementing Bates Numbering in Rust — Stamping Every Page of a Legal Document | hiyoyo | Sciencx | https://www.scien.cx/2026/04/26/implementing-bates-numbering-in-rust-stamping-every-page-of-a-legal-document/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.