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 callingDocument.Save()— an annotation that is never added to a collection is not written to the output file. - Use
AnnotationCollection.Contains(annotation)before callingRemove()if you are not certain the annotation is still present;Remove()returnsfalserather 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()(orPdfAnnotationEditor.FlatteningAnnotations()for the whole document) before archiving a document so that reviewers on other tools see the same appearance you authored. AnnotationFlagsis 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
| Issue | Cause | Fix |
|---|---|---|
| Annotation not visible after save | The annotation was constructed but never added to Page.Annotations() | Call page.Annotations().Add(annotation) before doc.Save() |
Remove() returns false | The annotation reference passed does not match an entry currently in the collection | Use Contains() first, or remove by index with Delete(index) |
| Wrong annotation type after reload | Code assumed a specific subtype without checking AnnotationType() | Branch on Annotation.AnnotationType() before treating the object as a specific subtype |
| Link action appears unset after assignment | A local PdfAction went out of scope; LinkAnnotation.Action() returns the annotation’s cloned copy, not the original object | Read the action back through link.Action() rather than holding onto the original local variable |
PdfAnnotationEditor operation has no effect | BindPdf() was not called, or was called with a path that does not exist | Confirm 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/Method | Description |
|---|---|
Annotation | Abstract 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 |
AnnotationCollection | Ordered 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 |
TextAnnotation | Sticky-note style annotation with Open() and Icon() (TextIcon) |
LinkAnnotation | Clickable region dispatching a PdfAction via Action() / Action(value) |
LinkAnnotation.Destination() / Destination(value) | Get or set an explicit navigation target |
HighlightAnnotation | Marks a span of text with a highlight color |
FreeTextAnnotation | Displays a text callout; configured via Justification(), DefaultAppearanceObject(), Callout() |
CircleAnnotation | Draws an ellipse within the annotation’s rectangle |
WatermarkAnnotation | Overlay annotation with an Opacity() / Opacity(value) accessor |
WidgetAnnotation | Form-field appearance annotation with ReadOnly(), Required(), Exportable(), DefaultAppearance() |
NamedAction | Predefined navigation action (PredefinedAction enum) attachable to a LinkAnnotation |
JavascriptAction | Runs an ECMAScript string via Script() / GetECMAScriptString() |
SubmitFormAction | Posts form data to a FileSpecification URL via Url() / Url(value) |
Border | Annotation border with Width(), Style() (BorderStyle), Effect() (BorderEffect) |
PdfAnnotationEditor | Facade 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 |