This example shows how to dynamically add multimedia annotations to a document.


/*
* 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.Context
import android.graphics.RectF
import android.net.Uri
import androidx.activity.viewModels
import com.pspdfkit.annotations.LinkAnnotation
import com.pspdfkit.annotations.actions.UriAction
import com.pspdfkit.catalog.R
import com.pspdfkit.catalog.SdkExample
import com.pspdfkit.catalog.tasks.ExtractAssetTask
import com.pspdfkit.configuration.activity.PdfActivityConfiguration
import com.pspdfkit.document.PdfDocument
import com.pspdfkit.ui.PdfActivity
import com.pspdfkit.ui.PdfActivityIntentBuilder
import org.intellij.lang.annotations.Language
import java.io.File
import kotlin.getValue
/** This example showcases how to dynamically add multimedia content to a PDF document. */
class DynamicMultimediaAnnotationExample(context: Context) : SdkExample(context, R.string.dynamicMultimediaExampleTitle, R.string.dynamicMultimediaExampleDescription) {
override fun launchExample(context: Context, configuration: PdfActivityConfiguration.Builder) {
// Before launching the example, we extract one video file to the private app folder. This
// file will be used to dynamically add
// another link annotation to the document at runtime.
ExtractAssetTask.extract("media/videos/small.mp4", title, context, false, "mp4") { videoFile: File? ->
// Next extract the demo document and launch it.
ExtractAssetTask.extract(WELCOME_DOC, title, context) { documentFile: File? ->
// For normal multimedia content playback, it is not necessary to subclass PdfActivity as no custom code is required (only
// annotations using the pspdfkit:// scheme have to be present). However, if you want to dynamically add multimedia annotations
// to a document, it is preferable to do this using a custom activity class (as done by this example).
val intent = PdfActivityIntentBuilder.fromUri(context, Uri.fromFile(documentFile))
.configuration(configuration.build())
.activityClass(MultimediaAnnotationsActivity::class.java)
.build()
// Pass the file system path to our video file to the activity. The activity will use the path to dynamically add a multimedia link
// annotation to the PDF for opening the extracted video.
intent.putExtra(MultimediaAnnotationsActivity.EXTRA_VIDEO_PATH, videoFile!!.getAbsolutePath())
context.startActivity(intent)
}
}
}
}
/**
* This activity is part of the [DynamicMultimediaAnnotationExample] and shows how to dynamically add multimedia annotations to a PDF document.
*/
class MultimediaAnnotationsActivity : PdfActivity() {
private val viewModel: AnnotationCreationViewModel by viewModels()
companion object {
/** This is the filesystem path of a video file we're going to dynamically add to the PDF document. */
const val EXTRA_VIDEO_PATH = "videoPath"
}
override fun onDocumentLoaded(document: PdfDocument) {
super.onDocumentLoaded(document)
viewModel.createObjects {
// We add a video link to the first page.
addVideoAnnotation()
// We add a gallery link to the second page.
addGalleryAnnotation()
}
}
/**
* This method adds a link annotation to a video on the local file system.
*/
private fun addVideoAnnotation() {
// Get the rect for the link annotation we want to add. We're using absolute page coordinates here, but your app can use different positioning techniques
// like for example using multimedia position data that you would retrieve from your server. This rect is in the center of the page, so tapping the
// page will trigger the video.
val linkAnnotationRect = RectF(0f, 768f, 768f, 256f)
// We're going to place the video on the first page of the document.
val pageIndex = 0
// The activity was launched with the path to a video on the local file system. We're going to use this file for playback with the multimedia annotation.
val videoPathUri = intent.getStringExtra(EXTRA_VIDEO_PATH)?.let { Uri.fromFile(File(it)) }
?: throw IllegalStateException("No string value found for $EXTRA_VIDEO_PATH.")
// Create the link annotation. The LinkAnnotation constructor takes the index of the page on which the annotation will be added.
val multimediaLinkAnnotation = LinkAnnotation(pageIndex).apply {
// Set the position of the link annotation on the page.
boundingBox = linkAnnotationRect
// To let the link point to the multimedia content, we have to set a UriAction on the link. The UriAction encodes the actual URL of the content.
// The multimedia URL uses the pspdfkit:// URL scheme, has optional options in square brackets, followed by the local file system URI of the file.
// Note the the videoPathUri also carries a file:// scheme which is required for video discovery. For a comprehensive list of supported URI formats
// and options, please consult our Multimedia Annotation online guides at: https://nutrient.io/guides/android/annotations/multimedia-annotations/
action = UriAction("pspdfkit://[autoplay:true]$videoPathUri")
}
// Add the annotation to the document and show it.
requirePdfFragment().addAnnotationToPage(multimediaLinkAnnotation, false)
// The line above uses the fragment to add the annotation to the document. This will immediately update the rendered page too, making the newly added
// annotation visible. Alternatively, you can use the document's annotation provider, and manually trigger an annotation updated notification on the
// fragment. Like so:
//
// document.annotationProvider.addAnnotationToPage(multimediaLinkAnnotation)
// fragment.notifyAnnotationHasChanged(multimediaLinkAnnotation)
}
/**
* This method adds a link annotation to a custom gallery on the local file system.
*/
private fun addGalleryAnnotation() {
// This example defines a custom JSON content for the gallery. It writes this JSON to a local file and then create an annotation pointing to the file.
// See our online guides at https://nutrient.io/guides/android/annotations/multimedia-annotations/ for a full specification of the JSON format
// used by galleries.
@Language("JSON")
val galleryJson = """
[
{
"contentURL": "https://farm4.staticflickr.com/3701/13630138733_abf2411bd1_z.jpg",
"caption": "This is a local image. Captions are optional"
},
{
"contentURL": "https://farm3.staticflickr.com/2157/3527157206_f3ebec9909_z.jpg",
"caption": "This is a local image. Captions are optional"
}
]
""".trimIndent()
// Write the JSON to a local gallery file on the file system. It is important that the file uses the .gallery file extension so that Nutrient can
// recognize the file for showing a gallery.
val outputFile = filesDir.resolve("sample.gallery").apply {
// For the sake of this example, we recreate the gallery file from scratch. We therefore delete it if it already exists.
if (exists()) delete()
// Write the whole JSON to the output file.
writeText(galleryJson)
}
// Get the rect for the link annotation we want to add. We're using absolute page coordinates here. These are the same coordinates used by the video
// annotation created in the method above, but we're adding the gallery to the second page (instead of the first one).
val linkAnnotationRect = RectF(0f, 768f, 768f, 256f)
// We're going to place the gallery on the second page of the document.
val pageIndex = 1
// Pointing the link to the gallery file is enough for showing the gallery. It is essential that Uri.fromFile() is used, so that the path inside the
// link annotation has the correct format and includes the file:// URL scheme.
val galleryPathUri = Uri.fromFile(outputFile)
// Create the link annotation. The LinkAnnotation constructor takes the index of the page on which the annotation will be added.
val galleryLinkAnnotation = LinkAnnotation(pageIndex).apply {
// Set the position of the link annotation on the page.
boundingBox = linkAnnotationRect
// To let the link point to the gallery file, we have to set a UriAction on the link. The UriAction encodes the actual URL of the content.
// The multimedia URL uses the pspdfkit:// URL scheme followed by the local file system URI of the file. Galleries don't support multimedia options.
// Note the the galleryPathUri also carries a file:// scheme which is required for gallery discovery. For a comprehensive list of supported URI
// formats, please consult our Multimedia Annotation online guides at: https://nutrient.io/guides/android/annotations/multimedia-annotations/
action = UriAction("pspdfkit://$galleryPathUri")
}
// Add the annotation to the document and show it.
pdfFragment?.addAnnotationToPage(galleryLinkAnnotation, false)
}
}

This code sample is an example that illustrates how to use our SDK. Please adapt it to your specific use case.