XFDF Example
Shows how to import and export annotations in XFDF format.
/* * Copyright © 2018-2026 PSPDFKit GmbH. All rights reserved. * * The PSPDFKit Sample applications are licensed with a modified BSD license. * Please see License for details. This notice may not be removed from this file. */
package com.pspdfkit.catalog.examples.kotlin
import android.content.Contextimport android.content.Intentimport android.net.Uriimport android.view.Menuimport android.view.MenuItemimport android.widget.Toastimport androidx.appcompat.app.AppCompatActivityimport com.pspdfkit.annotations.AnnotationTypeimport com.pspdfkit.catalog.Rimport com.pspdfkit.catalog.SdkExampleimport com.pspdfkit.catalog.tasks.ExtractAssetTask.extractimport com.pspdfkit.configuration.activity.PdfActivityConfigurationimport com.pspdfkit.document.formatters.XfdfFormatterimport com.pspdfkit.document.providers.ContentResolverDataProviderimport com.pspdfkit.ui.PdfActivityimport com.pspdfkit.ui.PdfActivityIntentBuilderimport kotlinx.coroutines.CoroutineScopeimport kotlinx.coroutines.Dispatchersimport kotlinx.coroutines.launchimport kotlinx.coroutines.withContextimport java.io.FileNotFoundExceptionimport java.util.EnumSet
/** Shows how to import and export annotations in XFDF format. */class XfdfExample(context: Context) : SdkExample( context, R.string.xfdfExampleTitle, R.string.xfdfExampleDescription, ) { override fun launchExample(context: Context, configuration: PdfActivityConfiguration.Builder) { // Extract the document from the assets and launch example activity. extract(WELCOME_DOC, title, context) { documentFile -> val intent = PdfActivityIntentBuilder .fromUri(context, Uri.fromFile(documentFile)) .configuration(configuration.build()) .activityClass(XfdfExampleActivity::class.java) .build() context.startActivity(intent) } }}
/** This activity shows how to import and export annotations in XFDF format. */class XfdfExampleActivity : PdfActivity() { override fun onCreateOptionsMenu(menu: Menu): Boolean { super.onCreateOptionsMenu(menu) menu.add(0, EXPORT_TO_XFDF_ITEM_ID, 0, "Export to XFDF") menu.add(0, IMPORT_FROM_XFDF_ITEM_ID, 0, "Import from XFDF") return true }
override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) { EXPORT_TO_XFDF_ITEM_ID -> { pickFileForXfdfExport() true }
IMPORT_FROM_XFDF_ITEM_ID -> { pickFileForXfdfImport() true }
else -> { super.onOptionsItemSelected(item) } }
/** * Fires up [Intent.ACTION_CREATE_DOCUMENT] to allows user to pick output file for XFDF * export. */ @Suppress("DEPRECATION") private fun pickFileForXfdfExport() { if (document == null) return
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply { type = "application/*" addCategory(Intent.CATEGORY_OPENABLE) // This sets the default name of the output file. putExtra(Intent.EXTRA_TITLE, "annotations.xfdf") }
startActivityForResult(intent, PICK_EXPORT_FILE_RESULT) }
/** * Fires up [Intent.ACTION_OPEN_DOCUMENT] to allows user to pick input file for XFDF * import. */ @Suppress("DEPRECATION") private fun pickFileForXfdfImport() { if (document == null) return
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply { type = "application/*" addCategory(Intent.CATEGORY_OPENABLE) }
startActivityForResult(intent, PICK_IMPORT_FILE_RESULT) }
@Deprecated("Deprecated in Java") override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data)
if (resultCode != AppCompatActivity.RESULT_OK || data == null) return val uri = data.data ?: return
when (requestCode) { PICK_EXPORT_FILE_RESULT -> exportToXfdf(uri) PICK_IMPORT_FILE_RESULT -> importFromXfdf(uri) } }
/** * Exports annotations from the first page to the XFDF file. * * @param uri Uri of the target file for XFDF export. */ private fun exportToXfdf(uri: Uri) { try { val outputStream = contentResolver.openOutputStream(uri) ?: return
CoroutineScope(Dispatchers.Main).launch { try { val doc = document ?: return@launch
val allAnnotations = doc.annotationProvider.getAllAnnotationsOfType( EnumSet.allOf(AnnotationType::class.java), ) withContext(Dispatchers.IO) { XfdfFormatter.writeXfdf(doc, allAnnotations, emptyList(), outputStream) outputStream.close() } Toast .makeText( this@XfdfExampleActivity, "Annotations successfully exported", Toast.LENGTH_LONG, ).show() } catch (e: Exception) { Toast .makeText( this@XfdfExampleActivity, "Annotations export failed", Toast.LENGTH_LONG, ).show() } } } catch (ignored: FileNotFoundException) { } }
/** * Imports annotations from XFDF file and adds them to the document. * * @param uri Uri of the XFDF file from which to import annotations. */ private fun importFromXfdf(uri: Uri) { CoroutineScope(Dispatchers.Main).launch { try { val doc = document ?: return@launch val annotations = withContext(Dispatchers.IO) { XfdfFormatter.parseXfdf(doc, ContentResolverDataProvider(uri)) } // Annotations parsed from XFDF are not added to document automatically. // We need to add them manually. for (annotation in annotations) { pdfFragment?.addAnnotationToPage(annotation, false) }
Toast .makeText( this@XfdfExampleActivity, "Annotations successfully imported", Toast.LENGTH_LONG, ).show() } catch (e: Exception) { Toast .makeText( this@XfdfExampleActivity, "Annotations import failed", Toast.LENGTH_LONG, ).show() } } }
companion object { private const val EXPORT_TO_XFDF_ITEM_ID = 1 private const val IMPORT_FROM_XFDF_ITEM_ID = 2
private const val PICK_EXPORT_FILE_RESULT = 1 private const val PICK_IMPORT_FILE_RESULT = 2 }}This code sample is an example that illustrates how to use our SDK. Please adapt it to your specific use case.