Programmatically manage PDF annotations in Flutter
Nutrient Flutter SDK provides methods to get, add, and remove annotations programmatically using annotation model classes(opens in a new tab). Access these methods from the loaded document’s annotation manager (controller.document.annotations), which is available from the NutrientDocumentView onControllerReady callback.
The getAnnotations(opens in a new tab) method returns typed annotation models. To get annotations as an Instant JSON string instead, use getAnnotationsJson(pageIndex, type) or getUnsavedAnnotationsJson().
Use these annotation manager methods to retrieve, add, and remove annotations:
| Method | Description |
|---|---|
getAnnotations(int pageIndex, [AnnotationType type = AnnotationType.all]) | Gets all annotations on the given page index, optionally filtered by type. Defaults to all supported annotation types(opens in a new tab). |
getUnsavedAnnotations() | Gets all unsaved annotations from the entire document. |
addAnnotation(Annotation annotation) | Adds the given annotation to the document. |
removeAnnotation(int pageIndex, String annotationId) | Removes the annotation with the given ID from the given page. |
Get all annotations
The following example gets all annotations on the first page of a document:
List<Annotation> allAnnotations = await controller.document.annotations.getAnnotations(0, AnnotationType.all);print(allAnnotations);Remove all annotations
The following example removes an array of annotations from a document:
List<Annotation> allAnnotations = await controller.document.annotations.getAnnotations(0, AnnotationType.all);print(allAnnotations);
// Make sure at least one annotation exists in the document.// Remove the first annotation.await controller.document.annotations.removeAnnotation(0, allAnnotations[0].id!);print(allAnnotations);Add annotations
The following examples show how to create different types of annotations in Flutter PDF documents using Nutrient.
Link annotations
Refer to the link annotation API reference(opens in a new tab) for available properties. The following example creates a link annotation:
// 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 controller.document.annotations.addAnnotation(linkAnnotation);Highlight annotations
Refer to the highlight annotation API reference(opens in a new tab) for available properties. The following example creates a highlight annotation:
// 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 controller.document.annotations.addAnnotation(highlightAnnotation);Free text annotations
Refer to the free text annotation API reference(opens in a new tab) for available properties. The following example creates a free text annotation:
// 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 controller.document.annotations.addAnnotation(freeTextAnnotation);Ink annotations
Refer to the ink annotation API reference(opens in a new tab) for available properties. The following example creates an ink annotation:
// 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 controller.document.annotations.addAnnotation(inkAnnotation);Note annotations
Refer to the note annotation API reference(opens in a new tab) for available properties. The following example creates a note annotation:
// 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 controller.document.annotations.addAnnotation(noteAnnotation);Stamp annotations
Refer to the stamp annotation API reference(opens in a new tab) for available properties. The following example creates a stamp annotation:
// Create a stamp annotationfinal stampAnnotation = StampAnnotation( id: 'stamp-annotation-1', bbox: [50.0, 650.0, 50.0, 50.0], stampType: StampType.approved, pageIndex: 0);
await controller.document.annotations.addAnnotation(stampAnnotation);Image annotations
Refer to the image annotation API reference(opens in a new tab) for available properties. The following example creates an image annotation:
// 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 controller.document.annotations.addAnnotation(imageAnnotation);Add multiple annotations
Add multiple annotations by iterating over a list:
final annotations = [ noteAnnotation, highlightAnnotation, inkAnnotation,];
for (final annotation in annotations) { await controller.document.annotations.addAnnotation(annotation);}