Add watermarks, stamps, headers and page numbers

This guide shows developers how to use PDFluent to apply common page elements to PDF documents. It is for Rust programmers working with PDFs.

Add PDFluent to your project

Add the pdfluent crate to Cargo.toml.

toml
[dependencies]
pdfluent = "1.0.0"

Add a text watermark to a PDF in Rust

Stamp each page with a diagonal text watermark. Control font, size, colour, opacity, rotation, and position.

rust
use pdfluent::{PdfDocument, WatermarkOptions};

fn main() -> pdfluent::Result<()> {
    let mut doc = PdfDocument::open("report.pdf")?;
    doc.add_watermark("DRAFT", WatermarkOptions::centered().opacity(0.3))?;
    doc.save("watermarked.pdf")?;
    Ok(())
}
  1. Open the PDF

    Open the document with a mutable binding.

    rust
    use pdfluent::PdfDocument;
    
    let mut doc = PdfDocument::open("contract.pdf")?;
  2. Build a TextWatermark

    Create a TextWatermark with the text you want to stamp. Use the builder methods to set style properties.

    rust
    use pdfluent::WatermarkOptions;
    
    let opts = WatermarkOptions::centered()
        .font_size(72.0)
        .opacity(0.12)          // 12% opacity
        .rotated(45.0)          // degrees
        .color(0.6, 0.0, 0.0);  // dark red, sRGB
  3. Set the position

    WatermarkPosition::Center places the text at the page centre. Other options include TopLeft, TopRight, BottomLeft, BottomRight, and Custom(x, y).

    rust
    // Watermarks are centered by default; tune size, angle, and opacity
    let opts = WatermarkOptions::centered()
        .font_size(64.0)
        .rotated(45.0)
        .opacity(0.15);
  4. Apply to all pages or specific pages

    add_watermark() stamps every page. There is no page subset: WatermarkOptions carries position, rotation, opacity, layer, font size and colour, and not a page list.

    rust
    // Apply to all pages
    doc.add_watermark("DRAFT", opts)?;
  5. Save the result

    Save the watermarked document to disk.

    rust
    doc.save("contract_draft.pdf")?;
  • Opacity of 0.1 to 0.2 is typical for background watermarks. Higher values produce more prominent stamps.
  • The watermark is drawn as a content stream beneath the page text so it does not obscure the document content.
  • To place the watermark on top of the content instead, use watermark.layer(WatermarkLayer::Foreground).
  • PDFluent uses the Helvetica built-in font by default. Specify a custom font path with .font_path("path/to/font.ttf").

Apply a stamp or label to each page of a PDF in Rust

Draw text or an image stamp at a fixed position on every page, with configurable opacity, size, and rotation.

rust
use pdfluent::{PdfDocument, PageDecoration, WatermarkOptions};
use pdfluent::watermark::{Layer, Position};

fn main() -> pdfluent::Result<()> {
    let mut doc = PdfDocument::open("input.pdf")?;

    doc.add_decoration(PageDecoration::watermark(
        "CONFIDENTIAL",
        WatermarkOptions::centered()
            .at(Position::TopRight(36.0, 36.0))
            .layer(Layer::Foreground)
            .font_size(18.0)
            .color(0.8, 0.1, 0.1)
            .opacity(1.0),
    ))?;

    doc.save("stamped.pdf")?;
    Ok(())
}
  1. Open the document

    Stamping rewrites page content, so bind the document as mutable.

    rust
    let mut doc = PdfDocument::open("input.pdf")?;
  2. Describe the stamp

    WatermarkOptions carries the whole appearance. Layer::Foreground draws the stamp over the page content; Layer::Background puts it underneath. Colour components are floats from 0.0 to 1.0.

    rust
    use pdfluent::WatermarkOptions;
    use pdfluent::watermark::{Layer, Position};
    
    let look = WatermarkOptions::centered()
        .at(Position::TopRight(36.0, 36.0))   // points in from the corner
        .layer(Layer::Foreground)
        .font_size(18.0)
        .color(0.8, 0.1, 0.1)
        .opacity(1.0);
  3. Apply it

    add_decoration takes the text and the appearance together. add_watermark(text, options) is the same operation under a shorter name.

    rust
    use pdfluent::PageDecoration;
    
    doc.add_decoration(PageDecoration::watermark("CONFIDENTIAL", look))?;
  4. Angle it across the page instead

    A diagonal draft mark is the same call with a rotation and a lower opacity, centred rather than cornered.

    rust
    doc.add_watermark(
        "DRAFT",
        WatermarkOptions::centered()
            .rotated(45.0)
            .opacity(0.3)
            .font_size(64.0)
            .layer(Layer::Background),
    )?;
  5. Stamp an image

    An image stamp is an image insert, not a decoration. Give it the target page, the position in PDF points from the bottom-left, and the size to draw at.

    rust
    use pdfluent::{ImageInsert, InsertImageFormat};
    
    let logo = std::fs::read("stamp_logo.png")?;
    let report = doc.insert_image(
        ImageInsert::new(logo, InsertImageFormat::Png, 1, 400.0, 700.0, 120.0, 40.0)
            .with_opacity(0.6),
    )?;
    println!("placed {} at {}x{}px", report.resource_name, report.pixel_width, report.pixel_height);
  6. Save the result

    Write the stamped document to a new file.

    rust
    doc.save("stamped.pdf")?;
  • A decoration is applied to every page in the document. There is no per-page selection on add_decoration or add_watermark; to mark a single page, use insert_image, which takes a page number.
  • Page numbers on ImageInsert are 1-based, and positions are PDF points measured from the bottom-left of the page.
  • Layer::Foreground draws over the existing content and will cover it where they overlap. Layer::Background keeps the page readable but is hidden by opaque page elements.
  • PNG input is decoded and re-encoded with FlateDecode, carrying an alpha channel through as an SMask. JPEG is passed through untouched as a DCTDecode stream, so it is not re-compressed.
  • PageDecoration currently models watermark text only. Headers, footers and page numbers are not variants of it.