Developer Resources

Cracking the Code: Converting PDF Documents to Meet ISO Standards

#Adobe PDF Library #.NET #Code Samples #Tutorial
Published January 18, 2023 Updated June 19, 2026

Standard PDF formats exist because different industries need guarantees that go beyond what a plain PDF provides. An archival system needs to know a document will render identically in 20 years. A commercial printer needs to know color data is complete and fonts are embedded. An invoicing system needs a machine-readable data layer alongside the human-readable layout. ISO-defined PDF standards address each of these requirements.

 

The Adobe PDF Library provides conversion functions for the three most widely required PDF standards: PDF/A for long-term archiving, PDF/X for print and prepress, and ZUGFeRD for structured invoice archiving. This tutorial covers all three using .NET samples. The same conversions are also available in .NET Framework, Adobe C++, Modern C++, and Java in the Datalogics GitHub repository.

 

Who Is This For?

This tutorial is for developers working in industries with document compliance requirements. That includes government agencies and regulated industries that mandate PDF/A for records retention, commercial print and prepress shops requiring PDF/X-compliant files, and organizations operating in European markets where ZUGFeRD or similar e-invoicing standards are legally required or actively adopted. It is also relevant to any developer building a document processing pipeline that needs to validate or normalize incoming PDFs to a known standard.

 

PDF/A: Long-Term Document Archiving

What Problem It Solves

A standard PDF may reference external fonts, embed JavaScript, use encryption, or rely on features that future PDF viewers may not support. PDF/A eliminates all of these by requiring that the document be self-contained and free of content that could prevent faithful reproduction. The result is a document that will render identically regardless of which software or operating system opens it, now or in the future.

 

PDF/A was first published as ISO 19005-1 in 2005. Multiple conformance levels exist (PDF/A-1, 2, and 3), with later versions adding support for additional features such as embedded files. The conversion type you choose depends on which conformance level your archival system requires.

 

The PDFAConverter Sample

The PDFAConverter sample opens an input PDF and calls CloneAsPDFADocument, which creates a new PDF/A-compliant document without modifying the original. The conversion parameters control validation behavior:

 

using (Document doc = new Document(sInput))

{

    PDFAConvertParams pdfaParams = new PDFAConvertParams();

    pdfaParams.AbortIfXFAIsPresent = true;

    pdfaParams.IgnoreFontErrors = false;

    pdfaParams.NoValidationErrors = false;

    pdfaParams.ValidateImplementationLimitsOfDocument = true;

 

    PDFAConvertResult pdfaResult = doc.CloneAsPDFADocument(PDFAConvertType.RGB3b, pdfaParams);

 

    if (pdfaResult.PDFADocument == null)

    {

        Console.WriteLine("ERROR: Could not convert " + sInput + " to PDF/A.");

    }

    else

    {

        pdfaResult.PDFADocument.Save(pdfaResult.PDFASaveFlags, sOutput);

    }

}

 

The PDFAConvertType parameter specifies the conformance level. PDFAConvertType.RGB3b produces a PDF/A-3b document using RGB color, which is the most commonly required conformance level for general document archiving. Setting AbortIfXFAIsPresent = true is important because XFA content cannot be made PDF/A compliant and the conversion should fail explicitly rather than produce a non-conformant result silently.

 

Always check whether pdfaResult.PDFADocument is null before saving. A null result means the source document contained content that could not be made PDF/A compliant under the chosen parameters, such as unsupported transparency modes or fonts that cannot be embedded. Logging this condition and routing the document for manual review is the appropriate handling in a production pipeline.

 

Expected Output

The output is a self-contained PDF/A document with embedded fonts, no external references, no JavaScript, and no encryption. It is suitable for submission to archival systems, regulatory bodies, and document management platforms that require PDF/A compliance.

 

Sample: PDFAConverter.cs on GitHub

 

ZUGFeRD: Structured Invoice Archiving

What Problem It Solves

ZUGFeRD is an invoice standard used primarily in Germany and broader European markets. It combines a PDF/A-3 document, which provides the visual invoice, with an embedded XML data file conforming to the ZUGFeRD schema. This allows both humans and automated systems to process the same invoice file without needing two separate documents.

 

Government and enterprise procurement systems in Europe are increasingly mandating ZUGFeRD-compatible invoices. If your organization issues or receives invoices in Germany or is working toward e-invoicing compliance with EN 16931, ZUGFeRD support is relevant to you.

 

The ZUGFeRDConverter Sample

ZUGFeRD conversion is a five-step process that builds on top of the PDF/A-3 converter. The sample takes two inputs: the visual invoice PDF and the ZUGFeRD-compliant XML invoice file. The output is a single PDF that is simultaneously a valid PDF/A-3 document and a valid ZUGFeRD invoice.

 

Step 1: Attach the XML Invoice to the PDF

Before converting to PDF/A-3, the XML invoice file is attached to the document using FileAttachment. This embeds the XML as an associated file within the PDF structure, which is what makes the resulting document machine-readable:

 

using (Document doc = new Document(sInputPDF))

{

    using (new FileAttachment(doc, sInputInvoiceXML))

    {

        // PDF/A-3 conversion happens inside this block

    }

}

 

The FileAttachment is created inside a using block that wraps the PDF/A-3 conversion. This ensures the attachment is present in the document structure at the time of conversion, which is required for the output to pass ZUGFeRD validation. Attaching the XML after conversion would produce a non-compliant result.

 

Step 2: Convert to PDF/A-3

With the XML attached, the document is converted to PDF/A-3 using the same CloneAsPDFADocument call used for standard PDF/A conversion. The PDFAConvertType.RGB3b target specifies PDF/A-3b, which is the correct conformance level for ZUGFeRD because it supports embedded file attachments (PDF/A-1 and PDF/A-2 do not):

 

PDFAConvertParams pdfaParams = new PDFAConvertParams();

pdfaParams.IgnoreFontErrors = false;

pdfaParams.NoValidationErrors = false;

pdfaParams.ValidateImplementationLimitsOfDocument = true;

 

PDFAConvertResult pdfaResult = doc.CloneAsPDFADocument(PDFAConvertType.RGB3b, pdfaParams);

 

if (pdfaResult.PDFADocument == null)

{

    Console.WriteLine("ERROR: Could not convert " + sInputPDF + " to PDF/A.");

}

else

{

    Document pdfaDoc = pdfaResult.PDFADocument;

    // Steps 3 and 4 operate on pdfaDoc

}

 

Always check for a null PDFADocument before proceeding. A null result means the source PDF contained content incompatible with PDF/A-3, and no further ZUGFeRD steps should be attempted on that document.

 

Step 3: Add ZUGFeRD XMP Metadata

PDF/A-3 alone does not make a document ZUGFeRD-compliant. Four specific XMP metadata properties must be written into the document under the ZUGFeRD namespace. These tell receiving systems the invoice type, the name of the embedded XML file, the ZUGFeRD conformance level, and the schema version:

 

string namespaceURI = "urn:ferd:pdfa:CrossIndustryDocument:invoice:2p0#";

string namespacePrefix = "zf";

 

document.SetXMPMetadataProperty(namespaceURI, namespacePrefix, "DocumentType",     "INVOICE");

document.SetXMPMetadataProperty(namespaceURI, namespacePrefix, "DocumentFileName", sInputInvoiceXML);

document.SetXMPMetadataProperty(namespaceURI, namespacePrefix, "ConformanceLevel", "BASIC");

document.SetXMPMetadataProperty(namespaceURI, namespacePrefix, "Version",          "2p0");

 

The DocumentFileName value must exactly match the filename of the attached XML file. If they do not match, ZUGFeRD validators will reject the document even if every other aspect of the structure is correct. The ConformanceLevel can be BASIC, COMFORT, or EXTENDED depending on how much structured data your XML invoice contains.

 

Step 4: Add the ZUGFeRD PDF/A Extension Schema

This is the step that most ZUGFeRD implementations get wrong. PDF/A-3 requires that any custom XMP namespace used in a document be described by a PDF/A Extension Schema embedded in the document's XMP metadata. The ZUGFeRD namespace is not part of the PDF/A standard itself, so the schema description must be added manually.

 

The sample appends the extension schema by reading the existing XMP metadata string, replacing the closing rdf:RDF tag with the schema definition block followed by a new closing tag:

 

string xmpMetadata = document.XMPMetadata;

string newXMPMetadata = xmpMetadata.Replace("</rdf:RDF>", extensionSchema);

document.XMPMetadata = newXMPMetadata;

 

The extensionSchema string is a block of RDF/XML that declares the four ZUGFeRD properties (DocumentFileName, DocumentType, Version, ConformanceLevel) under the pdfaExtension namespace. Each property entry specifies its name, value type (Text), category (external), and a human-readable description. This block is required for the document to pass PDF/A-3 validation when a non-standard namespace is present.

 

Step 5: Save

The document is saved using the save flags returned by the PDF/A conversion result, which ensures the correct linearization and metadata flags are applied:

 

pdfaDoc.Save(pdfaResult.PDFASaveFlags, sOutput);

 

Expected Output

A single PDF file that is simultaneously a valid PDF/A-3b document and a valid ZUGFeRD 2.0 BASIC invoice. The file contains the visual invoice as a human-readable PDF page, the XML invoice as an embedded attachment, and the required ZUGFeRD XMP metadata and extension schema. The output can be validated with a ZUGFeRD validator such as ZUV or Mustang and submitted to European procurement systems that require machine-readable invoices.

 

Note: The 2025 ZUGFeRD updates introduced revised schema requirements for newer Factur-X profiles. Review the current ZUGFeRD specification alongside the sample code to ensure your implementation meets the version requirements of your target system.

 

Sample: ZUGFeRDConverter.cs on GitHub

 

PDF/X: Standards for Print and Prepress

What Problem It Solves

PDF/X was developed to solve a specific problem in commercial printing: PDF files sent to a printer often contained missing fonts, unembedded images, undefined color spaces, or other elements that caused the job to fail at the press. PDF/X defines a set of requirements that guarantee a PDF is suitable for high-quality print production. The 'X' stands for eXchange, reflecting its purpose as a reliable interchange format between content creators and print service providers.

 

PDF/X is required by most commercial printers for print-ready files and is the standard format for submitting advertisements to publications. If you are building a workflow that accepts customer-submitted PDFs for printing, PDF/X validation and conversion is an important quality gate.

 

The PDFXConverter Sample

The PDFXConverter sample follows the same pattern as the PDF/A converter. CloneAsPDFXDocument creates a new PDF/X-compliant document using conversion parameters, and the result must be checked before saving:

 

using (Document doc = new Document(sInput))

{

    PDFXConvertParams pdfxParams = new PDFXConvertParams();

 

    PDFXConvertResult pdfxResult = doc.CloneAsPDFXDocument(PDFXConvertType.X4, pdfxParams);

 

    if (pdfxResult.PDFXDocument == null)

        Console.WriteLine("ERROR: Could not convert " + sInput + " to PDF/X.");

    else

    {

        pdfxResult.PDFXDocument.Save(pdfxResult.PDFXSaveFlags, sOutput);

    }

}

 

PDFXConvertType.X4 targets the PDF/X-4 standard, which supports transparency and is the most current and widely accepted PDF/X version for commercial print. Earlier versions such as X-1a are still required by some legacy workflows and are also available as conversion targets.

 

The PDFXConvertParams object can be configured to control how the converter handles elements that do not meet the PDF/X specification. In most cases the defaults are appropriate, but production workflows may want to enable stricter validation to catch documents that would fail at the press.

 

Expected Output

The output is a PDF/X-compliant document with all fonts embedded, color spaces explicitly defined, and transparency flattened if the target standard requires it. It is ready for submission to commercial printers, publication advertising systems, and prepress workflows.

 

Sample: PDFXConverter.cs on GitHub

 

Choosing the Right Standard

PDF/A, PDF/X, and ZUGFeRD serve distinct purposes and are not interchangeable. PDF/A is for documents that must be preserved and reproduced faithfully over time. PDF/X is for documents that must print correctly on commercial equipment. ZUGFeRD is for invoices that must be both human-readable and machine-processable. If you are unsure which standard applies to your workflow, the requirement is typically driven by the system or organization receiving the document.

 

Get Started

All three converters and more are part of the Adobe PDF Library. Get your free trial today.