PDF Annotations
PDF Annotations
Page.annotations exposes an AnnotationCollection — a mutable, sequence-like view over every annotation on a page. Each entry is an Annotation (or the MarkupAnnotation / LinkAnnotation subclasses), and subtype-specific data such as quad points, ink lists, or colors is read and written through get_property() / set_property() rather than dedicated attributes.
Adding Annotations
AnnotationCollection.add(subtype, rect, contents, title, appearance_normal, properties) creates a new annotation and appends it to the page. subtype accepts either a plain string ("Text", "Square", "Highlight") or an AnnotationType enum member.
import aspose_pdf
from aspose_pdf import Document, AnnotationType
doc = Document()
doc.pages.add()
page = doc.pages[0]
# Plain string subtype
page.annotations.add("Text", (100, 100, 200, 200), "Hello")
# AnnotationType enum, with subtype-specific properties
page.annotations.add(
AnnotationType.POLYGON,
(0, 0, 10, 10),
"",
properties={"Vertices": [0, 0, 10, 0, 5, 10]},
)Reading and Updating Properties
get_property(name, default) reads a subtype-specific value; set_property(name, value) writes one, and setting a property to None removes it from the annotation’s properties dict.
doc = Document()
doc.pages.add()
page = doc.pages[0]
ann = page.annotations.add(
"Square", (0, 0, 50, 50), "x", properties={"C": [1, 0, 0]},
)
ann.set_property("IC", [0, 0, 1])
print(page.annotations[0].get_property("IC")) # [0, 0, 1]
ann.set_property("C", None) # removes the "C" entry entirely
print("C" in page.annotations[0].properties) # FalseNaming Annotations with AnnotationName
PDF names (e.g. a Stamp annotation’s Name entry) are marked distinctly from plain strings using AnnotationName, a str subclass from aspose_pdf.engine.cos. A value stored this way still compares equal to an ordinary string.
from aspose_pdf.engine.cos import AnnotationName
doc = Document()
doc.pages.add()
page = doc.pages[0]
page.annotations.add(
"Stamp", (10, 10, 110, 60), "",
properties={"Name": AnnotationName("Approved")},
)Inserting, Deleting, and Clearing
insert(index, subtype, rect, contents, title, appearance_normal, properties) places a new annotation at a specific position; delete(index) removes one by index (raising IndexError for an out-of-range index); clear() removes all annotations from the page.
doc = Document()
doc.pages.add()
page = doc.pages[0]
page.annotations.add("Text", (0, 0, 100, 100), "A")
page.annotations.add("Text", (200, 200, 300, 300), "C")
page.annotations.insert(1, "Text", (100, 100, 200, 200), "B")
# order is now: A, B, C
page.annotations.delete(1) # removes "B"
page.annotations.clear() # removes everything remainingGenerating Annotation Appearances
Annotation.generate_appearance(force) builds the /AP /N appearance stream for one annotation and returns True when a renderer for that subtype exists; AnnotationCollection.generate_appearances(force) does the same for every annotation on the page in one call and returns the count of annotations that were actually generated (unsupported subtypes are skipped).
doc = Document()
doc.pages.add()
page = doc.pages[0]
page.annotations.add("Square", (0, 0, 50, 50), "")
page.annotations.add("Circle", (60, 0, 110, 50), "")
page.annotations.add("Text", (0, 60, 20, 80), "") # unsupported subtype -> skipped
generated = page.annotations.generate_appearances()
print(generated) # 2Annotation Subtypes and Flags
AnnotationType enumerates the standard PDF 32000-1:2008 (Table 169) subtype names: TEXT, LINK, FREE_TEXT, LINE, SQUARE, CIRCLE, POLYGON, POLY_LINE, HIGHLIGHT, UNDERLINE, SQUIGGLY, STRIKE_OUT, STAMP, CARET, INK, POPUP, FILE_ATTACHMENT, SOUND, MOVIE, WIDGET, SCREEN, PRINTER_MARK, TRAP_NET, WATERMARK, and REDACT.
AnnotationFlags is an IntFlag covering annotation display/interaction behavior: DEFAULT, INVISIBLE, HIDDEN, PRINT, NO_ZOOM, NO_ROTATE, NO_VIEW, READ_ONLY, LOCKED, and TOGGLE_NO_VIEW.
Prerelease: 3D Annotations
PDF3DAnnotation, PDF3DArtwork, PDF3DContent, and PDF3DView model 3D artwork attached to a page — a PDF3DAnnotation has a rect: Rectangle, an artwork: PDF3DArtwork, and an optional background_color: Color. PDF3DArtwork.add_view() registers a PDF3DView, each carrying a render_mode (PDF3DRenderMode: SOLID, WIREFRAME, TRANSPARENT) and a lighting_scheme (PDF3DLightingScheme: HEADLAMP, WHITE, GRAY, DARK, CUSTOM). The library’s own docstring marks PDF3DAnnotation as a “minimal annotation wrapper for prerelease imports” — treat this surface as early-stage rather than a fully worked-out 3D authoring API.
Tips and Best Practices
- Prefer
AnnotationTypeenum members over raw subtype strings when the value also needs to be compared or branched on elsewhere in your code. - Call
set_property(name, None)to remove a property outright rather than leaving a stale value in place — the entry disappears frompropertiescompletely. - Batch appearance generation with
AnnotationCollection.generate_appearances()instead of loopinggenerate_appearance()per annotation; it returns the actual count generated so you can detect skipped/unsupported subtypes. delete()and indexing intopage.annotationsare both 0-based; validate an index before callingdelete()if it comes from user input, since an out-of-range index raisesIndexError.- Wrap PDF name values (like a
Stamp’sName) inAnnotationNameso they round-trip as PDF names rather than plain text strings.
Common Issues
| Issue | Cause | Fix |
|---|---|---|
generate_appearances() returns fewer than the number of annotations added | One or more subtypes have no built-in appearance renderer | Check the return count against len(page.annotations); unsupported subtypes are silently skipped, not errored |
delete(index) raises IndexError | Index is negative or beyond the current annotation count | Check len(page.annotations) before calling delete() |
A property set with set_property() doesn’t appear after reload | Property was set to None, which deletes it instead of storing it | Use a real value, not None, when the property should persist |
| Inserted annotation ends up in the wrong position | insert(index, ...) index counted from the pre-insert collection state | Re-check indices after each insert() call in a loop |
FAQ
How do I add a plain text comment annotation?
Call page.annotations.add("Text", (x0, y0, x1, y1), "comment text"). The four-number tuple is the annotation’s rectangle on the page.
What’s the difference between Annotation, MarkupAnnotation, and LinkAnnotation?
Annotation is the live view returned for any annotation on a page. MarkupAnnotation is the base for markup-style subtypes (highlights, text notes, shapes) and LinkAnnotation is kept for link-style annotations; both currently expose the same method/property surface as Annotation.
Can I remove a single property without deleting the whole annotation?
Yes — call annotation.set_property(name, None); the annotation itself is untouched, only that one entry is removed from properties.
Does AnnotationCollection.generate_appearances() fail if a subtype isn’t supported?
No. It skips subtypes without a built-in appearance renderer and returns the count of annotations it actually generated an appearance for.
Are the 3D annotation classes production-ready?
PDF3DAnnotation and related types are documented as a minimal wrapper for prerelease imports — verify behavior against your target PDF viewer before relying on them for production 3D content.
API Reference Summary
| Class/Method | Description |
|---|---|
AnnotationCollection.add | Create and append a new annotation to a page |
AnnotationCollection.insert | Create and insert a new annotation at a specific index |
AnnotationCollection.delete | Remove an annotation by index (raises IndexError if out of range) |
AnnotationCollection.clear | Remove every annotation from the page |
AnnotationCollection.generate_appearances | Generate /AP /N appearance streams for every supported annotation on the page |
Annotation.get_property / set_property | Read or write a subtype-specific property value |
Annotation.update_properties | Recompute derived state after direct property edits |
Annotation.generate_appearance | Generate the /AP /N appearance stream for a single annotation |
AnnotationType | Enum of standard PDF annotation subtype names |
AnnotationFlags | IntFlag of annotation display/interaction behavior |
AnnotationName | str subclass marking a value to serialize as a PDF name |
PDF3DAnnotation / PDF3DArtwork / PDF3DContent / PDF3DView | Prerelease 3D annotation and artwork model |
PDF3DRenderMode / PDF3DLightingScheme | Enums for 3D view render mode and lighting scheme |