Import and export PDF annotations with XFDF files on Android
Adobe’s XML Forms Data Format (XFDF) standard (ISO 19444-1:2016)(opens in a new tab) defines how to encode annotations and form field values. An XFDF file contains a snapshot of a PDF document’s annotations and form field values. Adobe Acrobat and several third-party frameworks support XFDF.
XFDF isn’t designed for synchronization, but Instant JSON supports synchronization and generally produces smaller files. For details, refer to the Instant JSON guide.
Nutrient Android SDK reads and writes XFDF files through the XfdfFormatter class. This class provides parseXfdf() and writeXfdf() for synchronous operations.
Use parseXfdfAsync() and writeXfdfAsync() with a background scheduler to keep processing off the UI thread.
Importing XFDF
To read PDF annotations from an XFDF file asynchronously, use parseXfdfAsync():
// Your data provider, serving the XFDF file to parse.var yourDataProvider = SomeDataProvider()
// The async parse method is recommended (so you can easily offload parsing from the UI thread).XfdfFormatter.parseXfdfAsync(pdfDocument, yourDataProvider) .subscribeOn(Schedulers.io()) // Specify the thread on which to parse XFDF. .subscribe { annotations -> // Annotations parsed from XFDF aren't added to the document automatically. // You need to add them manually. lifecycleScope.launch { for (annotation in annotations) { pdfDocument.getAnnotationProvider().addAnnotationToPage(annotation) } } }import kotlin.coroutines.EmptyCoroutineContext;import kotlinx.coroutines.BuildersKt;
// Your data provider, serving the XFDF file to parse.DataProvider yourDataProvider = new SomeDataProvider();
// The async parse method is recommended (so you can easily offload parsing from the UI thread).XfdfFormatter.parseXfdfAsync(pdfDocument, yourDataProvider) .subscribeOn(Schedulers.io()) // Specify the thread on which to parse XFDF. .subscribe(annotations -> { // Annotations parsed from XFDF aren't added to the document automatically. // You need to add them manually. This callback runs on the I/O thread, so // `runBlocking()` can wait there for the suspend function `addAnnotationToPage()`. for (Annotation annotation : annotations) { BuildersKt.runBlocking( EmptyCoroutineContext.INSTANCE, (scope, continuation) -> pdfDocument.getAnnotationProvider().addAnnotationToPage(annotation, continuation)); } });The callback returns annotations without adding them to the document, so you can choose which annotations to add. Call document.getAnnotationProvider().addAnnotationToPage() for each annotation you choose.
Exporting to XFDF
To export annotations and form field values to an XFDF file, use writeXfdfAsync():
// List of annotations from the document to be exported.val listOfAnnotationsToExport = ...
// List of form fields from the document to be exported.val listOfFormFieldsToExport = ...
// Output stream pointing to the XFDF file into which to write the data.val outputStream = ...
// The async `write` method is recommended (so you can easily offload writing from the UI thread).XfdfFormatter.writeXfdfAsync(pdfDocument, listOfAnnotationsToExport, listOfFormFieldsToExport, outputStream) .subscribeOn(Schedulers.io()) // Specify the thread on which to write XFDF. .subscribe(..)// List of annotations from the document to be exported.List<Annotation> listOfAnnotationsToExport = ... ;
// List of form fields from the document to be exported.List<FormField> listOfFormFieldsToExport = ... ;
// Output stream pointing to the XFDF file into which to write the data.OutputStream outputStream = ... ;
// The async `write` method is recommended (so you can easily offload writing from the UI thread).XfdfFormatter.writeXfdfAsync(pdfDocument, listOfAnnotationsToExport, listOfFormFieldsToExport, outputStream) .subscribeOn(Schedulers.io()) // Specify the thread on which to write XFDF. .subscribe(..);