Document Management
Document Management
Document is the entry point for every document-management operation covered here: opening and saving files, exporting to HTML, adding optional content layers, authoring Tagged PDF, and reading or writing AcroForm data. Page and Form are reached through Document.Page(n) and Document.Form().
Opening and Saving Documents
pdf.Open loads a PDF from a file path; pdf.OpenWithPassword does the same for password-protected files. Document.Save writes the result to a new file path.
doc, err := pdf.Open("input.pdf")
if err != nil {
panic(err)
}
_, err = pdf.OpenWithPassword("locked.pdf", "userpassword")
if err != nil {
panic(err)
}
err = doc.Save("output.pdf")Exporting to HTML
Document.SaveHTML and Document.WriteHTML convert a document to HTML. HTMLSaveOptions.Mode selects the representation: HTMLModeText (visible styled text over a glyph-less raster background), HTMLModeNative (page graphics as one inline SVG layer), or HTMLModeFlow (reflowable HTML with headings and paragraphs in reading order). Leaving Mode unset produces the faithful default: a full page raster with a transparent selectable text layer.
doc, _ := pdf.Open("input.pdf")
// Faithful mode (default)
doc.SaveHTML("out.html")
// Visible-text mode
doc.SaveHTML("out.html", pdf.HTMLSaveOptions{Mode: pdf.HTMLModeText})
// Multi-file output: external resources plus one HTML file per page
doc.SaveHTML("site/doc.html", pdf.HTMLSaveOptions{
Mode: pdf.HTMLModeNative, ResourceDir: "assets", SplitPages: true,
})
// Page subset, custom raster DPI and title
doc.SaveHTML("part.html", pdf.HTMLSaveOptions{Pages: []int{1, 3}, DPI: 96, Title: "Report"})Managing Optional Content Layers
Document.AddLayer(name) creates a new Optional Content Group and returns a *Layer; Document.Layers() lists every layer already present. Page.BeginLayer / Page.EndLayer mark page content as belonging to a layer, and Layer.SetVisible(false) hides that content.
doc := pdf.NewDocumentFromFormat(pdf.PageFormatA4)
layer := doc.AddLayer("Watermark")
page, _ := doc.Page(1)
page.BeginLayer(layer)
page.AddText("DRAFT", pdf.TextStyle{Font: pdf.FontHelveticaBold, Size: 48},
pdf.Rectangle{LLX: 150, LLY: 400, URX: 450, URY: 460})
page.EndLayer()
layer.SetVisible(false)
doc.Save("layered.pdf")Building Tagged (Accessible) PDFs
Document.TaggedContent() returns the *TaggedContent facade that owns the logical structure tree of the document and sets the catalog metadata PDF/UA requires. Page.TagContent brackets a drawing call in marked content and returns a *StructElement for that node.
doc := pdf.NewDocumentFromFormat(pdf.PageFormatA4)
tc := doc.TaggedContent()
tc.SetTitle("Quarterly Report")
tc.SetLanguage("en-US")
page, _ := doc.Page(1)
page.TagContent(tc.Root(), pdf.StructH1, func() error {
return page.AddText("Quarterly Report", pdf.TextStyle{Font: pdf.FontHelveticaBold, Size: 24},
pdf.Rectangle{LLX: 50, LLY: 760, URX: 545, URY: 800})
})
fig, _ := page.TagContent(tc.Root(), pdf.StructFigure, func() error {
return page.AddImage("chart.png", pdf.Rectangle{LLX: 50, LLY: 540, URX: 300, URY: 680})
})
fig.SetAlt("Bar chart of Q3 sales by region") // required for figures
doc.Save("accessible.pdf")Grouping elements nest under the tree root as well:
doc := pdf.NewDocumentFromFormat(pdf.PageFormatA4)
tc := doc.TaggedContent()
page, _ := doc.Page(1)
tbl := tc.Root().AddChild(pdf.StructTable)
row := tbl.AddChild(pdf.StructTR)
cell := row.AddChild(pdf.StructTD)
page.TagContent(cell, pdf.StructP, func() error { return nil })Exporting and Importing Form Data as JSON
Form.ExportJSON serializes every field type and value to JSON ({"name": {"type": "text", "value": "Jane"}, ...}); Form.ImportJSON applies a JSON payload to a form and returns the number of fields it updated. JSONExportOptions.Indent pretty-prints the output.
doc, _ := pdf.Open("filled.pdf")
data, _ := doc.Form().ExportJSON(pdf.JSONExportOptions{Indent: true})
// Fill a template from a JSON payload; discard the applied-field count.
template, _ := pdf.Open("template.pdf")
_, _ = template.Form().ImportJSON(data)Tips and Best Practices
- Choose
HTMLModeNativefor vector-heavy pages,HTMLModeFlowfor reflow/mobile reading, and the faithful default (noModeset) when visual fidelity matters most. - Call
Layer.SetVisible(false)beforeSaveto hide watermark or annotation layers by default while keeping the content addressable through theLayerobject. - Set
TaggedContent.SetTitleandSetLanguagebefore callingPage.TagContent, since PDF/UA validation checks the catalog-level metadata those methods write. - Call
StructElement.SetAlton everyStructFigurenode — figures without alternate text fail PDF/UA validation. - Use
JSONExportOptions.Indentfor human-readable diffing of exported form state; omit it for compact machine-to-machine payloads.
Common Issues
| Issue | Cause | Fix |
|---|---|---|
| HTML output has no selectable text glyphs | HTMLSaveOptions.Mode left at faithful default without a text layer requirement | Set Mode: pdf.HTMLModeText for a visible, styled text layer |
| HTML export loses the source font appearance | NoFontEmbedding set to true | Leave NoFontEmbedding false (default) so embedded fonts are re-wrapped as WOFF @font-face data URLs |
Page.TagContent returns an error | Called before Document.TaggedContent() initialized the structure tree | Call Document.TaggedContent() (and set title/language) before the first TagContent call |
ValidatePDFUA reports non-conformant figures | A StructFigure element has no alt text | Call StructElement.SetAlt on every figure node |
Form.ImportJSON updates fewer fields than expected | JSON payload field names do not match the target form field names; import is lenient and skips unmatched entries | Confirm exported field names match the target form field names exactly |
FAQ
Which HTML export mode should I use?
HTMLModeText for the smallest, fully selectable output; HTMLModeNative when vector fidelity (curves, native strokes) matters more than file size; HTMLModeFlow for a reflowable, mobile-friendly reading layout. Leave Mode unset for the faithful raster-plus-transparent-text default.
Can I export only specific pages to HTML?
Yes. Set HTMLSaveOptions.Pages to a slice of 1-based page numbers, e.g. pdf.HTMLSaveOptions{Pages: []int{1, 3}}.
How do I hide a layer by default but let a viewer toggle it back on?
Call Layer.SetVisible(false) before saving. The layer remains an addressable Optional Content Group; Layer.IsVisible() reports its current state.
Does the JSON form export include field types?
Yes. Each exported field is a JSON object with type and value keys, e.g. {"subscribe": {"type": "checkbox", "value": true}}.
Do I need to call TagContent for every element, or can I nest groups directly?
Both. Page.TagContent wraps a drawing call and adds a leaf structure element. For grouping elements (tables, lists), call StructElement.AddChild on the tree root or a parent element to build the nesting first, then tag the leaf content underneath.
API Reference Summary
| Class/Method | Description |
|---|---|
Document.SaveHTML / WriteHTML | Export the document to HTML, controlled by HTMLSaveOptions |
HTMLSaveOptions | HTML export configuration: mode, DPI, page subset, resource handling |
Document.AddLayer / Layers | Create or list Optional Content Groups on the document |
Page.BeginLayer / EndLayer | Mark page content as belonging to a layer |
Layer | An Optional Content Group — name and visibility |
Document.TaggedContent | Facade for the logical structure tree of the document (Tagged PDF) |
TaggedContent | Sets document title/language and exposes the structure tree root |
Page.TagContent / TagArtifact | Bracket drawing calls in marked content and structure elements |
StructElement | A node in the logical structure tree — children, alt text, language |
Form.ExportJSON / ImportJSON | Serialize or apply AcroForm field data as JSON |
JSONExportOptions | JSON export configuration: indentation, omit-empty |