The awkward thing about PDF/A is that conformance is completely invisible. The same LaTeX document, producing a PDF that looks identical, passes as A-2b and fails as A-1b — and when you actually run the check, the validator names the reason in one line: an ExtGState dictionary carries a ca key of 0.5 instead of 1.0. PDF/A is not a standard about pretty PDFs; it is an ISO requirement on the structure inside the file. This page covers what the standard actually demands, the two routes out of LaTeX (pdfx and \DocumentMetadata), and — the part usually skipped — how to find out whether the file you produced really conforms.
What PDF/A actually requires
PDF/A (ISO 19005) is an archival standard, and at its core it asks for one thing: the file must be completely self-contained. Someone opening it ten years from now has none of your fonts, none of your colour-management settings, and none of your other files — and it must still read correctly. Every concrete requirement follows from that. Fonts must be fully embedded (never rely on what the reader happens to have installed). No encryption (a lost key means a lost document). XMP metadata (title and author held inside the PDF as standard XML). An embedded output intent — an ICC profile (so that “this red” carries its own definition of the colour space). The same logic explains the suspicion of anything that reaches outside the file, such as a form’s submission target.
Producing PDF/A with pdfx — the ICC profile ships with it
One line, \usepackage[a-2b]{pdfx}, plus a \jobname.xmpdata file holding the title and author, is all it takes. You do not have to go and find an ICC profile. There was a time when you were told to fetch the sRGB profile from Adobe’s site, but in TeX Live 2024 the colorprofiles package ships one, and the log records the embedding as <<sRGB.icc>>. In the same log, ** pdfx: Metadata file document.xmpdata read successfully. confirms the metadata was picked up; forget the file and you get ** pdfx: No file document.xmpdata . Metadata will be incomplete! instead — though, as we will see, ignoring that warning still leaves you with a file that passes validation. Besides a-1b, a-2b and a-3b, the package offers the accessibility levels a-1a, a-2a, a-3a and the Unicode levels a-2u, a-3u. The print-oriented PDF/X flavours (x-1a and friends) come from the same package.
% document.tex
\documentclass{article}
\usepackage[a-2b]{pdfx} % reads document.xmpdata, embeds sRGB.icc
\begin{document}
Hello PDF/A.
\end{document}
% document.xmpdata -- a separate file, same base name
\Title{A Test Document}
\Author{Test Author}
\Keywords{LaTeX\sep PDF/A}A-1b vs A-2b vs A-4: whether transparency survives
The number is the PDF version underneath; the trailing letter is how strict. A-1 sits on PDF 1.4, A-2 on PDF 1.7, A-3 is A-2 plus permitted attachments, and A-4 sits on PDF 2.0. The trailing b is basic — the appearance must be reproducible, and no more. a is accessible, adding tagging (logical structure). u requires that the text map to Unicode. In practice the difference that bites is transparency. Take a document with two TikZ rectangles at opacity=0.5, build it with [a-1b]{pdfx} and run veraPDF: it fails ISO 19005-1:2005 clause 6.4, and the reason reads “An ExtGState dictionary contains the ca key (fill alpha) with value 0.5 other than 1.0”. Change nothing but the option to [a-2b] and it passes. A twenty-year-old fact — PDF 1.4 has no transparency — still governs what a repository will accept from you today.
| Level | Base PDF | What it means |
|---|---|---|
A-1b | PDF 1.4 | The narrowest. No transparency — any picture using opacity fails. Object streams are also forbidden |
A-2b | PDF 1.7 | Transparency passes. The default choice from LaTeX. JPEG 2000 is allowed too |
A-3b | PDF 1.7 | A-2b plus arbitrary file attachments. Asked for when raw data must travel inside the document |
A-4 | PDF 2.0 | The newest. The header must read %PDF-2.0, so pdfversion=2.0 is required. Not available from pdfx; use \DocumentMetadata |
The \DocumentMetadata route — match pdfversion or fail
The other route is \DocumentMetadata{pdfstandard=A-2b}, placed before \documentclass. It loads no package and accepts everything from A-1B to A-4 — but written plainly, only A-2b actually passes. pdfTeX writes PDF 1.5 by default, and for A-1b that is rejected because the cross-reference table is a stream (The document uses xref streams, clause 6.1.4), while for A-4 it is rejected because “File header %PDF-1.5 ... does not match the pattern %PDF-2.n” (clause 6.1.2). The fix lives in the same braces: add pdfversion=1.4 and A-1b passes; add pdfversion=2.0 and A-4 passes. Add pdfversion=2.0 to A-2b, however, and it now fails with “%PDF-2.0 ... does not match the pattern %PDF-1.n” — because A-2 is defined on PDF 1.7 and no higher. Each standard has a different right answer, which is exactly the kind of place people get wrong.
| What you wrote | Left at the default (PDF 1.5) | With pdfversion added |
|---|---|---|
pdfstandard=A-1b | Fails — clause 6.1.4, “uses xref streams” | Add pdfversion=1.4 and it passes |
pdfstandard=A-2b | Passes — the one combination that needs nothing added | Adding pdfversion=2.0 makes it fail (clause 6.1.2) |
pdfstandard=A-4 | Fails — clause 6.1.2, “header %PDF-1.5” | Add pdfversion=2.0 and it passes |
So why does pdfx at a-1b pass while still writing a PDF 1.5 header? The answer is in the package source. Line 515 of pdfx.sty carries the comment “PDF/A-1b doesn't allow object compression”, and the lines right after it set \pdfobjcompresslevel=0. Rather than argue about the number in the header, it simply stops using the feature the standard forbids. That is the difference in character between the two routes. pdfx is a package that bends the output until it fits the standard; \DocumentMetadata is a kernel mechanism that declares which standard you are claiming — and leaves it to you to make the contents live up to the claim. The other difference is metadata: pdfx reads .xmpdata automatically, whereas \DocumentMetadata fills in neither title nor author on its own. You supply those yourself with \hypersetup{pdftitle=...} and friends (see the bookmarks and metadata page).
% before \documentclass -- the version must match the standard
\DocumentMetadata{
pdfstandard = A-4,
pdfversion = 2.0, % A-4 needs a %PDF-2.0 header
lang = en
}
\documentclass{article}
% for A-1b it is pdfversion = 1.4 instead;
% for A-2b, leave pdfversion out entirely.Verifying what you produced: veraPDF, and what a pass does not mean
There is no way to learn from the LaTeX side whether your file conforms. The log says only that you asked for PDF/A output; whether the result actually satisfies the standard is a separate question. That verdict comes from a PDF/A validator, and the de facto standard is veraPDF, the open-source reference checker. It is not part of TeX Live and has to be installed separately. Using it is simple: verapdf file.pdf reads the XMP identifier inside the PDF, works out which level to check against, and answers in one line — PASS ... 2b or FAIL ... 1b. Pass -f 1b to force a level instead. When it fails, the thing to read is the clause number: 6.4 (transparency), 6.1.2 (header version), 6.3.3 (annotation appearances) point straight at what has to change.
# auto-detect the level from the file itself
verapdf document.pdf
# -> PASS /path/document.pdf 2b
# force a level (useful to see what a stricter one would say)
verapdf -f 1b --format text document.pdf
# -> FAIL /path/document.pdf 1b
# the XML report names the clause and the exact reason
verapdf -f 1b document.pdf > report.xmlOne fact here will save you regret later: passing validation does not mean your metadata is acceptable. Forget the .xmpdata file, leave the ** pdfx: No file ... Metadata will be incomplete! warning unaddressed, and run veraPDF on the result: it answers PASS ... 1b. With no title and no author in the file. Conformance level b requires that XMP metadata be structurally present and correct, not that it be filled in. The empty fields are exactly what frustrates a librarian or a repository curator, so treat a validator pass and a finished submission as two different things. It also pays to keep the habit of checking font embedding with pdffonts (the page on producing PDF goes into this).
Interactive forms and PDF/A do not mix
A single input field made with hyperref’s Form environment is enough to fail PDF/A validation. Put one \TextField in a document, build it with [a-2b]{pdfx}, run veraPDF, and it fails clause 6.3.3: “An annotation does not contain an appearance dictionary”. hyperref leaves the drawing of the field to the viewer (that is what NeedAppearances means), while PDF/A insists that appearances be baked into the file. Add a submit button and the failures multiply, now including clause 6.4.1, “A Widget annotation dictionary shall not contain the A or AA keys” — attaching an action to a form control is itself forbidden. On reflection this is exactly what you would expect: an archival standard cannot bless a widget whose job is to talk to the outside world. If a submission target asks for both PDF/A and a fillable form, the requirements contradict each other, so ask before you build it.
Tagged PDF and PDF/UA: accessibility is still a moving target
The tagging demanded by the a levels of PDF/A means embedding the logical structure — headings, paragraphs, lists, reading order, alt text — into the PDF, so that a screen reader can navigate it. The standalone accessibility standard is PDF/UA (ISO 14289), whose second part is PDF/UA-2. On the LaTeX side the implementation is the LaTeX Project’s tagpdf package (by Ulrike Fischer); the copy in TeX Live 2024 is version 0.98x, dated 2024-02-29 — a version number beginning with zero tells the whole story. The low-level commands for placing tags by hand, such as \tagstructbegin, come from that package. Sure enough, writing \DocumentMetadata{tagging=on} on the TeX Live 2024 kernel (LaTeX2e 2023-11-01) produces ! LaTeX Error: The key 'document/metadata/tagging' is unknown and is being ignored. In this release the switch is testphase=phase-III, which does get pdfinfo to report Tagged: yes. As the name says, this is a test-phase facility, so the spelling will change. Check the current documentation before relying on it.
And one thing deserves an honest note: satisfying both at once is not yet easy. Taking a document that passes on pdfstandard=A-2b alone and adding testphase=phase-III, veraPDF came back with a failure at clause 6.2.11.5: “Glyph width 333 in the embedded font program is not consistent with the Widths entry of the font dictionary (value 334.2)”. That is not a defect in the tag structure but a mismatch in the embedded font’s glyph widths. If someone asks you for a tagged PDF/A, run veraPDF before you send it — assuming it will work is how you end up stuck the night before a deadline.
What to do before you submit
- Ask which level first. If you are simply told “PDF/A”, find out whether that means A-1b or A-2b. With any transparency in your figures, that difference decides acceptance.
- When in doubt,
pdfxata-2b.\usepackage[a-2b]{pdfx}plus title and author in\jobname.xmpdata. It is the one combination that passes with nothing else added. - If A-4 is required, use
\DocumentMetadata{pdfstandard=A-4,pdfversion=2.0}.pdfxstops at A-3 and cannot produce A-4. - Do not forget the
.xmpdata. Validation will pass without it, so go and look for theMetadata will be incomplete!warning in the log yourself. - Run
verapdf document.pdfonce before sending, every time. It is not in TeX Live, so install it separately. On failure, read the clause number (6.4,6.1.2,6.3.3). - Give up on forms. A document with fillable fields will not conform to PDF/A.