Guide

Existing PDF Overlay

Open existing PDFs and add text, images, stamps, and page numbers on top

Overview

gpdf can open existing PDFs and overlay new content on top of them without modifying the original data. This uses the Incremental Update technique — new objects are appended after the original PDF bytes.

Common use cases:

  • Adding watermarks ("DRAFT", "CONFIDENTIAL")
  • Inserting page numbers
  • Stamping approval marks with dates
  • Adding headers/footers to existing documents

Opening an Existing PDF

import gpdf "github.com/gpdf-dev/gpdf"

// Read existing PDF bytes (from file, HTTP response, database, etc.)
pdfBytes, _ := os.ReadFile("input.pdf")

doc, err := gpdf.Open(pdfBytes)
if err != nil {
    log.Fatal(err)
}

You can pass the same options as NewDocument — fonts, default font, etc.:

doc, err := gpdf.Open(pdfBytes,
    gpdf.WithFont("NotoSans", fontData),
    gpdf.WithDefaultFont("NotoSans", 12),
)

Overlay on a Single Page

Use Overlay(pageIndex, fn) to add content on a specific page (0-based index):

doc.Overlay(0, func(p *template.PageBuilder) {
    p.Absolute(document.Mm(40), document.Mm(120), func(c *template.ColBuilder) {
        c.Text("DRAFT",
            template.FontSize(72),
            template.TextColor(pdf.Gray(0.85)),
        )
    })
})

The PageBuilder supports the same API as when creating new pages — AutoRow, Absolute, Row, etc.

Overlay on Every Page

Use EachPage(fn) to iterate over all pages:

count, _ := doc.PageCount()

doc.EachPage(func(pageIndex int, p *template.PageBuilder) {
    p.Absolute(document.Mm(170), document.Mm(285), func(c *template.ColBuilder) {
        c.Text(fmt.Sprintf("%d / %d", pageIndex+1, count),
            template.FontSize(10),
            template.AlignRight(),
        )
    }, template.AbsoluteWidth(document.Mm(20)))
})

Saving the Result

result, err := doc.Save()
if err != nil {
    log.Fatal(err)
}
os.WriteFile("output.pdf", result, 0644)

The original PDF content is preserved — Save() appends overlay data after the original bytes.

Complete Example: Watermark + Page Numbers

pdfBytes, _ := os.ReadFile("report.pdf")

doc, err := gpdf.Open(pdfBytes)
if err != nil {
    log.Fatal(err)
}

count, _ := doc.PageCount()

doc.EachPage(func(i int, p *template.PageBuilder) {
    // Watermark
    p.Absolute(document.Mm(40), document.Mm(140), func(c *template.ColBuilder) {
        c.Text("CONFIDENTIAL",
            template.FontSize(60),
            template.TextColor(pdf.Color{R: 0.9, G: 0.9, B: 0.9, A: 1, Space: pdf.ColorSpaceRGB}),
        )
    })

    // Page number (bottom-right)
    p.Absolute(document.Mm(170), document.Mm(285), func(c *template.ColBuilder) {
        c.Text(fmt.Sprintf("%d / %d", i+1, count),
            template.FontSize(10),
            template.AlignRight(),
        )
    }, template.AbsoluteWidth(document.Mm(20)))
})

result, _ := doc.Save()
os.WriteFile("report_stamped.pdf", result, 0644)

API Reference

MethodDescription
gpdf.Open(data, opts...)Open an existing PDF for modification
doc.PageCount()Get the number of pages
doc.Overlay(pageIndex, fn)Add content on a specific page (0-based)
doc.EachPage(fn)Add content on every page
doc.Save()Return the modified PDF bytes

Next Steps

  • Fonts — Embedding fonts, CJK support, and text shaping limitations
  • Basic Usage — Creating PDFs from scratch
  • Styling — Colors, text decoration, and typography
  • API Reference — Full gpdf package reference