How to Work with PDF Annotations in C++
Aspose.PDF FOSS for C++ represents every PDF annotation as a subclass of the
common Annotation base class, and exposes the annotations on a page through
the AnnotationCollection returned by Page::Annotations(). This guide adds
a plain text-note annotation and a styled annotation to a page with
TextAnnotation, saves the document, then reopens it to read the annotations
back and remove one. The library is integrated into a CMake project as a
subdirectory dependency — there is no package-registry install step.
Step-by-Step Guide
Step 1: Install the Package
Add the library as a CMake subdirectory and link the static library target:
add_subdirectory(aspose.pdf-foss-for-cpp)
target_link_libraries(your_app PRIVATE aspose_pdf_foss)Verify the toolchain and link step resolve correctly with a minimal program:
#include <aspose/pdf/document.hpp>
#include <iostream>
int main() {
Aspose::Pdf::Document doc;
std::cout << "Linked OK — pages: " << doc.Pages().Count() << "\n";
}A successful build that prints pages: 0 confirms the library is linked.
Step 2: Import Required Classes
#include <aspose/pdf/document.hpp>
#include <aspose/pdf/page_collection.hpp>
#include <aspose/pdf/rectangle.hpp>
#include <aspose/pdf/color.hpp>
#include <aspose/pdf/annotations/annotation.hpp>
#include <aspose/pdf/annotations/annotation_collection.hpp>
#include <aspose/pdf/annotations/annotation_type.hpp>
#include <aspose/pdf/annotations/annotation_flags.hpp>
#include <aspose/pdf/annotations/border.hpp>
#include <aspose/pdf/annotations/border_style.hpp>
#include <aspose/pdf/annotations/text_annotation.hpp>
using namespace Aspose::Pdf;
using namespace Aspose::Pdf::Annotations;Step 3: Create a Document and Add a Page
Create a new document and add a page to it. PageCollection::Add() returns
the newly added Page:
Document doc;
Page page = doc.Pages().Add();Step 4: Add a Text Annotation to the Page
TextAnnotation renders as a sticky-note style comment. Construct it from
the owning Document, set its position with Rect() and its message with
Contents(), then add it to the page’s AnnotationCollection:
TextAnnotation note{doc};
note.Rect(Rectangle(100.0, 700.0, 200.0, 720.0, false));
note.Contents("Reviewed and approved.");
page.Annotations().Add(note);Step 5: Style a Second Annotation with Color, a Border, and Flags
Annotation also exposes Color(), Border(), and Flags(). Flags()
takes an AnnotationFlags bit field — combine values with bitwise OR to
set more than one flag at a time:
TextAnnotation flagged{doc};
flagged.Rect(Rectangle(100.0, 600.0, 300.0, 650.0, false));
flagged.Contents("Needs follow-up");
flagged.Color(Color::FromRgb(220, 20, 20));
flagged.Flags(AnnotationFlags::Print | AnnotationFlags::ReadOnly);
flagged.Border().Width(2);
flagged.Border().Style(BorderStyle::Dashed);
page.Annotations().Add(flagged);Step 6: Save the Document
Nothing is written to disk until Save() runs:
doc.Save("annotated.pdf");Step 7: Reopen the PDF and Read Its Annotations
Reopen the saved file and read its first page’s AnnotationCollection back.
AnnotationCollection is 0-based, and Count() reports how many annotations
the page holds:
Document reopened("annotated.pdf");
auto& annots = reopened.Pages()[1].Annotations();
std::cout << "Annotation count: " << annots.Count() << "\n";
for (int i = 0; i < annots.Count(); ++i) {
const auto& a = annots[i];
if (a.AnnotationType() == AnnotationType::Text) {
std::cout << "Text annotation: " << a.Contents() << "\n";
}
}Step 8: Remove an Annotation and Re-save
AnnotationCollection::Delete(index) removes an annotation by its 0-based
position. Delete the first annotation and save the result to a new file:
annots.Delete(0);
reopened.Save("annotated-cleaned.pdf");Common Issues and Fixes
Nothing changes in the saved PDF after calling Annotations().Add()
Two things commonly go wrong here. First, PageCollection is 1-based
(doc.Pages()[1] is the first page) while AnnotationCollection is 0-based
(annots[0] is the first annotation) — mixing up the two indexing schemes
leads to operating on the wrong object. Second, confirm Document::Save()
actually runs after the annotation is added; nothing is written to disk
until then.
AnnotationCollection indexing or Delete(index) throws std::out_of_range
Valid indices run from 0 to Count() - 1. Passing a negative index or an
index equal to or greater than Count() throws std::out_of_range by
design. Call Count() first to bound any loop or lookup.
Remove() returns false the second time I call it on the same annotation
This is not an error. Remove() reports whether the annotation was found
and removed as a bool; calling it again on an annotation that is already
gone is a no-op that returns false. Check the return value instead of
assuming Remove() always succeeds.
Setting a new AnnotationFlags value clears flags I had already set
Flags(value) replaces the whole flag set — it does not merge with the
previous value. To add or clear a single flag, read the current flags first
and combine them with bitwise operators, for example
a.Flags(a.Flags() | AnnotationFlags::Print) to add a flag, or
a.Flags(a.Flags() & ~AnnotationFlags::Print) to clear one flag while
leaving the rest untouched.
Frequently Asked Questions
What is the relationship between Annotation, TextAnnotation, and the other annotation subtypes?
Annotation is the common base class. TextAnnotation and the other
concrete annotation types each specialize it for one PDF annotation
subtype, while sharing the base class’s Rect(), Contents(), Color(),
Flags(), and Border() accessors.
Are annotations scoped to the whole document or to one page?
Each page has its own AnnotationCollection, returned by that page’s
Annotations() method. Annotations are always scoped to the page they were
added to, not to the document as a whole.
How do I count how many annotations are on a page?
Call Count() on the AnnotationCollection returned by
Page::Annotations().
Can an annotation be both printable and read-only at the same time?
Yes. AnnotationFlags is a bit field, so combine values with bitwise OR,
for example AnnotationFlags::Print | AnnotationFlags::ReadOnly.
Does deleting an annotation from AnnotationCollection remove it from the PDF file on disk?
Only after Document::Save() runs. Delete(), Remove(), and Clear()
only modify the in-memory collection — the PDF on disk is unchanged until
the document is saved.