Skip to content

Fix #320: CMYK images stay CMYK from PDF import to PDF export - #393

Merged
bflatastic merged 1 commit into
mainfrom
fix/issue-320
Oct 7, 2026
Merged

bflatastic merged 1 commit into
mainfrom
fix/issue-320

Conversation

@bflatastic

Copy link
Copy Markdown
Member

Fixes #320. CMYK images in a PDF now keep their CMYK samples when the file is opened, and PDF export writes them as CMYK. They used to become RGB with no warning.

  • Model (vectorcraft-doc::cmyk): a CMYK image is stored as a four-component JPEG (Adobe's inverted samples) or as a Deflate CMYK TIFF. ImageBlob::is_cmyk / ::cmyk read the ink amounts, capped at 64 megapixels, and ::cmyk_tiff writes the TIFF.
  • PDF import: DeviceCMYK, CalCMYK and four-component ICC images keep their samples. A JPEG with Decode [1 0 1 0 1 0 1 0] is kept byte for byte. Any other is decoded (8 or 16 bits, Decode array applied) and stored as a CMYK TIFF. Masked CMYK images and 1/2/4-bit ones still open in RGB, now with a warning. Placing a CMYK TIFF also keeps it CMYK.
  • PDF export: CMYK images are written as DeviceCMYK, or as ICC-based with the CMYK profile when colours are tagged (PDF/X-3, PDF/X-4, profiles: all). A CMYK JPEG that is not resampled or recompressed passes through unchanged. Other CMYK images are resampled in CMYK and compressed as ZIP or as a CMYK JPEG (jpeg-encoder). The CMYK JPEG encoder also replaces the old ZIP fallback and its warning for images converted to CMYK. Output conversion treats CMYK images like CMYK colours:
    • Preserve Numbers and PDF/X-1a keep their numbers.
    • Convert to Destination converts them to another CMYK profile or to RGB, through a 17⁴ cms::CmykLut. The renderer's ink table is now built on the same LUT.
    • A CMYK image that can't be decoded is reported in warnings.
  • Canvas: CMYK images are shown through the working CMYK profile, the same way CMYK fills are, where before they used a naive conversion. In ink planes they paint their own inks (CMYK raster exports, CMYK blending).
  • SVG export: TIFF images are written as PNG, so browsers can show them.
  • Illustrator parity: Output › No Conversion "preserves color data as is" (https://helpx.adobe.com/illustrator/using/pdf-options.html).
  • docs/mcp.md and ROADMAP.md (Shipped so far › Files) are updated.

Checks

  • Rebased on origin/main @ ce12b4b.
  • cargo fmt --all --check, cargo clippy -p vectorcraft-{pdf,render,doc,color,svg,engine} --all-targets -D warnings: clean.
  • cargo test for doc, color, render, pdf and svg: 781 passed. vectorcraft-engine: 1356 passed.
  • New tests:
    • pdf/tests_cmykimages.rs (4): JPEG pass-through for default, Preserve Numbers, X-1a, X-3, X-4 and profiles: all. Flate (8/16-bit, inverted Decode), non-Adobe DCT and ICC N=4 images. Mask and 4-bit warnings. Conversions (other CMYK profile, RGB), CMYK JPEG recompression and resampling.
    • doc/cmyk.rs (3), render/ink.rs (1: the image matches a CMYK fill on screen and paints its exact inks), engine fileio (1: a placed CMYK TIFF stays CMYK), svg/tests/options.rs (1).
    • The tests fail without the fix: with the import change disabled, all 4 PDF tests fail; with the render change disabled, the canvas test fails ([230,138,0] vs [229,151,16]).
  • cargo xtask layers, cargo xtask brands, cargo xtask wasm (19 crates ok) pass. cargo check --target x86_64-unknown-linux-gnu and aarch64-apple-darwin pass on doc/pdf/render/svg.
  • Live run with the issue's case, using a debug vectorcraft-cli on a generated PDF (PIL CMYK JPEG with Decode [1 0 …] plus a Flate CMYK image plus a CMYK fill):
    • info reports colorMode: cmyk.
    • convert gives DeviceCMYK for both images, with the source JPEG bytes embedded unchanged.
    • exportPdf pdfX3 and pdfX4 give [/ICCBased …] with N=4. pdfX1a gives DeviceCMYK.
    • All four runs return warnings: [].
    • The PNG render shows the image at (255,217,155), which matches the reporter's poppler reading of the source file.

🤖 Generated with Claude Code

A PDF's DeviceCMYK image opened as RGB (the interpreter's pixels as a PNG),
so every export wrote it as DeviceRGB or ICC RGB, silently. Images now keep
their CMYK samples, as CMYK colours already did:

- Model: CMYK images are blobs holding CMYK samples, a four-component JPEG
  (Adobe's inverted samples) or a Deflate CMYK TIFF. vectorcraft-doc's cmyk
  module reads their ink amounts (ImageBlob::is_cmyk, ::cmyk, capped at 64
  megapixels) and writes the TIFF (ImageBlob::cmyk_tiff).
- PDF import: DeviceCMYK, CalCMYK and four-component ICC images keep their
  samples. A JPEG with Decode [1 0 1 0 1 0 1 0] is kept byte for byte; any
  other is decoded (8 or 16 bits, its Decode array applied) and stored as a
  CMYK TIFF. Masked CMYK images and 1/2/4-bit ones open in RGB with a warning.
  Placing a CMYK TIFF keeps it CMYK too.
- PDF export: CMYK images are written in CMYK (DeviceCMYK, or ICC-based with
  the CMYK profile when colours are tagged: PDF/X-3, PDF/X-4, PDF/A). A CMYK
  JPEG neither resampled nor recompressed passes through unchanged; others are
  resampled in CMYK and compressed as ZIP or as a CMYK JPEG (jpeg-encoder,
  which also replaces the ZIP fallback and its warning for images converted to
  CMYK). Output conversion treats them like CMYK colours: Preserve Numbers and
  PDF/X-1a keep their numbers, Convert to Destination converts them to another
  CMYK profile or to RGB through a 17^4 lookup table (cms::CmykLut, now also
  behind the renderer's ink table). A CMYK image that can't be decoded is
  reported in the warnings.
- Canvas: CMYK images show through the working CMYK profile, as CMYK fills
  do, and paint their own inks in ink planes (CMYK raster exports, CMYK
  blending). SVG export writes TIFF images as PNG.

Illustrator's Output › No Conversion keeps colour data as it is
(https://helpx.adobe.com/illustrator/using/pdf-options.html).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@bflatastic
bflatastic merged commit 0169781 into main Oct 7, 2026
@bflatastic

Copy link
Copy Markdown
Member Author

Full cargo xtask ci passed on the integrated stack; merging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: PDF round trip writes DeviceCMYK images as RGB (default export: DeviceRGB, PDF/X-3: ICC RGB) without a warning

1 participant