Contents

Generating ZUGFeRD Invoices with PDFTron
How to Embed an XML in a PDF
How to Convert a PDF to PDF/A-3
Embedding XMP Metadata
Make use of Other PDF Invoicing Features

The ZUGFeRD standard makes the sharing of payment information between entities large and small a lot simpler. However, building a program to automatically generate ZUGFeRD compliant invoices is a little more involved. This post shows you how you can create valid ZUGFeRD files via Windows, Mac or Linux apps by leveraging PDFTron’s full-featured SDK.

linkGenerating ZUGFeRD Invoices with PDFTron

Start by downloading a trial of PDFTron’s SDK, which includes the features you will need, such as adding file attachments to a PDF, converting to PDF/A format, and PDF/A verification; as well as offerings for digital signature creation, redaction and much more.

First, it is important to reiterate that ZUGFeRD invoices bring together two parts: an XML and a PDF/A-3. The XML file serves as a machine-readable representation of the invoice (which should be named ZUGFeRD-invoice.xml), while the PDF/A-3 serves as both the human-readable image and as a container for the XML.

When generating the human-readable invoice, you may wish to work in a higher level format like DOCX, XAML or HTML before converting to PDF, which makes direct editing and structuring of the file more involved.

PDFTron’s SDK won’t restrict you to working in PDF since it is able to convert 20+ file formats via pdftron.PDF.Convert.ToPDF, with samples available in C#, C++, Java, Obj-C, PHP, Python, Ruby, and VB.

linkHow to Embed an XML in a PDF

The first step after creating your XML file is to embed the XML within the PDF invoice on a “one-to-one” basis. That means each ZUGFeRD invoice should consist of a single XML representation paired with a matching PDF representation, while you may later add as many non-invoice file attachments as you wish.

For the purpose of this post, we’ll provide sample code in C# -- with the full sample available for download here. Note that this sample assumes you have a file named ZUGFeRD-invoice.xml in the input_path TestFiles. (It will not generate an XML for you.)

Beneath is the section from the sample that reads the PDF document and an XML invoice from your chosen inputs, embeds the XML invoice into the PDF as an attachment, and saves the result as a new, in-memory PDF file (stored in the byte array). Importantly, when embedding the XML, the code attaches the XML to the PDF as a whole as it is supposed to, rather than to a section of the document.

byte[] doc_bytes_invoice_added = null;
using (PDFDoc in_doc = new PDFDoc(input_path + "fish.pdf"))
{
    in_doc.InitSecurityHandler();
    NameTree files = NameTree.Create(in_doc, "EmbeddedFiles");
    FileSpec fs = FileSpec.Create(in_doc, input_path + "ZUGFeRD-invoice.xml", true);
    byte[] file1_name = System.Text.Encoding.UTF8.GetBytes("ZUGFeRD-invoice.xml");
    files.Put(file1_name, fs.GetSDFObj());
    fs.GetSDFObj().PutText("Desc", "ZUGFeRD Rechnung");
    fs.GetSDFObj().PutName("AFRelationship", "Alternative");
    fs.GetSDFObj().PutText("F", "ZUGFeRD-invoice.xml");
    fs.GetSDFObj().PutText("UF", "ZUGFeRD-invoice.xml");
    Obj collection = in_doc.GetRoot().FindObj("Collection");
    if (collection == null) collection = in_doc.GetRoot().PutDict("Collection");
    collection.PutName("View", "T");
    doc_bytes_invoice_added = in_doc.Save(SDFDoc.SaveOptions.e_incremental);
}

linkHow to Convert a PDF to PDF/A-3

Converting to PDF/A-3 will serve as your next step to ensure there are no objects (e.g., non-embedded fonts) in your invoice that could later compromise the ability of a PDF reader to correctly display the content. The use of the PDF/A-3 standard, as opposed to PDF/A-2 or PDF/A-1, is mandatory for ZUGFeRD invoices, as only PDF/A-3 permits you to embed non-PDF/A file types.

For the following sample, we’ve also chosen to convert to PDF/A conformance level b. This is generally a good path to follow; selecting level b will make it easier for invoices to pass auto-conversion. You can always change the syntax to convert to another conformance level (i.e., level a or level u) in case you are either restricted by a policy or want to enhance your invoices’ accessibility features, such as ensuring text that can be reliably searched & copied. Just be prepared that this may entail doing extra scripting to mark PDF content for logical structure and read order, and to add character mappings to Unicode -- if your PDFs do not contain this information already.

byte[] doc_bytes_pdfa = null;
using (PDFACompliance pdf_a = new PDFACompliance(true, doc_bytes_invoice_added, null, PDFACompliance.Conformance.e_Level3B, null, 10, false))
{
    doc_bytes_pdfa = pdf_a.SaveAs(false);
}

linkEmbedding XMP Metadata

Finally, the last step will be to add XMP metadata to describe the embedded invoice as a ZUGFeRD invoice. The following code will do just that, and afterwards, it should save to disk a ZUGFeRD-compliant PDF!

using (PDFDoc in_doc = new PDFDoc(doc_bytes_pdfa, doc_bytes_pdfa.Length))
{
    in_doc.InitSecurityHandler();
    Obj xmp_stm = in_doc.GetRoot().FindObj("Metadata");
    Filter stm = xmp_stm.GetDecodedStream();
    FilterReader reader = new FilterReader(stm);
    byte[] buf = new byte[stm.Size()];
    int nb = reader.Read(buf);
    String xmp_str = System.Text.ASCIIEncoding.ASCII.GetString(buf);
    String zugferd_xmp = "<rdf:Description rdf:about=\"\">";
    zugferd_xmp += "<zf:ConformanceLevel>BASIC</zf:ConformanceLevel>";
    zugferd_xmp += "<zf:DocumentFileName>ZUGFeRD-invoice.xml</zf:DocumentFileName>";
    zugferd_xmp += "<zf:DocumentType>INVOICE</zf:DocumentType>";
    zugferd_xmp += "<zf:Version>1.0</zf:Version>";
    zugferd_xmp += "</rdf:Description>";
    xmp_str = xmp_str.Insert(xmp_str.IndexOf("<rdf:Description "), zugferd_xmp);
    xmp_stm.SetStreamData(System.Text.Encoding.ASCII.GetBytes(xmp_str));
    in_doc.Save(output_path + "zugferd_invoice.pdf", SDFDoc.SaveOptions.e_linearized);
}

linkMake use of Other PDF Invoicing Features

That’s it! If you’ve followed the steps above, you should now have a working prototype able to automatically generate ZUGFeRD-valid invoices using PDFTron’s SDK.

You may want to later add other invoicing capabilities to your solution. In which case, you can check out PDFTron’s full-featured SDK library with a free trial.

If you have any questions about PDFTron’s PDF SDK, please feel free to get in touch!