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.
Method | Description |
---|---|
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.
Link annotations
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 annotationfinal 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.