PDF Document API – Embed XMP Metadata & Create ZUGFeRD-Compliant PDFs in v21.1 (And an Important Survey)

Our PDF File API v21.1 allows you to embed Adobe Extensible Metadata Platform (XMP) and ZUGFeRD-compliant XML data within your PDF documents.

As you may already know, XMP is an XML-based ISO metadata standard (originally created by Adobe Systems Inc.) It defines the necessary data structure, serialization model, and basic metadata properties for a unified metadata package – a package that can be embedded into different media formats.

ZUGFeRD is a cross-industry data format used for electronic invoice data exchange (based on the XMP standard). ZUGFeRD integrates structured invoice data in XML format into a PDF/A-3b document.

XMP Metadata Support

The DevExpress PDF File API allows you to execute the following actions with XMP metadata:

  • embed metadata loaded from a stream or a string;
  • add new nodes to the embedded metadata;
  • change an existing node’s value;
  • remove XMP nodes;
  • create new metadata from scratch;
  • use predefined schemas to generate a new XMP data model.

Load and Embed XMP Metadata

To get started, execute the PdfDocument.SetMetadata method to embed XMP metadata into a document. You can pass a string with metadata - or an instance of the XMP data model (XMP packet) - to this method. Packet data can be loaded from a stream or a string.

The code below loads metadata from a file and embeds it in the document:

using DevExpress.Pdf;
using DevExpress.Pdf.Xmp;
//...
using (PdfDocumentProcessor pdfDocumentProcessor = new PdfDocumentProcessor())
{
  pdfDocumentProcessor.LoadDocument("Documents//Invoice.pdf");
  PdfDocument document = pdfDocumentProcessor.Document;
  XmpDocument metadata = new XmpDocument();
  using (FileStream xmlStream = new 
      FileStream("Documents//metadata.xml", FileMode.Open, FileAccess.Read))
    {
        metadata = XmpDocument.FromStream(xmlStream);
        document.SetMetadata(metadata);
    }
    pdfDocumentProcessor.SaveDocument("Invoice_Upd.pdf");
}

Manage Metadata Nodes

The PdfMetadata.Data property retrieves metadata associated with a document. Use the XmpDocument.FromString method to convert retrieved data to an XMP packet.

The XmpDocument.Values property returns a dictionary and contains packet nodes (name-value pairs for metadata properties). You can access a packet node by its name or value. A node name includes the prefix:local name format.

You can add new nodes, change an existing node’s value, or remove an XMP node. When you add a new node to the packet, you can use the XmpName class object or a string to specify node name. In the latter, make certain that the specified prefix is registered. You can call the XmpDocument.RegisterNamespace method to register the prefix.

The following code demonstrates how to edit document metadata:

using DevExpress.Pdf;
using DevExpress.Pdf.Xmp;
//...

using (PdfDocumentProcessor pdfDocumentProcessor = new PdfDocumentProcessor())
{
  // Load document
  pdfDocumentProcessor.LoadDocument("Documents//Invoice.pdf");
  PdfDocument document = pdfDocumentProcessor.Document;

  // Retrieve metadata:
  XmpDocument metadata = XmpDocument.FromString(document.Metadata.Data);

  // Add items to the Creator array:
  XmpArray creators = metadata.GetArray("dc:creator");
  if (creators != null)
  {
     creators.Add("PDF Document API");
     creators.Add("Office File API");
  }

  // Change the CreatorTool node value:
  XmpSimpleNode creatorTool = metadata.GetSimpleValue("xmp:CreatorTool");
  creatorTool.SetValue("PDF Document API");

  // Add MaxPageSize structure:
  XmpName structureName = 
      XmpName.Get("MaxPageSize", "http://ns.adobe.com/xap/1.0/t/pg/");
  XmpStructure dimensions = metadata.CreateStructure(structureName);
  metadata.RegisterNamespace("http://ns.adobe.com/xap/1.0/sType/Dimensions#", "stDim");
  dimensions.Add("stDim:h", 11);
  dimensions.Add("stDim:w", 8.5f);
  dimensions.Add("stDim:Unit", "inch");

  // Delete the Title node:
  metadata.Remove("dc:title");
    
  // Embed modified metadata in the document:
  document.SetMetadata(metadata);

  // Save the result:
  pdfDocumentProcessor.SaveDocument("Invoice_Upd.pdf");
}

Use XMP Schemas

An XMP schema (or namespace) is a set of metadata properties. Each schema is identified by a unique namespace URI and can hold an arbitrary number of properties. The XMP specification contains the definition of predefined schemas that include standard general-purpose namespaces, and namespaces that are specialized for Adobe applications.

The DevExpress PDF File API supports the following predefined XMP namespaces:

  • Basic XMP
  • Dublin Core
  • Adobe PDF
  • PDF/A
  • Rights Management

The code below demonstrates how to add items from the Dublin Core schema to the packet:

using DevExpress.Pdf;
using DevExpress.Pdf.Xmp;
//...

using (PdfDocumentProcessor pdfDocumentProcessor = new PdfDocumentProcessor())
{
  // Load document:
  pdfDocumentProcessor.LoadDocument("Documents//Invoice.pdf");
  PdfDocument document = pdfDocumentProcessor.Document;

  // Create new XMP packet:
  XmpDocument metadata = new XmpDocument();
   
  // Add items from the Dublin Core schema:
  DublinCoreProperties dublinCoreProperties = metadata.DublinCoreProperties;
  dublinCoreProperties.Creator.Add("DevExpress");
  dublinCoreProperties.Description.AddString
      ("This document has embedded XMP metadata", "en-us");
  dublinCoreProperties.Title.AddString("Invoice", "x-default");
  dublinCoreProperties.Type.Add("PDF");
  dublinCoreProperties.Publisher.Add("PDF Document API");
   
  // Embed metadata in the document:
  document.SetMetadata(metadata);

  // Save the result:
  pdfDocumentProcessor.SaveDocument("Invoice_Upd.pdf");
}

You can also create a custom schema as needed. To get started, create a CustomProperties class object, populate it with items and assign this object to the XmpDocument.CustomProperties property to add your schema to the packet.

using DevExpress.Pdf;
using DevExpress.Pdf.Xmp;
//...

using (PdfDocumentProcessor pdfDocumentProcessor = new PdfDocumentProcessor())
{
  pdfDocumentProcessor.LoadDocument("Documents//Invoice.pdf");
  PdfDocument document = pdfDocumentProcessor.Document;
  XmpDocument metadata = XmpDocument.FromString(document.Metadata.Data);

  metadata.RegisterNamespace("https://www.devexpress.com/", "dx");
  CustomProperties customProperties = 
      new CustomProperties(metadata, "https://www.devexpress.com/");
  customProperties["Team"] = "Office";
  customProperties["Checked"] = "true";
  customProperties["Project"] = "PDF Document API";

  document.SetMetadata(metadata);
  pdfDocumentProcessor.SaveDocument("Invoice_Upd.pdf");
}

ZUGFeRD-Compliant PDFs

Use the PdfDocument.AttachZugferdInvoice method to embed ZUGFeRD-compliant XML in your PDF documents. Please note that this method does not convert the document to a PDF/A-3b-compatible file. Make certain that your document is PDF/A-3b-compliant before embedding ZUGFeRD-compliant XML.

using (PdfDocumentProcessor pdfDocumentProcessor = new PdfDocumentProcessor())
{
    pdfDocumentProcessor.LoadDocument("Invoice.pdf");
    pdfDocumentProcessor.Document.AttachZugferdInvoice
        (File.ReadAllBytes("ZUGFeRD-invoice.xml"));
    pdfDocumentProcessor.SaveDocument("Invoice_Upd.pdf");
}

Note: You can use the following free package to generate ZUGFeRD-compliant XML data: https://github.com/stephanstapel/ZUGFeRD-csharp

Your Feedback Matters

As always, we welcome your feedback. Please feel free to leave comments below or contact us via the DevExpress Support Center.

Before we let you go - We are now exploring electronic invoice support (e-Invoicing, electronic billing, XML invoice documents). Your answers to the following survey questions will help us finalize our specifications:

FREE DevExpress Xamarin UI Controls

Deliver high-impact native mobile apps with our feature-rich Data Grid, Scheduler, Chart, TabView, Editors, and utility controls. Reserve your free copy today!
No Comments

Please login or register to post comments.