* fix(preflight): follow every /Next action and bound colour and intent work
Action chains followed an indirect /Next only when it named an array, and
skipped references inside a /Next array, so a forbidden action one indirect
hop behind an allowed one survived both verification and conversion; an
untyped dictionary with /P and /K was exempt from action checks whatever its
/S. Both are now followed and checked, and arrays are borrowed instead of
deep-copied per chain. Conversion treats a /Subtype /Widget without /Type as
an annotation, and takes forbidden annotations off their pages in one pass.
Device-colour inspection decoded each content stream with the 1 GiB
per-stream default and no total; it now shares one 1 GiB DecodeBudget and
reports unread content instead of treating it as clean. Type 3 CharProcs
shared by many fonts are read once, and declared() reads each output intent
once (at most 8).
* address review: no sRGB intent when colour couldn't all be read; count array reads in action chains; declare every output intent
* address review: cut only an over-long identifier; test with a filter that can't be read
* review: leave untyped structure elements out of the forbidden-action check
* merge main, keep both
* address review: a wide direct /Next array is refused before it is queued; queued references are resolved through aliases
* Print: flatten transparent sheets for GDI (v3) printer drivers
Windows sends a job for a GDI (v3) driver through its XPS-to-GDI
conversion, which fails on soft masks (#6155), prints halos around them
(#5838) or prints transparency as black boxes (#5940). XPS (v4) drivers
print the same pages correctly.
spooler_copy takes a flatten_transparency flag. With it, after greying
and before tiling, each sheet that uses transparency is replaced by an
opaque picture of itself (spooler::flattened): rendered at 300 dpi, lower
for a sheet past 80 MP or 16000 px a side, in tiles of at most
2000 x 2000 px, each an RGB Flate image over white, so no tile reaches
Windows' 2^22 px image cap and tiling leaves them alone. The sheet keeps
its boxes and rotation; its group and annotations go. Sheets without
transparency stay vector.
pdfcraft-preflight gets page_uses_transparency, the PDF/A transparency
search without counting a transparency group on its own, which Word
puts on every page.
Both callers pass false until the GDI-driver check lands.
* Print: flatten transparent sheets only for a GDI (v3) printer driver
spool::xps_driver / spool::gdi_driver read whether the printer's driver renders XPS itself,
through craft-print's new xps_driver (storytold/craft-libs#804, winprint
storytold/winprint.rs#21). The Print dialog and doc_print pass gdi_driver to spooler_copy's
flatten_transparency, so XPS (v4) drivers, PDF printers among them, keep vector sheets.
craft-print pinned to the craft-libs#804 branch, winprint to #21's, until they merge.
* craft-print 60ede99985ef1e5df87a2aca66ed538eb23dec99: craft-libs main with #804 (xps_driver), winprint bc06a7c4 (#21)
* Cargo.lock: the two winprint entries in Cargo's order (by source, after the re-pin)
The header check reports a file without the binary comment, and Save as PDF/A then makes the next save a full one. The known-answer documents and the generation-repair file predate it: the minimal document got a 6.1.2 issue, and an undamaged file needed a full save for its header instead of being saved incrementally. They now start with the comment, as the crate's unit test documents do.
verify() went past clippy's cognitive complexity limit once every check was in it. The checks move as they are into helpers, run in the same order, so the issues and their order don't change.
The test now places each of them in the catalog's /OpenAction (direct and
by reference), in an action of its own that a page's /AA refers to, and in
a link's /A, and adds a Named action whose /N refers to /Print. Save as
PDF/A removes each and keeps a Named page move.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
A 6.6.2.3.1 issue now names the metadata stream that holds the property
and carries its ObjRef in Issue::object, so a property mistyped in two
streams is two issues. Wordings that name several things use named holes,
filled in one pass. The message names the value type the XMP
Specification gives the property (Integer, Lang Alt, seq ResourceEvent,
Dimensions), and, when the packet writes the property with another prefix
than the preferred one or none, the name as written.
Tests also show that a property is known by its namespace URI, and that a
property a predefined namespace doesn't define, or a namespace that isn't
predefined, is left alone.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyDBXygTf7jcqdsjcfn
The unknown-blend-mode issue carries its page, as the transparency issue
does. Pages keep what was found under the indirect objects they share
(resources, forms, patterns, Type 3 fonts, graphics states) in a
document-wide map, filled only from objects read to the end, so the next
page takes them in one read. The walk reads objects in place instead of
copying resources dictionaries and their entries, and gathers at most 32
unknown blend mode names.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyDBXygTf7jcqdsjcfn
A namespace URI, prefix, name, value type, type or category entry that is
there but empty names nothing; it is now reported with its own wording.
Descriptions stay free to be empty Text.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyDBXygTf7jcqdsjcfn
6.6.2.3.3 findings are now reported per description instead of once per
entry name: each names the schema by its pdfaSchema:namespaceURI (or #n),
the property, value type or field by its own name (a field as type/name),
and the metadata stream, with Issue::object set. A misused prefix names
the namespace URI and the prefix written (or that none was); a container
that isn't one rdf:Bag names what it holds instead. Findings are capped at
1000 per document and repeated names at 200 characters.
6.6.2.3.1 issues now name the type the XMP Specification gives the
property, as the specification writes it (Integer, seq Rational,
Lang Alt, Flash); structure types carry their names for this.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A 6.6.2.3.1 issue now says which metadata stream holds the property
("in metadata stream 5 0 R") and carries its ObjRef in Issue::object, so a
property mistyped in more than one stream is reported once per stream.
Wordings that name more than one thing use named holes, such as {object},
filled in one pass with the {} value, so a translation can reorder them.
Tests: the stream is named and located per issue; a non-preferred prefix
bound to the TIFF, EXIF or aux namespace URI is checked, and the preferred
prefixes bound to other URIs are not, proving the lookup is by URI.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A schema's property or value type list, or a value type's field list,
written more than once is read each time; and a pdfaExtension:schemas
that isn't one rdf:Bag (TechNote 0009, 4.2) is reported.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyDBXygTf7jcqdsjcfn
A qualified value has exactly one rdf:value; a parse type other than
Resource, which XMP doesn't use (ISO 16684-1 7.9.2.5), breaks the value;
and an rdf:resource element holds no element content in any form.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyDBXygTf7jcqdsjcfn
All five extension schema container namespaces are written with their
own prefixes, pdfaExtension included (PDF Association TechNote 0009,
4.1). The module comment cites TechNote 0009 section 4 for the schemas,
entries and prefixes, and says where PDF/A-2 asks more than it does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyDBXygTf7jcqdsjcfn
* M1: respect generations in COS object references and full saves
Resolve stale references to null instead of replacement objects with the
same number. Validate complete identities in writer readers, indirect
stream lengths and catalog checks, and keep generation-aware length caches.
Cover cache reuse, edit overlays, snapshots, incremental and packed/classic
full saves, and stream lengths with synthetic regressions and independent
hayro checks.
Co-Authored-By: Codex <noreply@openai.com>
* M0: clarify refreshed CI roadmap note
Co-authored-by: OpenAI Codex <noreply@openai.com>
* M1: repair contradictory xref generation references
Address maintainer feedback on the existing PR. Preserve upstream work and document the tested scope and remaining validation limits.
* M1: cover repaired generations and freed-slot round trips
Address maintainer feedback on the existing PR. Preserve upstream work and document tested scope and validation limits.
* M1: document generation repair and bounded diagnostics
Address maintainer feedback on the existing PR. Preserve upstream work and document tested scope and validation limits.
* M1: record generation repair regression evidence
Address maintainer feedback on the existing PR. Preserve upstream work and document tested scope and validation limits.
* M1: document bounded COS generation repair
Address maintainer feedback on the existing PR. Preserve upstream work and document tested scope and validation limits.
* M1: record generation repair parity evidence
Address maintainer feedback on the existing PR. Preserve upstream work and document tested scope and validation limits.
* fix(cos): preserve repaired generations through preflight and saves
Keep accepted xref/header aliases across repair-aware edits and snapshots, canonicalize full-save identities, and retain bounded generation diagnostics from older revisions. Add COS, writer/encryption, and real preflight regression coverage.
* test(preflight): assert repaired aliases share saved identity
Address the review nitpick by comparing reopened HeaderImage and RowImage references after damaged full saves, for classic/packed output and edited/restored snapshots. Focused preflight regression and rustfmt check pass.
* M14: update certificate dependencies for RustSec advisories
Bump rustls-webpki to0.103.16 and webpki-root-certs to1.0.10. Preserve all other locked packages and dependency lists, manifests, Git pins, and advisory policy.
---------
Co-authored-by: MMexicann <MMexicann@users.noreply.github.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: FredApps <FredApps@users.noreply.github.com>
Every pdfaExtension:schemas description needs its entries: a schema its
schema, namespaceURI and prefix; a property its name, valueType,
category and description; a value type its type, namespaceURI, prefix,
description and field; a field its name, valueType and description.
Each description namespace is written with its own prefix. One pass over
the metadata streams serves this check and the value types.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyDBXygTf7jcqdsjcfn