PDFPipe

Metadata, versions and file structure / PDF version numbers

PDF version numbers and what sets them

The version in the file header and optionally in the catalogue, which says which features a reader must understand to open the file correctly.

Where this API stands

This API does part of what the standard asks for, and the paragraph below is the whole of it rather than a summary of it. There is no version option on this API and nothing that lets you target a particular one. One behaviour is worth knowing about: password protection applies 40-bit RC4 encryption as specified in the Adobe PDF Reference 1.4, using the standard security handler at /V 1 and /R 2. That is a 1.4-era mechanism, so a password-protected file from here is readable by any reader that handles 1.4, and it is not the AES-256 that a modern security policy is likely to be asking for. The `pdf_a` option is similarly anchored: it writes a PDF/A-1b identification packet, and PDF/A-1 is defined against PDF 1.4.

What the standard requires

The requirements as a checker enforces them, rather than as a procurement document paraphrases them. A file satisfies all of these or it satisfies none of them.

  • The first line of the file is %PDF-1.x or %PDF-2.0, and this is the version a reader uses when the catalogue does not override it.
  • A /Version entry in the catalogue takes precedence over the header, which is how an incremental update can raise the version without rewriting the first line.
  • The version has to be at least as high as the newest feature used: transparency needs 1.4, object streams and cross-reference streams need 1.5, AES-256 encryption needs 2.0.
  • PDF/A-1 is defined against PDF 1.4, PDF/A-2 and PDF/A-3 against PDF 1.7, and PDF/A-4 against PDF 2.0, so a conformance claim implies a version floor.
  • Declaring a version lower than the features used is a real defect: an older reader will accept the file on the strength of the header and then misread the parts it does not know about.

Who asks for this

Anyone with a downstream system that pins a version, which in practice means archiving systems, some regulators, and the occasional customer with a reader from a decade ago. It also comes up when a validator reports a feature that is newer than the header claims.

What it looks like in a file

The concrete form of the thing being described, so you can recognise it in a document you have been handed rather than only in a specification.

bash
$ head -c 8 invoice.pdf
%PDF-1.4

# But the catalogue can override the header, and an incremental update
# is exactly the situation where they disagree. Check both.
$ mutool show invoice.pdf trailer/Root | grep -i version

# Normalising for a downstream system that pins a version:
$ qpdf --force-version=1.7 invoice.pdf normalised.pdf

What to do about it

If a downstream system pins a version, normalise after the render rather than trying to hit the target during it. `qpdf --force-version=1.7 in.pdf out.pdf` sets the header, and Ghostscript's pdfwrite device with -dCompatibilityLevel rewrites the file against a chosen version, which is heavier but actually converts the features rather than relabelling them. Relabelling a file that uses newer features is worse than leaving it alone.

How to check a file rather than assume

`head -c 8 file.pdf` shows the header line. `mutool show file.pdf trailer/Root` shows a /Version entry if one is overriding it. `qpdf --show-npages --json=latest` reports the version it parsed, which is the one a real reader would use.

The mistake people make here

Assuming the header is the truth. A catalogue /Version silently overrides it, and an incremental update, which is what appending a signature or applying encryption does, can leave a header from before the change. If you are checking a version programmatically, check both.

Frequently asked

Does this API produce PDF version numbers?

Partly, and the page says how far. There is no version option on this API and nothing that lets you target a particular one. One behaviour is worth knowing about: password protection applies 40-bit RC4 encryption as specified in the Adobe PDF Reference 1.4, using the standard security handler at /V 1 and /R 2. That is a 1.4-era mechanism, so a password-protected file from here is readable by any reader that handles 1.4, and it is not the AES-256 that a modern security policy is likely to be asking for. The `pdf_a` option is similarly anchored: it writes a PDF/A-1b identification packet, and PDF/A-1 is defined against PDF 1.4.

Can I turn on the pdf_a option and be done?

No. The option writes an XMP packet declaring PDF/A-1b into the document catalogue, and the render response comes back carrying a warning that says in as many words that this is best-effort and that full conformance requires tagged structure and an embedded ICC profile. It is a claim written into the file, not a certificate earned by it, and a validator checks the claim against the bytes. Read the warning array in the response rather than taking the absence of an error as a pass.

Should I convert before rendering or after?

After, always. A conformance converter rewrites colour, embeds profiles, sets boxes and stamps metadata on a finished PDF. Trying to satisfy a conformance target from the source side means guessing at what the converter would have done, and the guesses that go wrong are expensive: flattening transparency you did not need to flatten changes what the page looks like.

Standards this one is confused with

The neighbours that matter are the ones people mistake for this, not the ones that sort next to it.

Conformance is decided after a file exists. Render the document, then check it, then convert only what the checker actually flags.