Repository navigation
PDF import: Separation images keep their ink (#6314) - #6347
Conversation
An image in a Separation color space opened as an RGB image: its spot ink was lost (no plate in Separations Preview), and Fill and Recolor Artwork didn't reach its color. It now opens as a grayscale image of its tints (white where it lays no ink, black at 100 %, its Decode array applied; 1 to 16 bits a sample, or one gray channel from its JPEG, CCITT, JBIG2 or JPEG 2000 decoder), colorized by its ink at 100 %: the spot swatch, a process plate's CMYK color, or Registration. Its mask becomes its opacity mask, as a CMYK image's does. The ink is found by the image's color space among those the file defines, once per image. The ink None, an ink whose color can't be told, images inside an alpha soft mask, inline images and DeviceN images open as before; samples that can't be read open in RGB with a warning, and the ink gets no swatch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. Walkthrough
Merge Risk:
|
eliets2
left a comment
There was a problem hiding this comment.
First-pass review notes (automated; combined from specialist angles: tests). Please treat as suggestions and verify before acting.
What the change does: Fixes #6314 by opening Separation color space images as grayscale tint images colorized by their ink at 100% — spot swatch, process-plate CMYK color, or Registration — so the ink is preserved for Recolor Artwork, with RGB fallback and a warning when tints cannot be read.
Logical units:
import_image::separation_spaceandtint_grayincrates/pdf/src/import_image.rsto read the Separation space and tint samplesColors::array_spaceincrates/pdf/src/import_color.rsto resolve the ink by kind, colorant names, and tint transformBuilder::separation_imageincrates/pdf/src/import/builder.rsto build the colorized image viaColors::nativedraw_imageincrates/pdf/src/import/device.rswith per-imageseparation_paintsdecision and separate gray cache key- Tests in
crates/pdf/src/tests/colorize.rsand docs indocs/file-format-parity.md
Findings:
- [tests]
crates/pdf/src/import_color.rsColors::array_space/crates/pdf/src/tests/colorize.rs: matching by tint transform is untested when two Separation spaces share the same ink name with different transforms; add a page with two such spaces and assert the image uses the transform from its own space. - [tests]
crates/pdf/src/import/builder.rsBuilder::separation_image: the unknown-ink fallback (array_space/nativereturningNone) and Registration are claimed but have no test; add a Registration image that colorizes and an unmodelled alternate-space image that stays RGB with no swatch. - [tests]
crates/pdf/src/import_image.rstint_gray: the decoder-output mismatch branch (Some(_) => Err) is untested, only truncated data is tested ina_separation_image_that_cant_be_read_stays_rgb; add a case where the decoder returns RGB, wrong dimensions, or alpha and assert RGB fallback with one warning. - [tests]
crates/pdf/src/import_image.rstint_gray/a_separation_image_reads_its_samples_and_decode_array: 2-bit samples are claimed but not tested, and the 16-bit case uses only0000/FFFFso a byte-order error passes; add 2-bit and mid-value 16-bit cases, including a width that needs row padding. - [tests]
crates/pdf/src/import_image.rstint_gray: theBitsPerComponentcheck and the zero/MAX_CMYK_PIXELSsize cap have no test; add invalid-bit-depth and oversized-dimension cases asserting RGB fallback with a warning and no swatch. - [tests]
crates/pdf/src/import/device.rsdraw_image(!whiteguard) andseparation_space: DeviceN, inline, and inside-a-soft-mask exclusions are claimed but untested; add negative tests that those images are not colorized. - [tests]
crates/pdf/src/import_image.rstint_grayDecode handling: only/Decode [1 0]is tested; add malformed Decode (wrong length or non-finite values, which should default to0..1) and out-of-range Decode values that should clamp. - [tests]
crates/pdf/src/import_image.rstint_graydecoder support: CCITT, JBIG2 and JPEG 2000 are claimed in docs but only JPEG is tested; add at least one non-JPEG decoder case or remove the claim until tested.
Overlaps: Follows #6321 (#6313) and reuses its colorized image masks; related to #3235 and #1466.
Verdict: needs changes — 1) tint-transform disambiguation for same ink name is untested, 2) unknown-ink fallback and Registration colorization are untested, 3) decoder-output mismatch fallback is untested.
|
Merged, thanks @jmverges! It passed its CI checks. |
… inks (#6348) An image in a DeviceN color space opened as an RGB image, losing its inks. One of one colorant now opens as a Separation image does since #6347: a grayscale image of its tints colorized by its ink. One of two to 32 colorants that are all process plates (the ink None may be among them) opens as a CMYK image, each colorant's tint in its plate, its Decode array applied (8 or 16 bits a sample). A DeviceN image that mixes a spot ink with other colorants, such as a duotone, still opens as RGB. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
What and why
Fixes #6314. Follows #6321 (#6313), whose colorized image masks this reuses. Related: #3235 (spot inks in vector DeviceN colors and gradients), #1466 (colorizing grayscale images).
An image in a Separation color space (one ink, ISO 32000-1 §8.6.6.4) opened as an RGB image: its spot ink was lost (only the process plates in Separations Preview), and
recolor.colorsdidn't list its color, so Recolor Artwork couldn't change it.It now opens as a grayscale image of its tints (white where it lays no ink, black at 100 %, its Decode array applied) colorized by its ink at 100 %: the ink's spot swatch, a process plate's CMYK color, or Registration. That is the model #4431 added for colorized images.
How
import_image::separation_spaceandtint_gray(crates/pdf/src/import_image.rs): the image's[/Separation …]space, and its samples read as tints, the wayimport_image::cmykreads a CMYK image's. Samples of 1, 2, 4, 8 and 16 bits, or one gray channel of the image's size from its JPEG, CCITT, JBIG2 or JPEG 2000 decoder. Samples that can't be read (data cut short, a decoder's output of another layout) leave the image in RGB, with a warning.Colors::array_space(crates/pdf/src/import_color.rs): finds the image's space among thoseColors::scanrecorded, by kind, colorant names and tint transform. The page's walk counts paths, not images, so it can't name the ink.Builder::separation_image: the tints, then the ink at 100 % throughColors::native, so the swatch, process plates and Registration work as they do for a fill. The ink is only marked used once the tints are read, so an image that stays RGB adds no swatch.draw_image: a Separation image takes that path after the CMYK one, with its own mask as its opacity mask, as a CMYK image's is. The decision is kept per image (separation_paints), and the gray pixels have their own cache key, so an image that opens in RGB stays RGB when it is drawn again, and the tint transform isn't read again for each draw.The ink
None(which paints nothing), an ink whose color can't be told (an alternate space the importer doesn't model), images inside an alpha soft mask, inline images (their/CSnames a resource) and DeviceN images open as before.Two differences from the old RGB image, both from how VectorCraft draws a colorized image:
Docs:
docs/file-format-parity.md(status line, the PDF row and the revision history).How it was tested
crates/pdf/src/tests/colorize.rs:a_separation_image_opens_colorized_by_its_ink: a 4 × 1 image of tints 0, 1/3, 2/3 and 1 opens as gray 255, 170, 85, 0, colorized by theSpotRedspot swatch at 100 %.a_separation_image_reads_its_samples_and_decode_array: 1-bit with/Decode [1 0], 4-bit and 16-bit samples.a_separation_jpeg_opens_colorized_by_its_ink: a one-component JPEG.a_separation_image_of_a_process_plate_or_of_no_ink:/Blackcolorizes in CMYK black with no spot swatch;/Noneisn't colorized.a_separation_image_keeps_its_soft_mask: its/SMaskbecomes its opacity mask.a_separation_image_drawn_twice_is_colorized_twice: both draws are colorized, over the same pixels.a_separation_image_that_cant_be_read_stays_rgb: data cut short, drawn twice, stays RGB both times, with one warning and no swatch for the ink.All seven fail on
main(the last one on its warning, whichmaindoesn't give). The/None, JPEG and "stays RGB" tests also fail with the change but without, respectively, theNonecheck, the decoder output accepted, and the ink resolved after the tints.What I ran:
cargo xtask ciwith Rust 1.99.1 on Linux x86_64, run one by one on this branch rebased onmain: fmt, clippy, test, doctests, no-bundled-fonts, pdf-deps, assets, brands, cursors, layers, wasm and i18n-report pass. As in PDF import: image masks open colorized by the color they are painted in (#6313) #6321, I skipped one test that fails on my machine whatever the change:vectorcraft-text'stests::harakat::coloured_harakat_keep_kashida, which picks the Arial installed here;vectorcraft-textdoesn't depend onvectorcraft-pdf.vectorcraft-clibuilt from this branch:image.infogives"colorMode":"Grayscale",recolor.colorslistscmyk 0 100 100 0(swatch SpotRed), the plates include SpotRed, andrecolor.apply {"map":{"cmyk 0 100 100 0":"#0000ff"},"model":"new"}turns the ramp blue.Checklist
cargo xtask cipasses (fmt, clippy, tests, assets, brands, layers, wasm), apart from the one machine-specificvectorcraft-texttest above.unwrap(),expect(),panic!,unreachable!,todo!orunimplemented!outside tests, and no unchecked indexing on data from files, parameters ormessages. Errors are returned as
Resultand shown to the user(why and how).
ASSETS.md(no new assets).Summary by CodeRabbit