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)  # False

Naming 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 remaining

Generating 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)  # 2

Annotation 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 AnnotationType enum 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 from properties completely.
  • Batch appearance generation with AnnotationCollection.generate_appearances() instead of looping generate_appearance() per annotation; it returns the actual count generated so you can detect skipped/unsupported subtypes.
  • delete() and indexing into page.annotations are both 0-based; validate an index before calling delete() if it comes from user input, since an out-of-range index raises IndexError.
  • Wrap PDF name values (like a Stamp’s Name) in AnnotationName so they round-trip as PDF names rather than plain text strings.

Common Issues

IssueCauseFix
generate_appearances() returns fewer than the number of annotations addedOne or more subtypes have no built-in appearance rendererCheck the return count against len(page.annotations); unsupported subtypes are silently skipped, not errored
delete(index) raises IndexErrorIndex is negative or beyond the current annotation countCheck len(page.annotations) before calling delete()
A property set with set_property() doesn’t appear after reloadProperty was set to None, which deletes it instead of storing itUse a real value, not None, when the property should persist
Inserted annotation ends up in the wrong positioninsert(index, ...) index counted from the pre-insert collection stateRe-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/MethodDescription
AnnotationCollection.addCreate and append a new annotation to a page
AnnotationCollection.insertCreate and insert a new annotation at a specific index
AnnotationCollection.deleteRemove an annotation by index (raises IndexError if out of range)
AnnotationCollection.clearRemove every annotation from the page
AnnotationCollection.generate_appearancesGenerate /AP /N appearance streams for every supported annotation on the page
Annotation.get_property / set_propertyRead or write a subtype-specific property value
Annotation.update_propertiesRecompute derived state after direct property edits
Annotation.generate_appearanceGenerate the /AP /N appearance stream for a single annotation
AnnotationTypeEnum of standard PDF annotation subtype names
AnnotationFlagsIntFlag of annotation display/interaction behavior
AnnotationNamestr subclass marking a value to serialize as a PDF name
PDF3DAnnotation / PDF3DArtwork / PDF3DContent / PDF3DViewPrerelease 3D annotation and artwork model
PDF3DRenderMode / PDF3DLightingSchemeEnums for 3D view render mode and lighting scheme

See Also