---
title: "Multimedia PDF annotations library on iOS | Nutrient SDK"
canonical_url: "https://www.nutrient.io/guides/ios/annotations/multimedia-annotations/"
md_url: "https://www.nutrient.io/guides/ios/annotations/multimedia-annotations.md"
last_updated: "2026-05-26T07:56:07.443Z"
description: "Learn to display multimedia annotations in PDFs on iOS using Nutrient iOS SDK. Support video, audio, and images with custom link annotations for dynamic content."
---

# Multimedia PDF annotations library on iOS

Along with [rich media/video annotations](https://www.nutrient.io/../../annotations/video-annotations), Nutrient iOS SDK and Nutrient Android SDK both support a custom format to display multimedia/gallery annotations using link annotations with the `pspdfkit` scheme.

This format isn’t compatible with PDF readers other than Nutrient iOS SDK and Nutrient Android SDK. Therefore, it’s best suited for inserting multimedia on the fly without saving annotations into a document. We don’t recommend saving these annotations into a document if that document might be opened by another PDF reader.

The supported formats are:

- Video (M3U8, MOV, AVI, MPG, M4V — these are the only formats supported by iOS). Both local content and remote content are supported.

- Audio (MP3, M4A, MP4)

- Images (JPG, JPEG, PNG, [animated] GIF, TIFF, TIF, BMP, BMPF, CUR, XMB)

- Any custom `UIView` using the delegate methods.

To load remote multimedia files, replace `http://` or `https://` with `pspdfkit://` in the URL of the link annotation. For example, `pspdfkit://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8` will show the Apple HTTP Live Streaming test page. There are [delegate methods](https://www.nutrient.io/api/ios/documentation/pspdfkitui/pdfviewcontrollerdelegate/pdfviewcontroller(_:shoulddisplay:on:)) if you need more control (like manually setting autoplay or adding custom annotations).

If you want to display local files, use `pspdfkit://localhost/file.xy`, where `file.xy` is located in the same directory as the PDF. You can also load local files using paths relative to these special directories: `Bundle`, `Documents`, and `Cache`. For example, `pspdfkit://localhost/Bundle/Samples/sunset.jpeg` looks for a file called `sunset.jpeg` in a `Samples` directory at the top level of the app’s bundle.

Playback options are available under the [`Action.Option`](https://www.nutrient.io/api/ios/documentation/pspdfkit/action/option) type. For example, to autoplay a video, create a link annotation like this:

```swift

let video = LinkAnnotation(action: URLAction(url: URL(string: "pspdfkit://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8")!, options: [.autoplayKey: true]))
video.boundingBox = CGRect(x: 100, y: 300, width: 400, height: 300)
document.add(annotations: [video])

```

## Adding a gallery to your document

Nutrient has great support for adding interactive content to a PDF. We support local/remote images, video, and audio. Content can come from different sources and can be configured both locally and remotely via a PDF annotation or a JSON file.

While galleries can be added programmatically, the simplest approach is via a link annotation. A link annotation already defines a bounding box for the position, which the gallery will use.

Gallery annotations can be both created and saved in a file or in code. Here’s an example of how to create this in code:

### SWIFT

```swift

// Dynamically add gallery annotation.
let galleryAnnotation = LinkAnnotation(url: URL(string: "pspdfkit://localhost/Bundle/sample.gallery")!)
let pageSize = document.pageInfoForPage(at: 0)!.size
let size = CGSize(width: 400, height: 300)
galleryAnnotation.boundingBox = CGRect(x: (pageSize.width - size.width) / 2, y: (pageSize.height - size.height) / 2, width: size.width, height: size.height)
document.add(annotations: [galleryAnnotation])

```

### OBJECTIVE-C

```objc

// Dynamically add gallery annotation.
PSPDFLinkAnnotation *galleryAnnotation = [[PSPDFLinkAnnotation alloc] initWithURL:[NSURL URLWithString:@"pspdfkit://localhost/Bundle/sample.gallery"]];
CGSize pageSize = [document pageInfoForPageAtIndex:0].size;
CGSize size = CGSizeMake(400, 300);
galleryAnnotation.boundingBox = CGRectMake((pageSize.width - size.width) / 2.0f, (pageSize.height - size.height) / 2.0f, size.width, size.height);
[document addAnnotations:@[galleryAnnotation] options:nil];

```

The target is a `.gallery` JSON file that defines the contents and title of each image. Its definition is straightforward and looks like this:

```json

[
	{
		"contentURL": "http://www.link-to-image1.com/image1.jpg",
		"caption": "This is a small image."
	},
	{
		"contentURL": "http://localhost/Bundle/gallery-local-image.jpg",
		"caption": "This is a local image. Captions are optional."
	}
]

```

[`contentURL`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/galleryitem/contenturl) can point to a local or remote source, and you can use common tokens like Documents or Bundle, which will be resolved if they’re local. Image sources can be JPG, PNG, or GIF. The image [`caption`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/galleryitem/caption) is optional.

You can also define the JSON in a PDF by using the [`contents`](https://www.nutrient.io/api/ios/documentation/pspdfkit/annotation/contents) property of the annotation (the notes field). Since Adobe Acrobat doesn’t allow setting or changing the [`contents`](https://www.nutrient.io/api/ios/documentation/pspdfkit/annotation/contents) field, we’ve added a second way to configure the gallery via adding the content as a JavaScript action.

The image gallery uses a smart download manager and will cache results (we don’t rely on `NSURLCache`, since not all servers are properly configured to send the correct ETag for images). If your images change dynamically, you need to update the URL to the JSON and use a new image URL. (Adding a timestamp like?1381917561 at the end is a good way to force cache reloads.)

## Video item options

The gallery also supports videos and certain other options:

```json

    "caption":"A local audio file.",
    "options": {
        "loop":true,
        "autoplay":true,
        "controls":false
    }

```

Video items support a wide range of options to control the way the gallery handles them.

| Name                      | Type    | Default   | Description                                                                                                                            |
| ------------------------- | ------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `loop`                    | Boolean | `NO`      | Indicates if the video should loop indefinitely.                                                                                       |
| `autoplay`                | Boolean | `NO`      | Indicates if the video should start playing automatically once it becomes visible.                                                     |
| `controls`                | Boolean | `YES`     | Indicates if the playback controls should be visible.                                                                                  |
| `coverMode`               | string  | `preview` | Defines the cover mode. Possible values are `preview`, `image`, `clear`, and `none`. A description of these values can be found below. |
| `coverImage`              | string  | `nil`     | Defines the image that should be displayed if `coverMode` is set to `image`.                                                           |
| `coverPreviewCaptureTime` | number  | `nil`     | Defines the time in the video that should be used to capture a preview if `coverMode` is set to `preview`.                             |
| `start`                   | number  | `nil`     | Defines the start time of the video in seconds. If this property isn’t set, a start time at the beginning of the video is assumed.     |
| `end`                     | number  | `nil`     | Defines the end time of the video in seconds. If this property isn’t set, an end time at the end of the video is assumed.              |

### coverMode

The following values are valid cover modes.

| Value     | Description                                                             |
| --------- | ----------------------------------------------------------------------- |
| `preview` | A cover will be visible and the cover will be generated from the video. |
| `image`   | A cover will be visible and the given `coverImage` will be presented.   |
| `clear`   | A cover will be visible but the background will be transparent.         |
| `none`    | No cover will be visible.                                               |

To get a clear cover, set the `backgroundColor` of the `GalleryEmbeddedBackgroundView` to `UIColor.clearColor`. This can be done with `UIAppearance`.

### Play button customization

You can change the play button image like this:

### SWIFT

```swift

let image = UIImage(named: "someImage.png")
MediaPlayerCoverView.appearance().playButtonImage = image

```

### OBJECTIVE-C

```objc

UIImage *image = [UIImage imageNamed:@"someImage.png"];
[[PSPDFMediaPlayerCoverView appearance] setPlayButtonImage:image];

```

If you just want to change the color of the play button, do the following:

### SWIFT

```swift

MediaPlayerCoverView.appearance().playButtonColor =.red

```

### OBJECTIVE-C

```objc

[[PSPDFMediaPlayerCoverView appearance] playButtonColor:UIColor.redColor];

```

## Activatable content![inline-gallery](@/assets/guides/ios/annotations/multimedia-annotations/inline-gallery.gif)

By default, the special link annotations mentioned above will show content within the annotation’s bounding box. This behavior can be changed as well:

- modal (`Action.Option.modalKey`) — This will show the content in a new controller, modally, when tapped.![modal](@/assets/guides/ios/annotations/multimedia-annotations/modal.gif)

- popover (`Action.Option.popoverKey`) — This content can also be displayed in a popover. This value is ignored on iPhone.![popover](@/assets/guides/ios/annotations/multimedia-annotations/popover.gif)

- size (`Action.Option.sizeKey`) — If this is defined, the modal controller will be presented as a sheet hovering over the parent controller. This property also controls the popover target size, if set. This will be ignored on iPhone. The minimum size for the sheet is 200×200. A value of 550×550 is recommended for modal sheets.

- button (`Action.Option.buttonKey`) — Set this to `@YES` or to a local/remote destination to show a button instead of directly showing the inline content. This can be used to create multimedia buttons that will show a gallery or web content on tap. This can be combined with a modal/popover to create these actions on a button tap. For local button URLs, use `pspdfkit://localhost/Bundle/image.png` or similar.
---

## Related pages

- [iOS video annotation library](/guides/ios/annotations/video-annotations.md)

