Skip to content
Attachments

Attachments

A PDF can carry arbitrary files inside it. Source spreadsheets alongside a report, the XML a rendered invoice came from, an image referenced in a form: the file travels with the document and is offered to the reader in a viewer’s attachments panel.

UniPDF has two ways to attach a file, and the choice determines where the attachment shows up.

ApproachWhere it livesHow the reader sees it
pdfWriter.AttachFile(file)The document’s /Names /EmbeddedFiles tree.In the viewer’s attachments panel. Not tied to any page.
annotator.CreateFileAttachmentAnnotation(def)A file attachment annotation on a page.A clickable pin or paperclip icon at a position on the page, and usually in the panel too.

Both build the same model.EmbeddedFile, so the file itself is described identically either way. Only the placement differs. Use the document-level form for supporting material that belongs to the document as a whole; use the annotation form when the attachment relates to a specific spot on a specific page. The annotation route is covered in the file attachment annotation guide.

The EmbeddedFile

emFile, err := model.NewEmbeddedFile("dummy.xml")
if err != nil {
    return err
}
emFile.Name = "invoice-source.xml"
emFile.Description = "Source XML for the rendered invoice"
emFile.Relationship = model.RelationshipData

NewEmbeddedFile reads the file, sniffs its MIME type, and computes an MD5 checksum. NewEmbeddedFileFromContent does the same from a byte slice you already have.

Name is the display name and the key the file gets in the name tree, so it needs to be unique within the document. NewEmbeddedFile defaults it to the base name of the path, which means attaching the same file more than once requires overwriting it. NewEmbeddedFileFromContent defaults it to the literal string attachment.

Relationship records why the file is there, and maps onto the PDF AFRelationship values: RelationshipSource, RelationshipData, RelationshipAlternative, RelationshipSupplement and RelationshipUnspecified. It’s metadata, and the zero value is RelationshipSource, so a struct you never set writes Source.

Content is always Flate compressed on the way in. CreationTime and ModTime default to now when left zero.

Where to look

GuideCovers
Attaching a fileAttachFile, the two EmbeddedFile constructors, and which fields actually reach the output.
Retrieving attached filesGetAttachedFiles, and what the returned metadata does and does not round-trip.
Last updated on