Working with PDF Annotations

Working with PDF Annotations

Working with PDF Annotations

PDF annotations in Aspose.PDF FOSS for C++ are represented by the Annotation base class and its concrete subtypes (TextAnnotation, LinkAnnotation, HighlightAnnotation, FreeTextAnnotation, CircleAnnotation, WatermarkAnnotation, WidgetAnnotation, and others). Every page exposes its annotations through Page.Annotations(), which returns an AnnotationCollection. This guide covers adding annotations to a page, iterating and removing them, reading annotations from an existing document, attaching link actions, customizing appearance, and flattening annotations.


Adding Annotations to a Page

Create a concrete annotation instance, position it with a Rectangle, and add it to the page’s collection with AnnotationCollection.Add(). TextAnnotation represents a sticky-note style comment anchored to a point on the page:

#include <aspose/pdf/document.hpp>
#include <aspose/pdf/annotations/text_annotation.hpp>
#include <aspose/pdf/rectangle.hpp>

int main() {
    Aspose::Pdf::Document doc("input.pdf");
    auto& page = doc.Pages()[1];

    Aspose::Pdf::Annotations::TextAnnotation note(doc);
    note.Rect(Aspose::Pdf::Rectangle(100.0, 700.0, 200.0, 720.0, false));
    note.Contents("Reviewed and approved");

    page.Annotations().Add(note);
    doc.Save("annotated.pdf");
}

Annotation.Contents() / Contents(value) get and set the note text, and Annotation.Rect() / Rect(value) position the annotation on the page.


Iterating and Removing Annotations

AnnotationCollection supports counting, indexed access, membership checks, and removal by value or by index:

#include <aspose/pdf/document.hpp>

int main() {
    Aspose::Pdf::Document doc("input.pdf");
    auto& annotations = doc.Pages()[1].Annotations();

    std::cout << "Annotation count: " << annotations.Count() << "\n";

    for (int i = 0; i < annotations.Count(); ++i) {
        std::cout << "Contents: " << annotations[i].Contents() << "\n";
    }

    if (annotations.Count() > 0) {
        annotations.Delete(0);   // remove by index
    }
    annotations.Clear();         // remove everything
}

AnnotationCollection.Contains(annotation) and Remove(annotation) operate on a specific annotation reference; Delete(index) removes by position, and Delete(annotation) removes a specific annotation without needing its index. IsReadOnly() reports whether the collection can be modified.


Reading Annotations from an Existing Document

When a document is loaded, its annotations are already populated and can be inspected without adding anything. Annotation.AnnotationType() reports the subtype (AnnotationType::Text, AnnotationType::Highlight, AnnotationType::Link, AnnotationType::FreeText, AnnotationType::FileAttachment, AnnotationType::Watermark, and others):

#include <aspose/pdf/document.hpp>
#include <aspose/pdf/annotations/annotation_type.hpp>

int main() {
    Aspose::Pdf::Document doc("annotated.pdf");
    auto& annotations = doc.Pages()[1].Annotations();

    for (int i = 0; i < annotations.Count(); ++i) {
        auto& a = annotations[i];
        if (a.AnnotationType() == Aspose::Pdf::Annotations::AnnotationType::Text) {
            std::cout << "Note: " << a.Contents() << "\n";
        }
    }
}

Annotation order and subtype are preserved across a save/reload round trip, so code that indexes into Annotations() after loading a document sees the same sequence that was present when the file was written.


Link Annotations and Actions

LinkAnnotation attaches a clickable region to a page and dispatches a PdfAction when activated. NamedAction jumps to a predefined navigation target, JavascriptAction runs an ECMAScript string, and SubmitFormAction posts form data to a URL via a FileSpecification:

#include <aspose/pdf/document.hpp>
#include <aspose/pdf/annotations/link_annotation.hpp>
#include <aspose/pdf/annotations/named_action.hpp>
#include <aspose/pdf/annotations/predefined_action.hpp>
#include <aspose/pdf/rectangle.hpp>

int main() {
    Aspose::Pdf::Document doc;
    auto page = doc.Pages().Add();

    Aspose::Pdf::Annotations::LinkAnnotation link(
        page, Aspose::Pdf::Rectangle(0.0, 0.0, 100.0, 20.0, false));
    link.Action(Aspose::Pdf::Annotations::NamedAction(
        Aspose::Pdf::Annotations::PredefinedAction::LastPage));

    page.Annotations().Add(link);
    doc.Save("linked.pdf");
}

LinkAnnotation.Action(value) accepts any PdfAction subtype and clones it internally, so the annotation retains its own copy of the action. LinkAnnotation.Destination() / Destination(value) set an explicit navigation target instead of an action, and Highlighting() / Highlighting(value) control the visual feedback shown while the link is clicked.


Annotation Appearance: Border, Flags, and Color

Every Annotation exposes a Border, a bitfield of AnnotationFlags, and a Color used to render its appearance:

#include <aspose/pdf/annotations/border_style.hpp>
#include <aspose/pdf/annotations/annotation_flags.hpp>
#include <aspose/pdf/color.hpp>

// 'note' is an existing Annotation reference, e.g. from AnnotationCollection.
note.Border().Width(2);
note.Border().Style(Aspose::Pdf::Annotations::BorderStyle::Dashed);
note.Flags(Aspose::Pdf::Annotations::AnnotationFlags::Print);
note.Color(Aspose::Pdf::Color::Red());

Border.Style() accepts BorderStyle::Solid, Dashed, Beveled, Inset, or Underline. Border.Effect() additionally supports a BorderEffect::Cloudy outline with EffectIntensity() controlling how pronounced it is. AnnotationFlags is a bitfield — combine values such as Print, NoZoom, ReadOnly, and LockedContents to control how an annotation behaves in a viewer without changing its visible content.


Flattening Annotations

A single annotation can be flattened — merged into the page content and made non-interactive — by calling Annotation.Flatten() directly:

#include <aspose/pdf/document.hpp>

int main() {
    Aspose::Pdf::Document doc("annotated.pdf");
    auto& annotations = doc.Pages()[1].Annotations();
    for (int i = 0; i < annotations.Count(); ++i) {
        annotations[i].Flatten();
    }
    doc.Save("flattened.pdf");
}

For document-wide annotation operations, PdfAnnotationEditor follows the shared Facade pattern used across the API: bind a source document with BindPdf(), apply one or more annotation operations, then write the result with Save():

#include <aspose/pdf/facades/pdf_annotation_editor.hpp>

int main() {
    Aspose::Pdf::Facades::PdfAnnotationEditor editor;
    editor.BindPdf("annotated.pdf");
    editor.FlatteningAnnotations();
    editor.Save("flattened.pdf");
}

PdfAnnotationEditor.DeleteAnnotations() removes every annotation from the bound document; DeleteAnnotations(annotType) restricts removal to a single AnnotationType. ImportAnnotationsFromXfdf(xfdfFile) and ImportAnnotationsFromFdf(fdfFile) load annotation data exported from another PDF viewer.


Tips and Best Practices

  • Always add a newly constructed annotation to Page.Annotations() before calling Document.Save() — an annotation that is never added to a collection is not written to the output file.
  • Use AnnotationCollection.Contains(annotation) before calling Remove() if you are not certain the annotation is still present; Remove() returns false rather than throwing when the annotation is absent.
  • Check Annotation.AnnotationType() before casting or branching on subtype behavior when iterating annotations loaded from an untrusted or third-party PDF file.
  • Flatten annotations with Annotation.Flatten() (or PdfAnnotationEditor.FlatteningAnnotations() for the whole document) before archiving a document so that reviewers on other tools see the same appearance you authored.
  • AnnotationFlags is a bitfield — combine flags with the enum’s underlying integer values rather than assuming only one flag can be active at a time.

Common Issues

IssueCauseFix
Annotation not visible after saveThe annotation was constructed but never added to Page.Annotations()Call page.Annotations().Add(annotation) before doc.Save()
Remove() returns falseThe annotation reference passed does not match an entry currently in the collectionUse Contains() first, or remove by index with Delete(index)
Wrong annotation type after reloadCode assumed a specific subtype without checking AnnotationType()Branch on Annotation.AnnotationType() before treating the object as a specific subtype
Link action appears unset after assignmentA local PdfAction went out of scope; LinkAnnotation.Action() returns the annotation’s cloned copy, not the original objectRead the action back through link.Action() rather than holding onto the original local variable
PdfAnnotationEditor operation has no effectBindPdf() was not called, or was called with a path that does not existConfirm BindPdf() succeeds before calling FlatteningAnnotations() or DeleteAnnotations()

FAQ

How do I add a comment-style annotation to a PDF page?

Construct a TextAnnotation with the target Document, set its Rect() and Contents(), then add it to page.Annotations() before saving.

How do I find out what kind of annotation I’m looking at?

Call Annotation.AnnotationType(), which returns an AnnotationType enum value such as Text, Link, Highlight, FreeText, FileAttachment, or Watermark.

Can one annotation carry more than one flag?

Yes. AnnotationFlags is a bitfield (Default, Invisible, Hidden, Print, NoZoom, ReadOnly, LockedContents, and others), so multiple flags can be combined on a single annotation.

What is the difference between flattening one annotation and flattening a document?

Annotation.Flatten() merges a single annotation into its page’s content. PdfAnnotationEditor.FlatteningAnnotations() (optionally scoped by page range and AnnotationType via the overload that accepts start, end, and annotType) flattens across the whole bound document in one call.

How do I remove all annotations of one type from a document?

Bind the document with PdfAnnotationEditor.BindPdf(), call DeleteAnnotations(annotType) with the target AnnotationType, then Save() the result.


API Reference Summary

Class/MethodDescription
AnnotationAbstract base class for all PDF annotation subtypes
Annotation.Rect() / Rect(value)Get or set the annotation’s bounding rectangle
Annotation.Contents() / Contents(value)Get or set the annotation’s text content
Annotation.AnnotationType()Returns the AnnotationType enum value for this annotation
Annotation.Flags() / Flags(value)Get or set the AnnotationFlags bitfield
Annotation.Border() / Border(value)Get or set the annotation’s Border
Annotation.Color() / Color(value)Get or set the annotation’s display Color
Annotation.Flatten()Merges this annotation into the page content, making it non-interactive
AnnotationCollectionOrdered collection of annotations on a page, returned by Page.Annotations()
AnnotationCollection.Add(annotation) / Add(annotation, considerRotation)Adds an annotation to the collection
AnnotationCollection.Count()Returns the number of annotations in the collection
AnnotationCollection.Contains(annotation)Reports whether the collection holds the given annotation
AnnotationCollection.Remove(annotation)Removes a specific annotation; returns false if not found
AnnotationCollection.Delete(index) / Delete(annotation)Removes an annotation by index or by reference
AnnotationCollection.Clear()Removes all annotations from the collection
TextAnnotationSticky-note style annotation with Open() and Icon() (TextIcon)
LinkAnnotationClickable region dispatching a PdfAction via Action() / Action(value)
LinkAnnotation.Destination() / Destination(value)Get or set an explicit navigation target
HighlightAnnotationMarks a span of text with a highlight color
FreeTextAnnotationDisplays a text callout; configured via Justification(), DefaultAppearanceObject(), Callout()
CircleAnnotationDraws an ellipse within the annotation’s rectangle
WatermarkAnnotationOverlay annotation with an Opacity() / Opacity(value) accessor
WidgetAnnotationForm-field appearance annotation with ReadOnly(), Required(), Exportable(), DefaultAppearance()
NamedActionPredefined navigation action (PredefinedAction enum) attachable to a LinkAnnotation
JavascriptActionRuns an ECMAScript string via Script() / GetECMAScriptString()
SubmitFormActionPosts form data to a FileSpecification URL via Url() / Url(value)
BorderAnnotation border with Width(), Style() (BorderStyle), Effect() (BorderEffect)
PdfAnnotationEditorFacade for document-wide annotation import, modification, flattening, and deletion
PdfAnnotationEditor.FlatteningAnnotations()Flattens annotations across the bound document
PdfAnnotationEditor.DeleteAnnotations(annotType)Deletes all annotations of a given AnnotationType
PdfAnnotationEditor.ImportAnnotationsFromXfdf(xfdfFile)Imports annotations from an XFDF file

See Also