Conversion and verification looked only at an action's own /S. An allowed
action (a GoTo, say) whose /Next held a JavaScript or other forbidden
action written directly inside it was kept, and verification never looked
at actions written directly in a catalog /OpenAction or an annotation /A.
Both now follow /Next through the actions written inside an action (an
indirect /Next is an object of its own, checked as one), within a bound,
and conversion removes the whole chain.
verify found each annotation's page by copying and searching every page's
/Annots array again for each annotation, so a page with many annotations
cost quadratic time. The annotation-to-page map is built once (the first
page that lists an annotation keeps it, as before).
content_colour parsed each content stream into a full list of operators
before looking at any of them, so a small compressed stream of millions of
tiny operators became gigabytes of parsed operators in memory. The content
parser's loop is now an iterator (pdfcraft_content::ops), which parse
collects; preflight reads it one operator at a time and stops once gray,
RGB and CMYK are all found.
Reading the colour space from an ICC header when /N is missing decoded
the whole profile under the general 1 GiB stream limit to look at four
bytes. The profile now decodes within 16 MiB; a larger one leaves the
component count unknown.
* fix(preflight): identify standards by XML namespace
* fix(preflight): bound XMP attribute parsing work
* fix(preflight): cap XMP during stream decoding
* Preflight: read the PDF/A and PDF/UA identification by its usual prefix when the XMP can't be parsed as XML
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
uses_device_colour found content streams by their dictionaries and split
their bytes on whitespace. It skipped form XObjects with /Type /XObject and
tiling patterns, missed `cs`/`CS` with a device space, inline images and
operators before a delimiter, and took a `k` in a string, a comment, inline
image data, a font program or an ICC profile for DeviceCMYK. A CMYK logo in a
form therefore got an sRGB output intent and passed pdfa_verify.
Content streams are now found by role (page /Contents, Type 3 glyphs, forms,
appearance streams, tiling patterns) and read with pdfcraft_content::parse.
Reading stops once all three device spaces are seen.
The PDF/A device-colour scan split content streams only on spaces and
line feeds, so `0 0 0 1 k` written with carriage returns, tabs, form
feeds or NULs between the tokens went unseen: verify reported no
DeviceCMYK, and convert gave the CMYK page an sRGB output intent.
Split on all six whitespace characters of ISO 32000-2 §7.2.3, using the
lexer's own `is_whitespace` (now exported from pdfcraft-cos) instead of
a second list.
Adds tests::device_colour_is_found_after_any_whitespace, which fails
before this change; its gray and RGB controls check that those pages
still get the sRGB output intent.
* i18n: let the layers below hand their sentences over, so they can be translated
The accessibility findings, the PDF/A problems, the signature details, the
page-range mistakes and the edit labels were English in all ten languages,
because matching their wording from the UI with a tl! literal would break
silently whenever the engine changed it.
So each layer now hands the wording over instead, apart from the document's
own words: a WORDINGS list of every sentence it can say, with holes in it, and
said(&words), which looks the wording up through the closure it is given and
fills the holes in a single pass. in_english changes nothing, for the CLI and
the tests; the UI passes &i18n::words, a catalog lookup. A wording with no
entry comes back as it stands, which is the English, so the nine catalogs this
does not touch read exactly as before.
a11y::report_html takes a language tag and a words closure, so a saved report
reads the way the panel read, down to its lang attribute. print::PrintError
gained a variant per thing a person can be wrong about, with the numbers apart
from the words; faults rather than mistakes keep their own text.
Spanish translates all of it (107 entries). spanish_covers_what_the_engine_says
requires an entry per wording in the eight lists and
spanish_keeps_the_holes_in_what_the_engine_says requires the holes to survive
the translation, so the catalog cannot fall behind the engine unnoticed.
No new tl! literal, so the Chinese, French and Russian UI-literal gates are
unaffected.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* Sign tests from #1099: compare against the &'static str kinds
* Camera tests: undo returns a Label now
---------
Co-authored-by: Fernando Areán <soporte@codebit.es>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* PDF/A: no sRGB output intent for CMYK documents, and verify checks the intent's colour space (#667)
pdfa_convert always added an sRGB output intent when there was none,
even for documents whose only content is DeviceCMYK, and pdfa_verify
then called them compliant: it only checked that some PDF/A output
intent existed. ISO 19005-2 6.2.4.3 allows DeviceCMYK only with a CMYK
output intent, and DeviceRGB only with an RGB one.
- verify reads the PDF/A output intent's destination profile (/N, else
the ICC header's data colour space) and reports DeviceCMYK under a
non-CMYK intent and DeviceRGB under a non-RGB one (6.2.4.3, not
fixable).
- convert adds the generated sRGB intent only when the document has no
DeviceCMYK; a CMYK document keeps the existing "needs a CMYK output
intent (not added automatically)" issue instead of a wrong intent.
- Device colour detection tells gray, RGB and CMYK apart (gray works
under any intent).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* PDF/A: DefaultRGB/DefaultCMYK resources satisfy the output-intent colour check
ISO 19005-2 6.2.4.3 accepts device colour drawn through a default colour space under any output
intent.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: DWAA1660 <DWAA1660@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
The app, crates, binaries, bundle id, packaging, icons, screenshots and docs are now
PdfCraft / pdfcraft (repo storytold/pdfcraft). On first launch the desktop app moves the
PrintCraft settings and crash-recovery folders to the new name, and both apps read settings
saved under the old storage key, so upgrades keep recent files, preferences and unsaved work.
The signing test fixtures keep their PrintCraft subject names (they are binary).
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
annot, compare, content, cos, export, geom, model, ocr, preflight, print and redact have no
production `unwrap`/`expect`/`panic!`/`unreachable!`/`todo!`/`unimplemented!`. The attribute
keeps it that way.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>