Set XMP Media Management Metadata

This guide will show how to set media management XMP metadata.

Before you begin

First of all you should get your API key from your UniCloud account.

If this is your first time using UniPDF SDK, follow this guide to set up a local development environment.

Project setup

Clone the project repository

In your terminal, clone examples repository. It contains the Go code we will be using for this guide.

git clone https://github.com/unidoc/unipdf-examples.git

Navigate to the metadata folder in the unipdf-examples directory.

cd unipdf-examples/metadata

Configure environment variables

Replace the UNIDOC_LICENSE_API_KEY with your API credentials from your UniCloud account.

Linux/Mac

export UNIDOC_LICENSE_API_KEY=PUT_YOUR_API_KEY_HERE

Windows

set UNIDOC_LICENSE_API_KEY=PUT_YOUR_API_KEY_HERE

How it works

package main
import (
"fmt"
"log"
"os"
"time"
"github.com/unidoc/unipdf/v4/common/license"
"github.com/unidoc/unipdf/v4/core"
"github.com/unidoc/unipdf/v4/model"
"github.com/unidoc/unipdf/v4/model/xmputil"
)
func init() {
// Make sure to load your metered License API key prior to using the library.
// If you need a key, you can sign up and create a free one at https://cloud.unidoc.io
err := license.SetMeteredKey(os.Getenv(`UNIDOC_LICENSE_API_KEY`))
if err != nil {
panic(err)
}
}
func main() {
args := os.Args
if len(args) < 3 {
fmt.Printf("Usage: %s INPUT_PDF_PATH OUTPUT_PDF_PATH\n", os.Args[0])
return
}
inputPath := args[1]
outputPath := args[2]
// Initialize starting time.
start := time.Now()
defer func() {
duration := float64(time.Since(start)) / float64(time.Millisecond)
fmt.Printf("Processing time: %.2f ms\n", duration)
}()
// Read some file to which you want to add XMP metadata.
reader, file, err := model.NewPdfReaderFromFile(inputPath, nil)
if err != nil {
log.Fatalf("Fail: %v\n", err)
}
defer file.Close()
// Copy content of the reader into a writer.
pdfWriter, err := reader.ToWriter(nil)
if err != nil {
log.Fatalf("Fail: %v\n", err)
}
// Extract metadata if is already defined within given catalog.
var xmpDoc *xmputil.Document
metadata, ok := reader.GetCatalogMetadata()
if ok {
stream, ok := core.GetStream(metadata)
if !ok {
log.Fatalf("Catalog metadata is expected to be a stream but is: %T", metadata)
}
xmpDoc, err = xmputil.LoadDocument(stream.Stream)
if err != nil {
log.Fatalf("Reading XMP metadata failed: %v", err)
}
} else {
// Otherwise, simply create a new XMP document,
xmpDoc = xmputil.NewDocument()
}
mm, ok := xmpDoc.GetMediaManagement()
if !ok {
mm = &xmputil.MediaManagement{
// OriginalDocumentID is a persistent identifier of a document. It should persist no matter
// what modification had been done on the document.
// If the Media Management metadata is not defined within XMP document, this value would either be automatically
// generated or set up to the one provided within MediaManagementOptions.
// By setting this value here and copying it to the MediaManagementOptions we can control how this value
// persists.
OriginalDocumentID: "56119f84-a812-484a-bb4c-61c7e7cb3265",
}
}
mmOptions := &xmputil.MediaManagementOptions{
// OriginalDocumentID should maintain after any modification of provided document.
OriginalDocumentID: string(mm.OriginalDocumentID),
// Set this value if we want to create a new file (not overwrite current file).
NewDocumentID: true,
ModifyComment: "Added Media Management XMP Metadata",
ModifyDate: time.Now(),
Modifier: "Example User Modifier name",
}
if err = xmpDoc.SetMediaManagement(mmOptions); err != nil {
log.Fatalf("Err: %v", err)
}
// Once we've defined all the XMP metadata we wanted we can extract raw bytes stream and store as catalog metadata PdfStream.
// By doing:
// 1. Marshal XMP Document into raw bytes.
metadataBytes, err := xmpDoc.MarshalIndent("", "\t")
if err != nil {
log.Fatalf("Err: %v", err)
}
// 2. Create new PdfStream
metadataStream, err := core.MakeStream(metadataBytes, nil)
if err != nil {
log.Fatalf("Err: %v", err)
}
// 3. Set the metadata stream as catalog metadata.
if err = pdfWriter.SetCatalogMetadata(metadataStream); err != nil {
log.Fatalf("Err: %v", err)
}
// Create output file.
err = pdfWriter.WriteToFile(outputPath)
if err != nil {
log.Fatalf("Fail: %v\n", err)
}
}

The import section in line 3-13 imports unipdf packages and other necessary libraries. The init function which is defined in lines 15-22 authenticates your request.

The main function defined in lines 24-122 sets the media management metadata. In this function, lines 25-31 the input and the output file paths are processed from the command line argument. The time taken to process the document is measured in lines 34-38. A new pdf reader is instantiated using NewPdfReaderFromFile in lines 41-45.

A new pdfWriter is created from the reader object in lines 48-51 using ToWriter method of the the PdfReader. The section in lines 54-69 extracts metadata from the input file if it already exists, otherwise it creates a new xmputil.Document.

in lines 71-82 a new media management is created xmputil.MediaManagement. The media management options is set in lines 84-92. In lines 93-95 the media management object is set to the XMP document using xmpDoc.SetMediaManagement(mmOptions).

The XMP document is marshaled into XML byte stream in lines 101-104. Then a new PdfObjectStream is created from the byte stream using core.MakeStream(metadataBytes, nil). In lines 113-115 the stream metadata is set to the pdfWriter using SetCatalogMetadata(metadataStream).

Finally the document is written to file using pdfWriter.WriteToFile(outputPath) in lines 118-121.

Run the code

go run pdf_set_xmp_media_management_metadata.go <input.pdf> <output.pdf>

Got any Questions?

We're here to help you.