PDFPipe

Accessibility and structure / Tagged PDF

How to tell if a PDF is tagged

A tagged PDF carries a second, invisible copy of itself: a tree of headings, paragraphs, lists and cells that says what the content is, rather than where the ink goes.

Where this API stands

This API does not produce this standard, and there is no option that would. What follows is what the requirement actually is and where a rendered document stands against it. This API exposes no option that controls tagging: there is nothing to switch on, nothing to switch off, and nothing in the response that reports on it. Whether a particular file carries a /StructTreeRoot depends on the source markup and on renderer behaviour that no option here pins, so the only correct thing to say about any given document is to go and look. What you do control is the markup: a heading written as `<h2>` is something a tagger can promote, and a heading written as a div with a large font size is not, whatever any renderer does with it.

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 catalogue has /MarkInfo << /Marked true >>, which is the file's own claim that it is tagged.
  • The catalogue has a /StructTreeRoot pointing at the top of the structure tree.
  • Page content is wrapped in marked content operators (BDC and EMC) carrying an /MCID, so each run of text can be tied back to a structure element.
  • Each page has a /StructParents entry giving the index into the /ParentTree that maps its marked content back up the tree.
  • Any non-standard structure element type is mapped to a standard one through /RoleMap, so a reader that has never seen your tag names still knows what they mean.

Who asks for this

Anyone downstream of an accessibility requirement, and also anyone doing serious text extraction. Tags are what let a tool recover the reading order and the table structure of a document rather than guessing from coordinates, which is why data extraction vendors care about them as much as accessibility auditors do. It is also the difference between PDF/A-1b and PDF/A-1a, so an archiving requirement can pull it in sideways.

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
# Does this file have a structure tree at all?
mutool show invoice.pdf trailer/Root | grep -i structtreeroot

# The fuller picture, including MarkInfo and the page ParentTree indices.
qpdf --json=latest invoice.pdf | jq '.qpdf[1]."obj:1 0 R".value'

What to do about it

Check first, then decide. If the files you get back already carry a tree, your job is fixing what is wrong in it rather than creating it, which is a much smaller job. If they do not, tagging is a post-processing step and the tool choice is the same one the PDF/UA page describes. Either way, going back and replacing presentational markup with semantic markup is work that pays off before the tagger runs, not after.

How to check a file rather than assume

`qpdf --json=latest file.pdf` dumps the object structure, and the presence or absence of /StructTreeRoot in the catalogue answers the question in one look. `mutool show file.pdf trailer/Root` is quicker if you only want that one entry. Acrobat's own accessibility panel will say "no tags available" in plain words if there is nothing there.

The mistake people make here

Assuming that because the text is selectable, the document is tagged. Selectable text means the glyphs carry a character mapping, which is a completely separate feature. A PDF can have perfectly selectable, searchable, copyable text and no structure tree whatsoever, and this is the normal state of most PDFs in the world.

Frequently asked

Does this API produce Tagged PDF?

Not produced by this API. This API exposes no option that controls tagging: there is nothing to switch on, nothing to switch off, and nothing in the response that reports on it. Whether a particular file carries a /StructTreeRoot depends on the source markup and on renderer behaviour that no option here pins, so the only correct thing to say about any given document is to go and look. What you do control is the markup: a heading written as `<h2>` is something a tagger can promote, and a heading written as a div with a large font size is not, whatever any renderer does with it.

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.