As of v2017R1.04, Qoppa’s Java PDF library jPDFProcess supports adding an electronic invoice in ZUGFeRD format to a PDF document as an XML file attachment or embedded file.
Sample Java program showing how to attach an XML ZUGFeRD invoice to a PDF document using jPDFProcess:
// Load the PDF document PDFDocument pdfDoc = new PDFDocument ("input.pdf", null); // Create a new file option and set the invoice descripion and invoice relation EmbedFileOptions options = new EmbedFileOptions("ZUGFeRD invoice document", "Alternative"); options.setZugferdInvoice(true); // Load the invoice as an XML file File zInvoice = new File("c:/qoppa/tmp/ZUGFeRD-invoice.xml"); // Attach the invoice to the PDF document pdfDoc.addEmbeddedFile(zInvoice, options); // Save the PDF document pdfDoc.saveDocument ("output.pdf"); |
Notes:
- The ZUGFeRD invoice data is held within an XML file that is then embedded into the PDF. The XML format is defined by ZUGFeRD specifications. jPDFProcess library does not validate the XML, it just embeds it into the PDF document.
- The embedded file has to have a “relationship” to the document of “Alternative”, . i.e. the XML invoice data is an alternative form of the PDF visualization. This is a key in the embedded file dictionary.
- The embedded file needs to have a description as well which can be something like “ ZUGFeRD invoice document”. The description requirement doesn’t seem to be strict in the ZUGFeRD specifications.
- There is an additional entry in the root catalog of the document that points to the ZUGFeRD embedded invoice. Note that the invoice is embedded through the normal PDF structures and that this entry in the root catalog is an additional entry that points to the same embedded file.
- ZUGFerd invoices are attached to PDF/A 3 compliant documents and so this code can used in conjunction with Qoppa’s PDF library jPDFPreflight to validate / convert PDF documents to PDF/A-3.
- The name for Zugferd invoice is supposed to be “ZUGFeRD-invoice.xml”, so when an embedded file is marked as Zugfedr, we will hard-code the name and ignore the original file name (starting in v2018R1).