Annotations and Forms
Annotations and Forms
Aspose.PDF FOSS for .NET gives you full read/write access to PDF annotations
and interactive AcroForm fields. The primary entry point for annotations is
Page.Annotations (an AnnotationCollection), while form fields are accessed
through Document.Form. Both subsystems work entirely in-memory and require no
license key.
Adding annotations
AnnotationCollection exposes typed helper methods for every standard
annotation kind. Each method accepts a Rectangle defining the annotation
position on the page plus type-specific parameters.
using var doc = Document.Open(pdfBytes);
var page = doc.Pages[1];
// Text (sticky-note) annotation
page.Annotations.AddTextAnnotation(
new Rectangle(72, 720, 200, 740),
contents: "Review this paragraph",
title: "Editor",
open: true);
// Highlight annotation
page.Annotations.AddHighlightAnnotation(
new Rectangle(72, 680, 300, 700),
quadPoints: null,
color: new double[] { 1, 1, 0 });
// Free-text annotation (rendered directly on the page)
page.Annotations.AddFreeTextAnnotation(
new Rectangle(72, 640, 350, 660),
contents: "Inline note",
fontName: "Helvetica",
fontSize: 10,
color: new double[] { 0, 0, 0 });
using var ms = new MemoryStream();
doc.Save(ms);Link annotations and actions
Links combine a clickable rectangle with a PdfAction. The library supports
URI, GoTo, JavaScript, Named, and Launch actions.
using var doc = Document.Open(pdfBytes);
var page = doc.Pages[1];
// URI link
var uriAction = PdfAction.CreateUri("https://aspose.com");
page.Annotations.AddLinkAnnotation(
new Rectangle(50, 700, 200, 720), uriAction);
// GoTo link (jump to page 3)
page.Annotations.AddLinkAnnotation(
new Rectangle(50, 660, 200, 680),
destinationPage: 3,
destRect: new Rectangle(0, 0, 612, 792));
// JavaScript link
var jsAction = PdfAction.CreateJavaScript("app.alert('Hello');");
page.Annotations.AddLinkAnnotation(
new Rectangle(50, 620, 200, 640), jsAction);
doc.Save("links.pdf");To read a link back after opening a saved PDF, cast the annotation to
LinkAnnotation and inspect its Uri property or resolve the action
dictionary via PdfAction.Create.
Markup and shape annotations
Markup annotations (highlight, underline, strikeout) mark existing text. Shape annotations (square, circle, line, ink) draw geometry on the page.
var page = doc.Pages[1];
// Underline
page.Annotations.AddUnderlineAnnotation(
new Rectangle(72, 600, 300, 620),
quadPoints: null,
color: new double[] { 1, 0, 0 });
// Square
page.Annotations.AddSquareAnnotation(
new Rectangle(72, 540, 200, 580),
borderColor: new double[] { 0, 0, 1 },
fillColor: null,
lineWidth: 1.5);
// Line
page.Annotations.AddLineAnnotation(
new Rectangle(72, 500, 300, 520),
x1: 72, y1: 510, x2: 300, y2: 510,
color: new double[] { 0, 0.5, 0 },
lineWidth: 2);
// Ink (freehand)
page.Annotations.AddInkAnnotation(
new Rectangle(72, 440, 200, 480),
inkPaths: new[] { new double[] { 80, 450, 120, 470, 160, 450 } },
color: new double[] { 0.5, 0, 0.5 },
lineWidth: 1);Stamp annotations
Stamp annotations overlay an image or predefined icon on a page.
var stamp = new StampAnnotation(doc);
// Configure stamp properties, then add to page
page.Annotations.Add(stamp);Flattening annotations
Call Flatten() on any annotation to burn its visual appearance into the page
content stream and remove it from the interactive annotation list.
foreach (var annot in doc.Pages[1].Annotations)
{
annot.Flatten();
}The visitor pattern with AnnotationSelector
AnnotationSelector implements the visitor pattern so you can filter
annotations by type without manual casting.
var selector = new AnnotationSelector();
doc.Pages[1].Accept(selector);
// selector.Selected now contains all annotations on page 1
foreach (var annot in selector.Selected)
{
// Process each annotation by type
}Pass a typed annotation instance to the constructor to filter for that type only:
var linkFilter = new AnnotationSelector(new LinkAnnotation(page, Rectangle.Empty));
page.Accept(linkFilter);
// linkFilter.Selected contains only LinkAnnotation instancesInteractive form fields
Access AcroForm fields through Document.Form. The Form class exposes
field-level read/write operations and supports JSON export.
using var doc = Document.Open(pdfBytes);
// Enumerate all fields
foreach (var field in doc.Form.Fields)
{
Console.WriteLine($"{field.FullName}: {field.Value}");
}Field subclasses include TextBoxField, CheckboxField, RadioButtonField,
ComboBoxField, ListBoxField, ChoiceField, and SignatureField.
Exporting form data to JSON
WidgetAnnotation provides ExportToJson overloads for serializing field data
to a stream or file path. An optional ExportFieldsToJsonOptions parameter
controls output formatting.
using var doc = Document.Open(pdfBytes);
var widget = (WidgetAnnotation)doc.Pages[1].Annotations[1];
using var jsonStream = new MemoryStream();
widget.ExportToJson(jsonStream);Tips and Best Practices
- Always specify explicit
Rectanglecoordinates in PDF user-space units (1/72 inch). - Use
AddLinkAnnotationwith aPdfActionfor maximum flexibility — URI, GoTo, JavaScript, and Named actions are all supported. - Call
Flatten()before distributing a PDF if you want annotations to appear in non-interactive viewers. - Access form fields via
Document.Form.Fieldsrather than iterating page annotations — the form collection handles cross-page field grouping. - Save and reopen the document to verify annotation round-trip fidelity, especially for custom actions.
Common Issues
| Issue | Cause | Fix |
|---|---|---|
| Annotation not visible after save | Rectangle has zero area or is outside page bounds | Verify coordinates fall within the page MediaBox |
LinkAnnotation.Uri returns null | Link uses a GoTo or JavaScript action, not a URI action | Resolve the action dictionary via PdfAction.Create and check ActionType |
| Form field value is empty string | Field exists but has no /V entry | Check field.Value is not null before processing |
Flatten() throws | Annotation has no /P (page) reference | Ensure the annotation was added through Page.Annotations |
FAQ
How do I add a hyperlink to a PDF page?
Use page.Annotations.AddLinkAnnotation(rect, PdfAction.CreateUri(url)) to
create a clickable URI link at the specified rectangle.
Can I read form field values from an existing PDF?
Yes. Open the document with Document.Open, then iterate Document.Form.Fields
and read the Value property on each Field.
What annotation types does the library support?
The library supports text, free-text, link, highlight, underline, strikeout,
square, circle, line, ink, stamp, caret, file-attachment, sound, polygon,
polyline, widget, watermark, and 3D annotations. All types are available through
AnnotationCollection helper methods or direct construction.
How do I filter annotations by type?
Use AnnotationSelector with a typed template annotation. Call page.Accept(selector)
and inspect selector.Selected for matching annotations.
Can I flatten only specific annotations?
Yes. Call Flatten() on individual Annotation instances rather than iterating
the entire collection.
API Reference Summary
| Class / Method | Description |
|---|---|
AnnotationCollection | Typed collection on each Page; provides Add* helpers for all annotation types |
AnnotationCollection.AddTextAnnotation | Add a sticky-note annotation |
AnnotationCollection.AddLinkAnnotation | Add a link with URI, page destination, or custom action |
AnnotationCollection.AddHighlightAnnotation | Add a text-highlight annotation |
AnnotationCollection.AddInkAnnotation | Add a freehand-drawing annotation |
AnnotationCollection.AddSquareAnnotation | Add a rectangle shape annotation |
AnnotationCollection.AddCircleAnnotation | Add an ellipse shape annotation |
AnnotationCollection.AddLineAnnotation | Add a line annotation |
Annotation.Flatten | Burn annotation appearance into page content |
Annotation.Accept | Dispatch to typed AnnotationSelector.Visit overload |
AnnotationSelector | Visitor that collects annotations by type |
LinkAnnotation | Annotation subclass carrying a URI or action |
TextAnnotation | Sticky-note annotation |
InkAnnotation | Freehand-drawing annotation with stroke paths |
StampAnnotation | Image or icon overlay annotation |
WidgetAnnotation.ExportToJson | Serialize form-field data to JSON |
Form | AcroForm facade; enumerates and manipulates fields |
Field | Base class for form fields (TextBoxField, CheckboxField, etc.) |
CheckboxField | Check-box form field |
TextBoxField | Single/multi-line text input field |
ComboBoxField | Drop-down choice field |
RadioButtonField | Radio-button group field |
AnnotationType | Enumeration of annotation kinds |
PdfAction.CreateUri | Factory for URI link actions |
PdfAction.CreateJavaScript | Factory for JavaScript actions |