Skip to content
Set Doc Info Metadata

Set Doc Info Metadata

There are two ways to set the /Info dictionary, and they operate at different scopes. The package-level setters such as model.SetPdfAuthor change a default applied to every writer created afterwards. PdfWriter.SetDocInfo replaces the whole dictionary on one writer.

ApproachScopeUse it when
model.SetPdfAuthor, SetPdfTitle, SetPdfProducer, …Process-wide default, read when a writer is constructedEvery document your program writes should carry the same producer or author.
PdfWriter.SetDocInfo(info)One writer, overwrites the entire dictionaryPer-document values, or you need custom keys.

The globals are guarded by a mutex and only read at NewPdfWriter time, so they have to be set before you build the writer. SetDocInfo overwrites whatever the globals put there.

Doing it

pdfWriter, err := pdfReader.ToWriter(&model.ReaderToWriterOpts{SkipInfo: true})
if err != nil {
    return err
}

info := &model.PdfInfo{
    Author:  core.MakeString("UniPDF Tester"),
    Subject: core.MakeString("PDF with a custom information dictionary"),
}
if err := info.AddCustomInfo("custom_info", "This is an optional custom info"); err != nil {
    return err
}

pdfWriter.SetDocInfo(info)
return pdfWriter.WriteToFile("output.pdf")

SkipInfo: true stops ToWriter from copying the source document’s /Info over the writer’s defaults. Without it, the input file’s metadata comes along and you are editing that rather than starting clean.

The string fields are *core.PdfObjectString, built with core.MakeString. CreationDate and ModifiedDate are *model.PdfDate, from model.NewPdfDateFromTime. Trapped is a *core.PdfObjectName.

AddCustomInfo returns an error if the name collides with one of the nine standard keys, since those belong in the typed fields. It is the only way to get a non-standard key into the dictionary.

Limitations

SetDocInfo is a replacement, not a merge. Anything you leave nil on the PdfInfo is absent from the output, including values the globals had supplied. To edit rather than replace, read the existing dictionary with PdfReader.GetPdfInfo first, modify it, and pass that back.

Writing /Info does not touch the XMP packet. If the document also carries XMP, the two will now disagree, which is a PDF/A conformance failure. Use xmputil.Document.SetPdfInfo to push the same values into the pdf: XMP model.

PdfAppender.SetDocInfo is the equivalent when you are appending an incremental update instead of writing a fresh file.

Run the example

The example writes two files from one input. gen_pdf_default_author.pdf gets the author set through model.SetPdfAuthor before the writer exists; gen_pdf_custom_info.pdf gets a PdfInfo with its own author, subject and one custom key. Note that customPdfWriter := defaultPdfWriter copies a pointer, not the writer, so the second SetDocInfo applies to the same writer - the example works because the first file is written before the info is replaced.

git clone https://github.com/unidoc/unipdf-examples.git
cd unipdf-examples/metadata
go run pdf_metadata_set_docinfo.go template.pdf

If this is your first time using UniPDF, follow the getting started guide to create an API key and set up your development environment.

View the full source
Last updated on