Skip to content
How to add annotations to a PDF

How to add annotations to a PDF

Build the annotation, then attach it with page.AddAnnotation. An annotation is a separate object in the page’s /Annots array, so adding one leaves the existing content stream untouched.

rectAnnotation, err := annotator.CreateRectangleAnnotation(annotator.RectangleAnnotationDef{
    X:             100,
    Y:             100,
    Width:         200,
    Height:        50,
    FillEnabled:   true,
    FillColor:     model.NewPdfColorDeviceRGB(1, 1, 0),
    BorderEnabled: true,
    BorderWidth:   2,
    BorderColor:   model.NewPdfColorDeviceRGB(0, 0, 0),
    Opacity:       0.5,
})
if err != nil {
    return err
}

page.AddAnnotation(rectAnnotation)

Two packages are involved and the choice between them is about appearance. model has a constructor per PDF subtype - NewPdfAnnotationSquare, NewPdfAnnotationCircle, NewPdfAnnotationLine, NewPdfAnnotationText and around two dozen others - and gives you the annotation data with no AP entry. The viewer then draws whatever it likes, which is why the same file can look different in Acrobat, Preview and a browser. The annotator package generates an appearance stream so it looks the same everywhere, through CreateRectangleAnnotation, CreateCircleAnnotation, CreateLineAnnotation, CreateInkAnnotation and CreateFileAttachmentAnnotation.

Those five, plus the widget appearances used by form fields, are what annotator covers. For any other subtype, use the model constructor and accept viewer-drawn appearance, or build the AP stream yourself. Sticky notes are the case where that costs nothing: viewers draw the note icon, so NewPdfAnnotationText needs no appearance stream at all.

The model constructors return a typed value that embeds *PdfAnnotation, so pass textAnnotation.PdfAnnotation to AddAnnotation. The annotator functions already return *model.PdfAnnotation and go in as they are.

annotator sets Rect from the bounding box it computes rather than from the coordinates you passed, and the three shape helpers do not agree on how. CreateCircleAnnotation applies its offset twice, putting the shape at double the coordinates you gave.

Per-type detail and the circle workaround are in the annotation guides.

Last updated on