XFDF Support

XFDF is an XML-like standard from Adobe XFDF 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.

Parsing XFDF

To read from an XFDF file:

Copy
1
2
3
4
5
6
7
8
9
// 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.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
// Load from an example XFDF file.
NSURL *externalAnnotationsFile = [NSURL fileURLWithPath:[docsFolder stringByAppendingPathComponent:@"XFDFTest.xfdf"]];

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

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);
}

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];