Commit Graph
171 Commits
Author SHA1 Message Date
aiongg 0fe6156614 krilla: PDF/A ledgers state DeviceN and the print output intent
Patch 06 records that DeviceN fails export under PDF/A-1 to -3 (its tint transform is
PostScript) and is written under PDF/A-4; patch 08 records the second output intent and
the caller's CMYK destination profile.
2026-10-20 04:09:24 +00:00
aiongg 1afbab004e ci: run the PDF jobs when craft-cms changes
craft-plate-test and craft-prepress depend on craft-cms, and the craft-pdf tests read its
CMYK profile.
2026-10-20 04:09:24 +00:00
aiongg 4c3cc64469 pdf: faster plate tests
The plate helper renders all inks of a page with one render cache, as a separating caller
does, so ICC transforms are built once per page instead of once per plate. The mutated
profile test changes the header fields a reader checks instead of every 16th header byte,
and samples the tag data more sparsely: each profile that still loads costs a fifth of a
second in a debug build.
2026-10-20 04:06:29 +00:00
aiongg e6d2a24641 prepress: to_pdf_color writes ink colors as DeviceCMYK, Separation or DeviceN
Process tints become DeviceCMYK, one spot a Separation with its alternate, other mixes a
DeviceN space with process inks first, registration and None the All and None
separations. Lab spot alternates convert through the printing condition, as resolve does.
2026-10-20 03:57:10 +00:00
aiongg 4026931196 Merge craft-prepress into the print color PR 2026-10-20 03:51:59 +00:00
aiongg 4344dfccf9 plate-test: keep short arrays and objects on one line in the scene files
Mark the krilla patch files as generated, so diffs collapse them.
2026-10-20 03:51:04 +00:00
aiongg e5b73eb4cf plate-test: mesh gradient paint and scene S17 (spot, process and DeviceN corners) 2026-10-20 03:41:18 +00:00
aiongg 60dc2b54ce krilla: write mesh corner colors in one color space
A mesh gradient took its color space and component count from the first
patch's first corner, so a later corner in another space was truncated or
padded with zeros and written as the wrong color. Mesh corner colors now go
through the same rule as gradient stops (`common_color_space`): process
colors alone are DeviceCMYK, one spot alone is Separation, and mixes are
DeviceN with process colorants first, then spots. Colors that rule can't
unify (RGB with CMYK, registration) fail the document with
`KrillaError::MixedMeshColorSpaces`. The opacity soft mask is unchanged, and
a mesh in one space writes the same bytes as before.

patches/10-mesh-gradients.patch holds #184's change and this fix, so
patches 01 to 10 reproduce src; the ledger section 10 and SOURCE.json follow.
2026-10-20 03:41:18 +00:00
fastmikey99 ce31f9d710 krilla: mesh gradients as PDF Type 6 shadings
paint::MeshGradient / MeshPatch: Coons patches with a colour and opacity at each corner, written as
one Type 6 (Coons patch mesh) shading through pdf-writer's StreamShading, so viewers and RIPs blend
them smoothly at device resolution instead of an app cutting each patch into flat-colour pieces.
Same path as the other gradients: a shading pattern fill, and corner opacities below 1 as a
luminosity soft mask of the same mesh in gray. 32-bit coordinates over the mesh bounds, 8-bit
components, Flate. Recorded in vendor/krilla/README.craft.md and SOURCE.json.
2026-10-20 03:41:18 +00:00
aiongg 21154585b5 krilla: record the master-rendition patch (#183) in the patch ledger 2026-10-20 03:41:18 +00:00
Hamza 96c45ccde1 krilla: a written document is the master rendition, not a proof
`chunk_container` wrote `xmpMM:RenditionClass` as `proof` on every PDF krilla
produces. That property says which rendition a file is (XMP Part 2, Media
Management): `default` is the master, `proof` a proof copy. So every export
told a prepress system that a print deliverable was only a proof, and PDF/X
output carries the same claim.

Noticed on storytold/designcraft#1207, where PDF/X-4 output was being checked
against Acrobat's preflight; it is not what fails that check, but it is wrong
and it reaches every app that writes PDF through this tree.

Checked with DesignCraft pointed at this tree: `xmpMM:RenditionClass` reads
`default` for a PDF/X-4 export and for an ordinary one, where both read `proof`
before.
2026-10-20 03:41:18 +00:00
aiongg f7ae814d91 plate-test: app-neutral print color scenes, checked by PDF structure and Ghostscript plates
craft-plate-test writes JSON scenes through craft-pdf and checks the written PDF's
structure (CI, under a second) and, locally only, its separated plates through
Ghostscript tiffsep (scripts/plate-check.sh). Apps can run the same scenes through
their own export as a dev-dependency.
2026-10-20 03:41:13 +00:00
aiongg eedd0246df krilla: CMYK print color in the vendored krilla, and a craft-pdf print preset
Print PDFs written through krilla separated wrongly: transparency groups blended in RGB
(K 50% over C100 separated as C84 M34 Y32 K37 instead of C50 K50), and there was no
overprint, knockout, DeviceN, soft-mask backdrop or print output intent.

Patches in vendor/krilla/patches/, recorded in README.craft.md and SOURCE.json:
- 02 blending color space: GroupColorSpace { Rgb (default, unchanged output), Cmyk }
- 03 overprint: Surface::push_overprint (/op /OP /OPM)
- 04 knockout groups: Surface::push_group(GroupOptions { isolated, knockout })
- 05 soft-mask backdrop and transfer function (/BC /TR)
- 06 DeviceN and NChannel colors for fills and strokes
- 07 DeviceN images and shadings
- 08 print output intent (GTS_PDFX), /Trapped, PDF/X version markers

craft_pdf::write::print::settings(PrintColor) turns them on for print export.
2026-10-20 03:41:13 +00:00
aiongg 4585efee97 prepress: rename craft-separations to craft-prepress 2026-10-20 03:39:36 +00:00
aiongg 2c80b65e98 separations: use US spelling 2026-10-20 03:25:47 +00:00
aiongg 602c915272 separations: US spelling in the coverage, composite and ink manager docs 2026-10-20 03:23:15 +00:00
aiongg 9e2c629f25 separations: ink manager on InkSet
Aliases (a spot printed on another ink's plate), spot to process and all
spots to process, with resolve applying both to a colour. The README
describes the coverage, composite and ink manager API and how the apps use
it for a Separations Preview and an Ink Manager.
2026-10-20 03:22:29 +00:00
aionggandGuillem Hermida 3c6089bcfc separations: coverage, TAC regions and a composite preview from plates
Per-ink coverage at a pixel and over a page, TAC per pixel, the pixels and
connected regions over a TAC limit, and an sRGB composite of chosen plates:
process plates through the printing condition, spot plates multiplied over
them by their alternate's appearance. Ported from the data parts of
pdfcraft #2770 separations.rs.

Co-authored-by: Guillem Hermida <66697068+guillehr2@users.noreply.github.com>
2026-10-20 03:22:29 +00:00
aiongg 126440b274 separations: test craft-separations in the PDF workflow on Ubuntu 2026-10-20 03:15:36 +00:00
aionggandGuillem Hermida c025c0dfff separations: add craft-separations with the ink model and plates
The ink model (process and spot inks, InkSet with PDF name lookup,
InkColor, Overprint) and plates(pdf, page, dpi, opts): ink discovery
and one gray film per ink through craft-pdf's raster plate mode, with
process colour converted through craft-cms (output intent, else the
caller's profile or FOGRA39). Plate rendering, ink discovery, caps and
output-intent selection port pdfcraft #2770's separations.rs.

Co-authored-by: Guillem Hermida <66697068+guillehr2@users.noreply.github.com>
2026-10-20 03:15:36 +00:00
aionggandmtlcl410 b01d19c716 vendor: port pdfcraft #2974 knockout groups into hayro
Bring storytold/pdfcraft#2974 (source commit
bae69819594a6385a027fec1f67e6b3c36c259b4) onto the vendored
hayro-interpret and hayro. Knockout transparency groups (/K true) knock
out: while one is innermost, fills, strokes, glyph outlines and shadings
are drawn with Compose::Copy, weighted by coverage. An unmasked image's
rectangle and a nested group's shape are cleared before their layer
composites; the nested group's shape comes from an erase pass over its
content. Masked images and stencils composite as before.

Code comments label the change "Knockout patch (pdfcraft #2974)": the
pull request numbers it hayro-interpret patch 39 and hayro patch 19,
which pdfcraft may renumber. The erase pass resolves resources with
Resources::from_scope, as this tree's form drawing does.

crates/pdf/tests/knockout.rs adapts the pull request's test to the
raster path (without its preview case: craft-pdf has no preview mode).
A plate-mode test checks that a knockout group of two 50% squares
separates with only the top square in the overlap. Options documents
that color_replacement also maps plate films. Ledger, NOTICE and the
source manifests are updated.

Co-authored-by: mtlcl410 <2368091+mtlcl410@users.noreply.github.com>
2026-10-20 03:07:22 +00:00
aionggandGuillem Hermida 7764afb2a7 vendor: convert plate-mode CMYK through a CmykConversion trait
CmykSimulation converts process colour to an output intent's CMYK
through a color::CmykConversion: sRGB colours, and CIE XYZ relative to
the D50 PCS white (color::PCS_WHITE) for Lab and ICCBased colours.
CmykSimulation::new keeps the moxcms conversion from pdfcraft #2770,
which takes XYZ on through its ProPhoto hub; with_conversion takes a
caller's, so a crate can separate with its own colour management.

crates/pdf/tests/plates.rs adapts #2770's plate tests to the raster
path: process, spot, DeviceN, All/None, ICC CMYK, gray and RGB colours,
images, shadings, uncoloured patterns, soft masks, OP/op/OPM, the ink
sink, output-intent simulation with #2770's synthetic ICC profiles, and
a caller's conversion. The ledger and NOTICE name the pull request.

Co-authored-by: Guillem Hermida <66697068+guillehr2@users.noreply.github.com>
2026-10-20 02:53:37 +00:00
aionggandGuillem Hermida 2c8c3ad261 vendor: port pdfcraft #2770 plate mode into hayro-interpret
Bring the vendored interpreter part of storytold/pdfcraft#2770 (Output
Preview, source commit 6fcf2a4aca29e943e28cb69017ff8f87d00656c6) onto
the ec0a965 snapshot. It applies without conflicts.

InterpreterSettings::plate draws one ink's separation: every paint
draws that ink's tint as a gray film, by the colour space's ink use and
tint. The graphics state reads OP, op and OPM, and an overprinting
paint that doesn't specify the plate's ink leaves the plate as it is
(ISO 32000-2 8.6.7). InterpreterSettings::ink_sink reports the spot
inks paints use, and color::CmykSimulation converts process colour to
an output intent's CMYK profile.

PdfCraft's separations.rs, Output Preview UI and automation are not
part of this port. The ledger in vendor/README.craft-reader.md names the
pull request, author and source commit.

Co-authored-by: Guillem Hermida <66697068+guillehr2@users.noreply.github.com>
2026-10-20 02:40:50 +00:00
aiongg b6f60f25b1 vendor: re-sync hayro reader trees from pdfcraft ec0a965
Bring vendor/hayro, hayro-interpret, hayro-syntax and hayro-jbig2 to
storytold/pdfcraft ec0a965074f376a5bf610435948e4e5184bf3299 (main,
2026-10-19), from 7437bde. The local patches (per-document decode
limits, incomplete-content diagnostics, Hayro 0.8 resource scopes,
nesting cap, iterative page tree, TJ fill order, transfer rounding,
safety repairs) are carried by a three-way merge without conflicts.

The re-sync includes transparency group /I and /K reading (pdfcraft
#2027), patches 28, 29 and 31-34, and the reader fixes listed in
vendor/README.craft-reader.md. SOURCE.json manifests, NOTICE and the
craft-pdf README name the new source revision.
2026-10-20 02:30:13 +00:00
Dylan M. Taylor ae2f796b67 ci: configure Dependabot for Cargo and GitHub Actions (#174)
* ci: configure Dependabot for Cargo and GitHub Actions

* ci: include read-only-contract in Cargo Dependabot coverage
2026-10-18 15:11:21 -04:00
skylar taylor-barrick 16ec4f7e69 Merge pull request #167 from benandez/feat/i18n-runtime
Add craft-i18n: shared translation runtime for the Craft apps
2026-10-18 12:44:29 -06:00
Martin BallandClaude Opus 5.5 bc9d71b27a i18n: test prints system_lang per platform for CI logs
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 19:12:44 +01:00
Martin BallandClaude Opus 5.5 c36ea1bf64 i18n: review fixes (offered locales, locale-first fallback, pt plurals, scripts)
Skylar's review of 886a0b3:
1. tc/tid go locale by locale: in each locale the context or @id row,
   then the plain row, so pt-br's plain row beats pt's context row.
2. pt (and pt-* other than pt-br) uses pt-PT plural rules: 0 is plural.
3. A script subtag (sr-Latn-RS, sr_RS@latin, be_BY@latin) never picks a
   code of another script; sr-Cyrl-RS still picks sr.
4. A row defined twice is reported and the first kept, as in the checker.
5. The pseudo locale is debug-only via from_code, get marks too, and
   looked_up() lists what was looked up for an app's audit.
6. intl_pluralrules pinned to =7.0.2; plural_form_counts copied from the
   checker, plus pt.
7. I18n::new takes the app's offered codes: languages(), from_code,
   match_tag and system_lang only return those; others stay fallbacks.

Smaller: en/pseudo/repeated codes are skipped and reported,
system_lang is cached, zh-hant-hk falls back to zh-hant, rtl adds ckb,
dv, ps, sd, ug and yi.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 19:12:01 +01:00
Martin BallandClaude Opus 5.5 886a0b367f i18n: sr_RS@latin picks sr-latn; README macro and get wording
Review fixes (CodeRabbit): a glibc @latin/@cyrillic modifier becomes the
script subtag and only codes with that script are tried. sys-locale
drops the modifier, so on desktop Unix system_lang reads LANGUAGE,
LC_ALL, LC_MESSAGES and LANG raw, in its order. README: tl! qualifies
CURRENT with $crate; get follows the locale chain but never the plain
row or English.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 10:38:04 +01:00
Martin BallandClaude Opus 5.5 10592ba4fd ci(i18n): run clippy and tests for craft-i18n on all three platforms
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 10:07:11 +01:00
Martin BallandClaude Opus 5.5 841ebed58c i18n: prefer pt over pt-br, no fallback across scripts, lookup without fallback
Final review fixes: a European Portuguese locale wins over pt-br when both
are embedded; sr-latn no longer falls back to Cyrillic sr; get() looks up
one context with no plain or English fallback (key-cap names).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F9fM3mv1PUyKpk5rdwUQrW
2026-10-18 09:33:21 +01:00
Martin BallandClaude Opus 5.5 c9bcc60832 i18n: README and library listing
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F9fM3mv1PUyKpk5rdwUQrW
2026-10-18 09:33:21 +01:00
Martin BallandClaude Opus 5.5 6346621e91 i18n: pseudo locale
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F9fM3mv1PUyKpk5rdwUQrW
2026-10-18 09:33:14 +01:00
Martin BallandClaude Opus 5.5 cfbc6a1adf i18n: languages, names and system locale matching
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F9fM3mv1PUyKpk5rdwUQrW
2026-10-18 09:33:14 +01:00
Martin BallandClaude Opus 5.5 c84b14d6c2 i18n: plurals and placeholder filling
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F9fM3mv1PUyKpk5rdwUQrW
2026-10-18 09:33:14 +01:00
Martin BallandClaude Opus 5.5 7b797335cb i18n: catalog parsing and lookup with fallback
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F9fM3mv1PUyKpk5rdwUQrW
2026-10-18 09:33:14 +01:00
skylar taylor-barrick 82a24b006e Merge pull request #169 from skylartaylor/docpath-crate
Add craft-docpath
2026-10-17 12:00:19 -06:00
skylar taylor-barrick a92010200c test(docpath): assert Unix-shaped results only on Unix
resolve_absolute_refuses_results_that_are_not_absolute resolved links against a
document at /home/u/docs/a.doc outside its cfg!(windows) branch. On Windows that
path is rooted but has no drive, so it is not absolute, resolve_absolute refuses
the result as documented, and the unwrap panicked. The Windows arm already covers
the same three cases with a drive. Found by the new docpath CI job on its first run.
2026-10-17 11:10:18 -06:00
skylar taylor-barrick 5542a9466d ci(docpath): run clippy and tests for craft-docpath on all three platforms
The per-crate workflows name their crates with -p, so the new crate had no job
and its tests, including the Windows-only colon and stream assertions, never ran
in CI.
2026-10-17 10:20:41 -06:00
skylar taylor-barrick 04e83f095a Merge pull request #166 from storytold/fix/models-provenance-for-a-running-test
craft-ai-core: record which address a test's models came from
2026-10-17 08:50:21 -06:00
skylar taylor-barrick 559992953f craft-ai-core: record which address a test's models came from
A test is not instant and the address field stays editable while it runs,
so its answer can arrive after the address has changed. `set_models` then
recorded the models against whatever the field held by the time it
returned, filing one endpoint's models under another — the mislabelling
`models_fit` exists to prevent, reached the asynchronous way rather than
the synchronous ones already closed.

`set_models` now takes the address the test was started against and
returns whether the models were taken, so an answer that outlived its
address is dropped and the caller can say the result is out of date. The
parameter replaces the old signature rather than joining it: there was no
second legitimate caller, and leaving an address-free version beside it
would have left the racy call the shorter, easier one to reach — against
this module's rule that the rules live once so two screens cannot
disagree.

Also fixes a pre-existing mismatch found while testing this:
`from_connection` recorded the loaded address untrimmed while `prepare`
compares it trimmed, so a stored endpoint with stray whitespace dropped
its models on the first save.
2026-10-16 23:07:53 -06:00
aiongg c04cc16109 fix(docpath): colons in names are refused only on Windows 2026-10-17 04:14:51 +00:00
skylar taylor-barrick 15ed713b8f Merge pull request #69 from Jeremy8776/feat/ai-model
Model provenance across loaded and preset endpoints and repeated endpoint edits, so models from one endpoint are not relabelled as another's, and eligibility resolved in both directions: a model must accept every input the tool sends, and the tool must supply every input the model requires (new ResolveError::InputRequired).

All 18 checks pass on a40245bd, including craft-ai-core fmt, clippy -D warnings, tests and the wasm32 check on Ubuntu, Windows and macOS.

Note for callers: after a tracked endpoint change, use set_models for newly discovered models; direct assignment on fresh custom drafts and unchanged saved endpoints still works. The asynchronous in-flight probe race is separate and not addressed here.
2026-10-16 21:56:16 -06:00
aiongg 0d0e5efaac feat(docpath): add resolve_absolute
resolve_absolute refuses a result that is not absolute on the running
platform, such as a relative link in a document that has no path yet.
It is the function to call before opening a file.
2026-10-17 03:36:22 +00:00
aiongg d7772fbb39 fix(docpath): refuse colons inside path components
A stored path that starts with a URL scheme and a colon is a URL; a
colon in any other name is invalid. Only a leading drive letter keeps
its colon.
2026-10-17 03:35:36 +00:00
skylar taylor-barrick a40245bd36 craft-ai-core: track model provenance by address; require the inputs a model needs 2026-10-16 20:26:06 -06:00
skylar taylor-barrick 83bf4cb25c Merge pull request #148 from midasmatterhorn/fix/r4-cms-icc-checked
cms: bound the ICC curve count before it is multiplied, and read mluc record offsets checked
2026-10-16 10:58:04 -06:00
aiongg 12281d07fe fix(docpath): accept drive hosts, legacy escapes and colon names; refuse lookalike separators 2026-10-16 16:14:16 +00:00
aiongg ddc5012437 feat(docpath): add craft-docpath for checking paths stored in documents 2026-10-16 16:01:59 +00:00
midasmatterhorn 8b71728482 cms: the mluc record is read as one checked 12-byte slice
The eager tuple computed o + 8 even when the first read had failed,
overflowing a 32-bit usize at offsets near u32::MAX (n = 2 with
size = u32::MAX - 20 reaches it: o fits, o + 8 does not). The record is
now bounds-checked in one slice and the fields read inside it, the same
complete-record pattern the profile reader uses elsewhere.
2026-10-16 14:46:23 +03:00