Programmatically manage PDF annotations in Flutter

Nutrient Flutter SDK offers several methods to programmatically get, add, and remove annotations. Since version 4.2.0, we’ve replaced Instant JSON with annotation model classes(opens in a new tab).

For adding and removing annotations, backward compatibility is maintained, so you can use both annotation model classes and Instant JSON. However, for retrieving annotations, the getAnnotations(opens in a new tab) method only supports annotation model classes.

To get annotations in Instant JSON format, use the PdfDocument.getAnnotationsAsJSON(opens in a new tab) or PdfDocument.getAllUnsavedAnnotations(opens in a new tab) methods.

MethodDescription
getAnnotations(int pageIndex, AnnotationType type)Gets all annotations on the given page index of the given type. List of all supported annotation types(opens in a new tab).
getUnsavedAnnotations()Gets all the unsaved annotations from the entire document.
addAnnotation(dynamic annotation)Adds the given annotation to the document.
addAnnotations(List<Annotation> annotations)Adds the given list of annotations. This does not trigger an annotationCreated event.
removeAnnotation(dynamic annotation)Removes the given annotation from the document. If the given annotation doesn’t exist, this method does nothing.

Getting all annotations

The example below shows how to get all annotations on the first page of a document:

List<Annotation> allAnnotations = await pdfDocument.getAnnotations(0, AnnotationType.all);
print(allAnnotations);

Removing all annotations

The example below shows how to remove an array of annotations from a document:

List<Annotation> allAnnotations = await pdfDocument.getAnnotations(0, AnnotationType.all);
print(allAnnotations);
// Make sure at least one annotation exists in the document.
// Remove the first annotation.
await pdfDocument.removeAnnotation(allAnnotations[0]);
print(allAnnotations);

Adding annotations

The examples below show how to programmatically create different types of annotations in your Flutter PDF documents using Nutrient.

API reference(opens in a new tab)

// Create a new link annotation with a URL.
final linkAnnotation = LinkAnnotation(
id: 'link-annotation-1',
bbox: [50.0, 700.0, 200.0, 30.0],
createdAt: '2025-01-08T12:08:57+03:00',
action: UriAction(
uri: 'https://nutrient.io',
),
pageIndex: 0,
creatorName: 'Nutrient Flutter',
);
// Add the annotation to the document.
await document.addAnnotation(linkAnnotation);

Highlight annotations

API reference(opens in a new tab)

// Create a highlight annotation.
final highlightAnnotation = HighlightAnnotation(
id: 'highlight-annotation-1',
bbox: [50.0, 450.0, 200.0, 20.0],
createdAt: '2025-01-07T16:49:18+03:00',
color: const Color(0xFFFFEB3B),
rects: [
[50.0, 450.0, 200.0, 470.0],
],
opacity: 0.5,
pageIndex: 0,
creatorName: 'Nutrient Flutter',
);
await document.addAnnotation(highlightAnnotation);

Free text annotations

API reference(opens in a new tab)

// Create a free text annotation.
final freeTextAnnotation = FreeTextAnnotation(
id: 'freetext-annotation-1',
bbox: [50.0, 650.0, 200.0, 50.0],
createdAt: '2025-01-07T16:46:01+03:00',
text: TextContent(
format: TextFormat.plain,
value: 'This is a free text annotation',
),
fontColor: const Color(0xFF000000),
fontSize: 20,
font: 'sans-serif',
pageIndex: 0,
creatorName: 'Nutrient Flutter',
backgroundColor: const Color(0xFFFF0000),
horizontalTextAlign: HorizontalTextAlignment.left,
verticalAlign: VerticalAlignment.top,
);
await document.addAnnotation(freeTextAnnotation);

Ink annotations

API reference(opens in a new tab)

// Create an ink annotation with drawing points.
final inkAnnotation = InkAnnotation(
id: 'ink-annotation-1',
bbox: [267.4, 335.1, 97.2, 10.3],
createdAt: '2025-01-06T16:36:59+03:00',
lines: InkLines(
points: [
[
[269.4, 343.4],
[308.4, 341.7],
[341.2, 339.6],
[358.8, 339.6],
[360.9, 339.2],
[362.6, 338.8],
[361.7, 337.1],
]
],
intensities: [
[1.0, 0.43, 0.64, 0.83, 0.98, 0.99, 0.97]
],
),
lineWidth: 4,
opacity: 1.0,
flags: [AnnotationFlag.print],
creatorName: 'Nutrient Flutter',
isDrawnNaturally: false,
strokeColor: const Color(0xFF2492FB),
pageIndex: 0);
await document.addAnnotation(inkAnnotation);

Note annotations

API reference(opens in a new tab)

// Create a note annotation.
final noteAnnotation = NoteAnnotation(
id: 'note-annotation-1',
bbox: [400.0, 450.0, 32.0, 32.0],
createdAt: '2025-01-07T16:49:18+03:00',
text: TextContent(value: 'This is a note', format: TextFormat.plain),
color: const Color(0xFFFF9800),
pageIndex: 0,
creatorName: 'Nutrient Flutter',
);
await document.addAnnotation(noteAnnotation);

Stamp annotations

API reference(opens in a new tab)

// Create a stamp annotation
final stampAnnotation = StampAnnotation(
id: 'stamp-annotation-1',
bbox: [50.0, 650.0, 50.0, 50.0],
stampType: StampType.approved,
pageIndex: 0);
await document.addAnnotation(stampAnnotation);

Image annotations

API reference(opens in a new tab)

// Example of a square annotation.
final imageAnnotation = ImageAnnotation(
id: 'image-annotation-1',
bbox: [300.0, 750.0, 100.0, 100.0],
createdAt: '2025-01-08T12:08:57+03:00',
imageAttachmentId:
'303c4baa3d6adfcb12cd71e7060d6714850fa9c5404270fde637e43606352580',
pageIndex: 0,
creatorName: 'Nutrient Flutter',
attachment: const AnnotationAttachment(
id: '303c4baa3d6adfcb12cd71e7060d6714850fa9c5404270fde637e43606352580',
contentType: 'image/jpeg',
binary:
'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',
),
)
await document.addAnnotation(imageAnnotation);

Adding multiple annotations

For better performance, add multiple annotations in a single operation:

final annotations = [
noteAnnotation,
highlightAnnotation,
inkAnnotation,
];
await document.addAnnotations(annotations);

This won’t trigger any annotationsCreated events. If you need to listen to these events, add each annotation separately using the addAnnotation(opens in a new tab) method.