PDF Validation
A PDF that should be accessible or archivable has to prove it: an accessibility audit, a public authority or an archive system checks the file, not the code that created it. Validation answers that question before your documents leave the application. With the TXTextControl.PDF.Validation package, you check PDF documents against PDF/UA, read the findings in code, store them as JSON reports and stop documents that fail.
What makes a document accessible in the first place is described in PDF/UA. The verification of digital signatures is the subject of Signature Validation.
The Validation Package
TXTextControl.PDF.Validation is a .NET library from Text Control that validates PDF/UA documents. It's published on nuget.org, not on the Text Control Private NuGet Feed:
dotnet add package TXTextControl.PDF.Validation 34.1.0
- Target framework. Version 34.1.0 targets .NET 10, so the project that uses it must target .NET 10.
- License. The package may be used free of charge by individuals and organizations that own a valid TX Text Control license, and its license must be accepted when the package is installed.
- Independent of ServerTextControl. The validator reads the PDF file or its bytes directly, so a document doesn't have to be loaded into TX Text Control to be checked.
Validate a PDF File
The validator is the static class PdfUaValidator in the TXTextControl.PDF.Validation namespace. The following program validates a PDF file and prints the findings that didn't pass:
using TXTextControl.PDF.Validation;
using TXTextControl.PDF.Validation.Model;
Report report = PdfUaValidator.Validate("Documents/invoice.pdf");
Console.WriteLine($"Status: {report.Status}, title: {report.DocumentTitle}, language: {report.DocumentLanguage}");
foreach (Finding finding in report.Findings)
{
if (!finding.Passed)
{
Console.WriteLine($"{finding.Severity} {finding.RuleId} ({finding.Category}): {finding.Message}");
}
}
The code works as follows:
Validatetakes the path of a PDF file or the PDF as a byte array and returns aReportof theTXTextControl.PDF.Validation.Modelnamespace.- The
Reportcontains theStatus, theFindingsand the details the validator extracted, such asPdfVersion,DocumentTitle,DocumentLanguage,StandardDecls,TableSummaries,Links,FiguresandForms. - Each
Findinghas a stableRuleId, aCategorysuch as Metadata, Structure Tree, Fonts or Security, aSeverityofInfo,WarningorError, whether itPassedand aMessage.
The Status summarizes the result:
| Status | Meaning | IsPass |
|---|---|---|
Passed | No blocking errors and no warnings | true |
CompletedWithWarnings | No blocking errors, but one or more warnings | true |
Failed | One or more blocking errors | false |
Blocked | The validation couldn't run completely, for example because the PDF is encrypted | false |
Only failed findings with the severity Error make a document fail. Failed warnings lead to CompletedWithWarnings.
Stop Documents That Fail
The best moment to validate is right after a PDF was created or received and before it's archived, emailed or handed to another system. The following program creates a PDF in memory, validates the bytes and writes the PDF only when it passes; otherwise, it stores the report as JSON:
using TXTextControl;
using TXTextControl.PDF.Validation;
using TXTextControl.PDF.Validation.Model;
byte[] pdf;
using (ServerTextControl tx = new ServerTextControl())
{
tx.Create();
tx.Load("Documents/invoice.docx", StreamType.WordprocessingML);
tx.DocumentSettings.DocumentTitle = "Invoice INV-2025-001";
tx.Save(out pdf, BinaryStreamType.AdobePDF);
}
Report report = PdfUaValidator.Validate(pdf);
if (report.Status is ValidationStatus.Failed or ValidationStatus.Blocked)
{
// Keep the details for the people who fix the template
File.WriteAllText("invoice-report.json", PdfUaValidator.ToJson(report, indented: true));
throw new InvalidOperationException($"The invoice didn't pass the PDF/UA validation: {report.Status}");
}
File.WriteAllBytes("invoice.pdf", pdf);
Console.WriteLine($"invoice.pdf saved: {report.Status}");
The code works as follows:
- The document is saved to a byte array with Save and
BinaryStreamType.AdobePDF, so it can be validated before it's written anywhere. ValidationStatusis the type ofReport.Status.FailedandBlockedstop the document.ToJsonserializes the report, withindented: truein a readable layout. The JSON contains the status, the findings, the extracted tables, links, figures and forms and the diagnostics of signatures and encryption.
The same check fits into automated tests and build pipelines: it finds templates that lose alternative texts, form labels or the document language after a change, and reports of two releases can be compared. The blog article Validating PDF/UA Documents in .NET C#: A Practical Guide builds a validation service for such pipelines. A check of the document before saving, as in Check a Document Before Saving, finds missing descriptions earlier, and a review by people remains necessary: a validator confirms that an alternative text exists, not that it describes the image well.
What the Validator Checks
The validator covers these areas of a PDF document:
- PDF syntax basics, such as the header and the cross-reference table
- The PDF/UA conformance declaration, the document title and XMP metadata
- The natural language of the document
- Tagged PDF markers, the structure tree and role mapping
- Fonts, embedded font references and Unicode mappings
- Alternative descriptions of figures
- Links and their descriptions, annotations and actions
- Form fields and their tooltips
- Tables, their summaries and header relationships
- Embedded files and their file specifications
- Page tabs, the display of the document title, optional content, XFA and encryption
Some rules the findings refer to:
| Rule | Checks |
|---|---|
UA-CONFORMANCE | The PDF/UA-1 declaration in the XMP metadata |
UA-TITLE | A document title in the document information or the XMP metadata |
UA-LANG | The primary language of the document |
UA-MARKED, UA-STRUCT | The tagged PDF marker and the structure tree |
UA-TEXT-MAPPING | Text that maps to Unicode |
UA-FIG-ALT | Alternative texts of figures |
UA-LINK-DESC | Texts or tooltips of links |
UA-FORMS-TU | Tooltips of form fields |
UA-TABLE-A-SUMMARY, UA-TABLE-HEADERS | Table summaries and header cells |
PDFA-CONFORMANCE | Whether a PDF/A declaration is present |
Some checks are exact validations of the document model; others are conservative signals that return informational findings instead of failures, for example for parts of the structure tree that need a review. The package doesn't validate PDF/A conformance: PDFA-CONFORMANCE only reports whether the document declares it.
Encrypted and Signed PDF Documents
- Encrypted PDF documents aren't decrypted. Their report has the status
Blocked,IsPassisfalse,report.Diagnostics.Encryption.IsEncryptedistrueand theUA-SECURITY-ENCRYPTEDfinding fails. The validation stops before the content, so an encrypted document never passes by mistake. Validate a PDF before you protect it with UserPassword. - Signed PDF documents are validated normally, and
report.Diagnostics.Signaturescontains the results of their signatures, which don't affect whether the document passes PDF/UA. Signature Validation describes these results.
Other Validators
- PAC, the PDF Accessibility Checker, is a desktop application that checks PDF documents against PDF/UA.
- veraPDF validates PDF/A documents and reports, for example, embedded files without a proper MIME type.
- Adobe Acrobat shows the conformance of a PDF/A document in its Standards panel and the tags of a document in its accessibility tags panel.
- ZUGFeRD and Factur-X invoices are checked with validation services for these formats, as Attachments mentions.
Next Steps
- PDF/UA: create documents that pass the validation.
- PDF/A: create archivable PDF/A-3a documents.
- Document Metadata: set the title the validator checks.
- Signature Validation: verify the digital signatures of PDF documents.