Skip to content
ComPDF
DemoFAQ
New Release

Open-Source PDF SDK & AI Document Processing

Get the full self-hosted SDK and AI document processing on GitHub. One-click deploy to quickly build your document workflows.

Guides

Annotations

The ComPDF Flutter SDK supports annotation callbacks and listener events for annotation creation, style editing, action interception, selection, and iOS Pencil drawing.

Available Callbacks and Events

TypeNameTrigger TimingPayload
Reader callbackonAnnotationCreationPreparedCallbackpreparing to create a signature, stamp, link, image, or Note annotationCPDFAnnotationType annotationType, CPDFAnnotation? annotation
Reader callbackonAnnotationStyleDialogDismissedCallbackAnnotation style dialog is dismissedCPDFAnnotationType type
Reader callbackonInterceptAnnotationActionCallbackExisting Note or Link annotation is tapped and interception is enabledCPDFAnnotation annotation
Listener eventCPDFEvent.annotationsCreatedAnnotation is createdCPDFAnnotation
Listener eventCPDFEvent.annotationsSelectedAnnotation is selectedCPDFAnnotation
Listener eventCPDFEvent.annotationsDeselectedAnnotation is deselectedCPDFAnnotation?
Listener eventCPDFEvent.pencilDrawingCompletediOS Pencil drawing is completedMap<String, dynamic> with type and pageIndex
Listener eventCPDFEvent.pencilDrawingDiscardediOS Pencil drawing is discardedMap<String, dynamic> with type and pageIndex

Annotation Creation Prepared Callback

onAnnotationCreationPreparedCallback is triggered when the user clicks signature, stamp, link, or image tools, or calls controller.setAnnotationMode() to enter creation mode. It is also used by the custom Note creation flow when autoShowNoteEditDialog is disabled.

To replace the default picker dialogs, disable the corresponding options in CPDFConfiguration:

dart
CPDFConfiguration(
  annotationsConfig: const CPDFAnnotationsConfig(
    autoShowSignPicker: false,
    autoShowLinkDialog: false,
    autoShowPicPicker: false,
    autoShowStampPicker: false,
  ),
);
dart
CPDFReaderWidget(
  document: documentPath,
  configuration: configuration,
  onCreated: (controller) {},
  onAnnotationCreationPreparedCallback: (
    CPDFAnnotationType annotationType,
    CPDFAnnotation? annotation,
  ) {
    debugPrint('Preparing to create annotation: $annotationType');
  },
);

Insert Signature and Stamp

dart
await controller?.prepareNextSignature(signImagePath);

await controller?.prepareNextStamp(standardStamp: stamp);
await controller?.prepareNextStamp(imagePath: imagePath);
await controller?.prepareNextStamp(
  textStamp: CPDFTextStamp(
    content: 'ComPDF-Flutter',
    date: CPDFDate.getTextStampDate(timeSwitch: false, dateSwitch: true),
    shape: CPDFTextStampShape.none,
    color: CPDFTextStampColor.white,
  ),
);

Annotation Style Dialog Dismissed Callback

dart
CPDFReaderWidget(
  document: documentPath,
  configuration: configuration,
  onAnnotationStyleDialogDismissedCallback: (CPDFAnnotationType type) {
    debugPrint('Annotation style dialog dismissed: ${type.name}');
  },
);

Annotation Action Intercept Callback

When interceptNoteAction or interceptLinkAction is enabled, the SDK sends the tapped Note or Link annotation to Flutter instead of running the default native behavior. Use this when you need to show your own Note editor, handle web links yourself, or replace page-jump behavior.

Enable interception before listening to onInterceptAnnotationActionCallback:

dart
CPDFConfiguration(
  annotationsConfig: const CPDFAnnotationsConfig(
    interceptNoteAction: true,
    interceptLinkAction: true,
  ),
);
dart
CPDFReaderWidget(
  document: documentPath,
  configuration: configuration,
  onCreated: (controller) {},
  onInterceptAnnotationActionCallback: (CPDFAnnotation annotation) {
    debugPrint('Intercepted annotation action: ${annotation.type}');
  },
);

Annotation Lifecycle Events

Register listener events after CPDFReaderWidget is created and the CPDFReaderWidgetController is available.

dart
late CPDFReaderWidgetController readerController;

void onAnnotationCreated(dynamic annotation) {
  debugPrint('Annotation created: $annotation');
}

void onAnnotationSelected(dynamic annotation) {
  debugPrint('Annotation selected: $annotation');
}

void onAnnotationDeselected(dynamic annotation) {
  debugPrint('Annotation deselected: $annotation');
}

CPDFReaderWidget(
  document: documentPath,
  configuration: configuration,
  onCreated: (controller) {
    readerController = controller;
    readerController.addEventListener(
      CPDFEvent.annotationsCreated,
      onAnnotationCreated,
    );
    readerController.addEventListener(
      CPDFEvent.annotationsSelected,
      onAnnotationSelected,
    );
    readerController.addEventListener(
      CPDFEvent.annotationsDeselected,
      onAnnotationDeselected,
    );
  },
);

Pencil Drawing Events

Payload fields:

FieldTypeDescription
typeStringDrawing type, usually pencil
pageIndexintzero-based page index
dart
void onPencilDrawingCompleted(dynamic event) {
  debugPrint('Pencil drawing completed on page: ${event['pageIndex']}');
}

void onPencilDrawingDiscarded(dynamic event) {
  debugPrint('Pencil drawing discarded on page: ${event['pageIndex']}');
}

readerController.addEventListener(
  CPDFEvent.pencilDrawingCompleted,
  onPencilDrawingCompleted,
);
readerController.addEventListener(
  CPDFEvent.pencilDrawingDiscarded,
  onPencilDrawingDiscarded,
);

Note: Pencil drawing events are available only on iOS. The returned pageIndex is zero-based.

Remove Event Listeners

When removing a listener, pass the same callback reference that was registered with addEventListener().

dart
readerController.removeEventListener(
  CPDFEvent.annotationsCreated,
  onAnnotationCreated,
);
readerController.removeAllEventListeners(CPDFEvent.annotationsCreated);
readerController.removeAllEventListeners();