How To…Customize PDF/A Metadata

Question

“How can I alter the default metadata when exporting to PDF/A?”

Solution

Use the TppPDFDevice.OnGetPDFMetadata event to retrieve the default metadata and alter it to meet your specific needs.  All metadata is in XML format so it is beneficial to use the Delphi built-in XML classes to edit the data. The following example shows how to alter the Conformance Level when exporting to the PDF/A-3 ZUGFeRD format.

Download: ZUGFeRDCustomMetaData.zip

1. First implement the OnGetPDFMetadata event in the TppReport.OnFileDeviceCreate event.

procedure TForm1.ppReport1FileDeviceCreate(Sender: TObject);
begin
  //Assign the OnGetMetaData event of the PDF Device
  if ppReport1.FileDevice is TppPDFDevice then
    TppPDFDevice(ppReport1.FileDevice).OnGetPDFMetaData := ehPDF_GetMetaData;

end;

 
2. Next, we plan to use the built-in Delphi XML classes to edit the XML.  For this example we will simply alter the value of an existing XML node.  To do so, we will need a separate routine to recursively find the XML node we need.

function FindNodeByName(aNode: IXMLNode; const aName: String): IXMLNode;
var
  liIndex: Integer;
begin

  Result := nil;

  if aNode = nil then Exit;

  if (aNode.NodeName = aName) then
    Result := aNode

  else if (aNode.HasChildNodes) then
    begin
      liIndex := 0;
      while (Result = nil) and (liIndex < aNode.ChildNodes.Count) do
        begin
          Result := FindNodeByName(aNode.ChildNodes[liIndex], aName);
          liIndex := liIndex + 1;
        end;

    end;

end;

 
3. Finally, we put everything together to alter a specific node in the existing metadata to meet our needs. The following code alters the “zf:ConformanceLevel” node to have a value of “COMFORT” instead of the default “BASIC”.

procedure TForm1.ehPDF_GetMetaData(Sender: TObject; aMetaData: TStrings);
var
  lXMLDoc: TXMLDocument;
  lNodeElement: IXMLNode;
begin

  lXMLDoc := TXMLDocument.Create(Self);

  //Load the existing XML text into the XML Document object
  lXMLDoc.LoadFromXML(aMetaData.Text);

  //Find the node that needs to be edited
  lNodeElement := FindNodeByName(lXMLDoc.DocumentElement,'zf:ConformanceLevel');

  //Update the node value
  if lNodeElement <> nil then
    lNodeElement.Text := 'COMFORT';

  //Save the updated XML back to the PDF
  aMetaData.Text := lXMLDoc.XML.Text;

  lXMLDoc.Free;

end;