@@ -5,6 +5,105 @@ All notable changes to this project will be documented in this file.
55The format is based on [ Keep a Changelog] ( https://keepachangelog.com/en/1.1.0/ ) ,
66and this project adheres to [ Semantic Versioning] ( https://semver.org/spec/v2.0.0.html ) .
77
8+ ## [ 0.2.1] — 2026-05-09
9+
10+ Patch release focused on PDF/X CMYK rendering correctness against the
11+ [ Ghent PDF Output Suite] ( https://gwg.org/pdf-output-suite/ ) (GWG)
12+ test corpus. Fixes a family of bugs where ICCBased / Lab / DeviceN
13+ fills, images, and transparency groups didn't round-trip through the
14+ document's ` /OutputIntents ` profile correctly, producing visible "X"
15+ markers in calibration swatches that should render uniform.
16+
17+ This is an ** additive, non-breaking** release. Cargo will auto-bump
18+ ` stet = "0.2" ` to ` 0.2.1 ` ; downstream code does not need to change.
19+ New public API on ` stet-graphics::IccCache ` and a new
20+ ` rendering_intent: u8 ` field on ` stet-graphics::ImageParams ` are
21+ documented under "Added" below.
22+
23+ ### Highlights
24+
25+ - ** GWG 13.3** — ICCBased RGB paints with ` /OP true ` no longer route
26+ into the custom-spot overprint path; per PDF 1.7 §11.7.4.5 they
27+ paint as if ` /OP ` were false.
28+ - ** GWG 16.1** — per-intent PDF/X proofing chain (`source A2B → PCS
29+ → OI B2A → CMYK`) is built for every registered ICCBased RGB
30+ profile, threaded through ` op_ri ` / ExtGState ` /RI ` .
31+ - ** GWG 16.4** — transparency groups with no ` /CS ` (inherit) now
32+ resolve correctly to the parent's CMYK compositing space when
33+ the parent is a ` /CS DeviceCMYK ` group.
34+ - ** GWG 17.2** — ICCBased images now go through the proofing chain
35+ via ` convert_image_8bit_with_intent ` (was bypassing the
36+ OutputIntent roundtrip and rendering via direct source→sRGB).
37+ - ** GWG 22.1** — Lab fills populate ` DeviceColor::native_cmyk ` via a
38+ direct ` Lab → PCS → OI B2A → CMYK ` chain (matches Adobe ACE),
39+ and the OutputIntent install path pre-warms the sRGB→CMYK
40+ reverse transform so the parallel CMYK buffer never falls back
41+ to the PLRM ` (1−r, 1−g, 1−b, 0) ` formula.
42+ - ** WASM viewer** — ` open_pdf ` now applies the document's
43+ OutputIntent before storing the cached state, so PDF/X documents
44+ render in the browser the same way they do in the CLI.
45+
46+ ### Added — public API (additive, non-breaking)
47+
48+ ` stet-graphics ` :
49+
50+ - ` IccCache::convert_to_oi_cmyk(hash, components, intent) ` — run an
51+ RGB ICC color through the proofing chain at the given intent and
52+ return the intermediate OutputIntent CMYK.
53+ - ` IccCache::convert_lab_to_oi_cmyk(l, a, b, intent) ` — direct
54+ ` Lab → OI CMYK ` via the OI's per-intent B2A LUT.
55+ - `IccCache::convert_image_8bit_with_intent(hash, samples,
56+ pixel_count, intent)` — bulk image conversion with explicit
57+ rendering intent.
58+ - ` IccCache::convert_color_with_intent ` and
59+ ` convert_color_readonly_with_intent ` — per-intent single-color
60+ conversion.
61+ - ` IccCache::prepare_lab_to_oi_cmyk() ` — pre-build per-intent
62+ Lab→OI samplers; pair with ` prepare_reverse_cmyk() ` .
63+ - ` IccCache::intent_from_pdf_byte(b: u8) ` — map PDF rendering-intent
64+ bytes (` 0..3 ` ) to ` IccRenderingIntent ` .
65+ - ` pub use moxcms::RenderingIntent as IccRenderingIntent ` .
66+ - ` pub struct LabToCmykSampler ` (in ` icc::perceptual ` ) with
67+ ` pub fn sample_pdf_lab(l, a, b) ` .
68+ - New field ` ImageParams::rendering_intent: u8 ` . Default is ` 0 `
69+ (Perceptual). Per the documented "be a reader, not a writer"
70+ policy for param structs (CLAUDE.md), this is additive and not
71+ treated as a SemVer break.
72+
73+ ` stet-pdf-reader ` :
74+
75+ - ` PdfDocument::apply_output_intent_as_default_cmyk() ` now also
76+ pre-warms the sRGB→CMYK reverse and per-intent Lab→OI samplers
77+ in addition to its previous behaviour. No signature change.
78+ - Image XObjects with ` /Intent ` now propagate the per-image
79+ rendering intent into ` ImageParams.rendering_intent ` , overriding
80+ the gstate ` /RI ` per ISO 32000 §11.3.4.
81+
82+ ` stet-render ` :
83+
84+ - ` build_icc_cache_for_list ` now also pre-warms the per-intent
85+ Lab→OI samplers when proofing is enabled.
86+
87+ ### Fixed
88+
89+ - DeviceGray painted in a PDF/X DeviceCMYK page group now routes
90+ through the K plate (matches DeviceCMYK 0/0/0/(1−g) byte-for-byte).
91+ - DeviceN images with a non-CMYK alternate space go through the
92+ overprint path so process plates aren't disturbed.
93+ - Paired ` /OP true /op true ` ExtGStates are now treated as a
94+ "strict overprint" signal (matches Adobe Illustrator's emit).
95+ - The custom-spot overprint dispatch and the parallel CMYK buffer's
96+ ` is_custom_spot ` heuristic both now require
97+ ` process_cmyk.is_some() ` so proofing-chain ICCBased RGB stays out.
98+
99+ ### Crates published at 0.2.1
100+
101+ ` stet ` , ` stet-cli ` , ` stet-fonts ` , ` stet-graphics ` , ` stet-core ` ,
102+ ` stet-ops ` , ` stet-engine ` , ` stet-render ` , ` stet-viewer ` ,
103+ ` stet-pdf-reader ` , ` stet-pdf ` . The vendored ` stet-tiny-skia ` /
104+ ` stet-tiny-skia-path ` forks remain at ` 0.11.4 ` . ` stet-wasm ` is
105+ excluded from crates.io and bumped to ` 0.1.1 ` independently.
106+
8107## [ 0.2.0] — 2026-05-01
9108
10109This release lands a substantial expansion of the ` stet-pdf-reader `
0 commit comments