Skip to content

fix(pdfa): XMP from /Info, Print flag on links and widgets - #53

Open
serpentblade wants to merge 3 commits into
dskripchenko:mainfrom
serpentblade:fix/pdfa-conformance
Open

serpentblade wants to merge 3 commits into
dskripchenko:mainfrom
serpentblade:fix/pdfa-conformance

Conversation

@serpentblade

Copy link
Copy Markdown
Contributor

Two PDF/A fixes found by validating documents that use metadata() and hyperlinks with veraPDF 1.30.3. The existing conformance references set neither, so CI never saw them. One commit per fix, plus a third that adds references covering both.

1. XMP packet built from the /Info values. PDF/A requires every /Info entry to match its XMP property (ISO 19005-1 §6.7.3). The XMP was built from PdfAConfig alone: producer always dskripchenko/php-pdf, dates the render time, no Subject, Keywords or Creator. Any document that set a producer, creator or creation date failed PDF/A-1b, and the XMP changed on every render, even with a fixed creation date.

  • /Info is resolved once and the XMP written from it: dc:title, dc:creator, dc:description, pdf:Keywords, xmp:CreatorTool, pdf:Producer, xmp:CreateDate, xmp:ModifyDate.
  • The config's title and author still apply when the metadata has none, and now also go into /Info, as PdfXConfig's do.
  • Empty properties are left out instead of written as empty elements.
  • /Info dates are written in UTC. A date in another time zone was written with its local clock time but a +00'00' offset, so hours off.
  • PdfAConfig::xmpMetadata() keeps its signature and gains an optional $info array.

2. Print flag on links and form widgets. PDF/A requires /F with Print set on every annotation except a Popup (19005-1 §6.5.3, 19005-2 §6.3.2). Links and widgets had no /F, so any PDF/A document with a hyperlink or form field failed on 1b, 2b and 2u. All five link kinds and every widget now carry /F 4, as the signature widget already did.

3. Conformance references. pdfa-1b-annotated and pdfa-2b-annotated have external and internal links and every standard /Info entry. Both fail veraPDF without the fixes and pass with them, and verapdf.sh now checks them.

Markup annotations (text notes, highlights and so on) also lack /F, but they have no appearance streams either, which PDF/A requires as well (6.3.3), so I left them for a separate change.

Tests added; full suite and phpstan pass. Every reference in scripts/conformance passes veraPDF.

🤖 Generated with Claude Code

serpentblade and others added 3 commits November 1, 2026 16:26
PDF/A requires every /Info entry to be equivalent to its XMP property
(ISO 19005-1 §6.7.3, ISO 19005-2 §6.6.2.3). The XMP packet was built
from PdfAConfig alone: its producer was always dskripchenko/php-pdf,
its dates the time of the render, and Subject, Keywords and Creator
were missing. A document that set metadata() — any producer, creator or
creation date — failed veraPDF on PDF/A-1b (6.7.3-1, -6, -7), and the
packet changed on every render, so the output was not reproducible
even with a fixed creation date.

The /Info values are now resolved once and the XMP packet is written
from them: dc:title, dc:creator, dc:description, pdf:Keywords,
xmp:CreatorTool, pdf:Producer, xmp:CreateDate and xmp:ModifyDate. The
config's title and author still apply when the metadata has none, and
are written to /Info as well, as PdfXConfig's are. Empty properties are
left out instead of written as empty elements.

/Info dates are written in UTC. A creation date in another time zone was
written with its local clock time but a +00'00' offset — hours off, and
a different instant from the XMP date.

PdfAConfig::xmpMetadata() keeps its signature and gains an optional
$info array.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Link annotations and form-field widgets were written without /F, so
their Print flag was off. PDF/A requires /F with Print set on every
annotation but a Popup (ISO 19005-1 §6.5.3, ISO 19005-2 §6.3.2), so a
PDF/A document with a hyperlink or a form field failed veraPDF
(6.5.3-2 on 1b, 6.3.2-1 on 2b and 2u). Without the flag a printed form
also leaves its fields blank.

All five kinds of link and every widget (text, checkbox, push, submit
and reset buttons, combo and list boxes, radio buttons) now carry
/F 4, as the signature widget already did.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pdfa-1b-annotated and pdfa-2b-annotated have an external and an
internal link and set every standard /Info entry (Title, Author,
Subject, Keywords, Creator, Producer). The existing references set
neither, which is how the two previous fixes went unnoticed: both new
files fail veraPDF without them and pass with them. verapdf.sh checks
them with the others.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant