XFDF Support

XFDF is an XML-like standard from Adobe XFDF (ISO 19444-1:2016) for encoding annotations and forms (see this XFDF overview). It is compatible with Adobe Acrobat and several other third-party frameworks.

ℹ️ Note: XFDF has various limitations. In most cases, using PSPDFKit Instant will result in a smaller file and better synchronization.

PSPDFKit for iOS supports both reading and writing XFDF. It also offers an annotation provider subclass — PSPDFXFDFAnnotationProvider — that will save/load annotations to/from XFDF automatically.

Importing XFDF

You can import annotations and form fields from an XFDF file to a document like so:

Copy
1
2
3
4
5
6
7
8
9
10
11
12
// Load from an example XFDF file.
let externalAnnotationsFile = URL(fileURLWithPath: "path/to/XFDF.xfdf")

let documentProvider = (document.documentProviders.first)!
let dataProvider = PSPDFFileDataProvider(fileURL: externalAnnotationsFile)

// Create the XFDF parser and parse all annotations.
let parser = PSPDFXFDFParser(dataProvider: dataProvider, documentProvider: documentProvider)
let annotations = try! parser.parse()

// Add the parsed annotations to the document.
document.add(annotations)
Copy
1
2
3
4
5
6
7
8
9
10
11
12
// Load from an example XFDF file.
NSURL *externalAnnotationsFile = [NSURL fileURLWithPath:@"path/to/XFDF.xfdf"];

PSPDFDocumentProvider *documentProvider = document.documentProviders.firstObject;
PSPDFFileDataProvider *dataProvider = [[PSPDFFileDataProvider alloc] initWithFileURL:externalAnnotationsFile];

// Create the XFDF parser and parse all annotations.
PSPDFXFDFParser *parser = [[PSPDFXFDFParser alloc] initWithDataProvider:dataProvider documentProvider:documentProvider];
NSArray<PSPDFAnnotation *> *annotations = [parser parseWithError:NULL];

// Add the parsed annotations to the document.
[document addAnnotations:annotations options:nil];

Exporting to XFDF

You can export annotations and form fields from a document to an XFDF file like so:

Copy
1
2
3
4
5
6
7
8
9
10
// Collect all existing annotations from the document.
let annotations = document.allAnnotations(of: .all).values.flatMap { $0 }

// Write the file.
let dataSink = try! PSPDFFileDataSink(fileURL: externalAnnotationsFile)
do {
	try PSPDFXFDFWriter().write(annotations, to: dataSink, documentProvider: document.documentProviders.first!)
} catch {
	print("Failed to write XFDF file: \(error.localizedDescription))")
}
Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
// Collect all existing annotations from the document.
NSMutableArray<PSPDFAnnotation *> *annotations = [NSMutableArray<PSPDFAnnotation *> array];
for (NSArray<PSPDFAnnotation *> *pageAnnotations in [document allAnnotationsOfType:PSPDFAnnotationTypeAll].allValues) {
	[annotations addObjectsFromArray:pageAnnotations];
}

// Write the file.
NSError *error;
PSPDFFileDataSink *dataSink = [[PSPDFFileDataSink alloc] initWithFileURL:externalAnnotationsFile options:PSPDFDataSinkOptionNone error:&error];
NSAssert(dataSink != nil, @"%@", error);
if (![[PSPDFXFDFWriter new] writeAnnotations:annotations toDataSink:dataSink documentProvider:tempDocument.documentProviders[0] error:&error]) {
	NSLog(@"Failed to write XFDF file: %@", error.localizedDescription);
}

Using an XFDF Annotation Provider

PSPDFKit offers an annotation provider subclass — PSPDFXFDFAnnotationProvider — which uses PSPDFXFDFParser and PSPDFXFDFWriter internally and ensures the best performance.

You can use a PSPDFXFDFAnnotationProvider to set up an XFDF annotation provider for a document, which will ensure that all annotation changes will be saved into the XFDF file. This can be done like so:

Copy
1
2
3
4
5
6
7
8
9
10
// Load from an example XFDF file.
let externalAnnotationsFile = URL(fileURLWithPath: "path/to/XFDF.xfdf")

// Create `document` and set up the XFDF provider.
let document = PSPDFDocument()
document.annotationSaveMode = .externalFile
document.didCreateDocumentProviderBlock = {(_ documentProvider: PSPDFDocumentProvider) -> Void in
	let XFDFProvider = PSPDFXFDFAnnotationProvider(documentProvider: documentProvider, fileURL: externalAnnotationsFile)
	documentProvider.annotationManager.annotationProviders = [XFDFProvider]
}
Copy
1
2
3
4
5
6
7
8
9
10
// Load from an example XFDF file.
NSURL *externalAnnotationsFile = [NSURL fileURLWithPath:@"path/to/XFDF.xfdf"];

// Create `document` and set up the XFDF provider.
PSPDFDocument *document = [[PSPDFDocument alloc] initWithURL:documentURL];
document.annotationSaveMode = PSPDFAnnotationSaveModeExternalFile;
document.didCreateDocumentProviderBlock = ^(PSPDFDocumentProvider *documentProvider) {
	PSPDFXFDFAnnotationProvider *XFDFProvider = [[PSPDFXFDFAnnotationProvider alloc] initWithDocumentProvider:documentProvider fileURL:externalAnnotationsFile];
	documentProvider.annotationManager.annotationProviders = @[XFDFProvider];
};

Please take a look at PSCXFDFAnnotationProviderExample in the Catalog app for a runnable sample project.

PSPDFKit also allows you to use an encrypted XFDF file in your XFDF annotation provider. For sample code, please refer to PSCEncryptedXFDFAnnotationProviderExample from the Catalog app.

Handling External Changes

If the XFDF file used to store annotations for a document is changed outside of PSPDFKit, the cache for that document needs to be manually cleared. For performance reasons, PSPDFCache does not take the annotations on a given page into account. As such, when a previously used document is loaded in a PSPDFViewController with an XFDF file that was changed externally, the cache will return stale images.

To counter this, you can clear the cache like so:

1
2
// Where `document` is a `PSPDFDocument` instance.
PSPDFKit.sharedInstance.cache.remove(for: document)
1
2
// Where `document` is a `PSPDFDocument` instance.
[PSPDFKit.sharedInstance.cache removeCacheForDocument:document];

Exporting Annotations to XFDF via Adobe Acrobat

Adobe Acrobat can export annotations into XFDF. The export menu is part of the Comments tool and is accessed by opening the tool in the sidebar.

You can access the export function by clicking on the three dots and then choosing Export All To Data File.

  1. At the bottom of the page, choose Acrobat XFDF Files.
  2. Select the directory you wish to save the XFDF file to and name the file.
  3. Click save.

A successful export will result in a file with an .xfdf extension.

Importing Annotations to XFDF via Adobe Acrobat

The export function is part of the Comments tool and is accessed by clicking on its icon.

Click on the three dots to open the import menu, and then click on Import Data File.

Highlight the .xfdf file you wish to import and click Select.

The import function completes with the annotations being placed on the document.

Adobe Acrobat Error Conditions

Error Description Screenshot
Damaged/missing document body
Damaged/missing description tag
Missing document flag