Files

4.7 KiB
Raw Permalink Blame History

photocraft-cms

Pure-Rust ICC colour management for PhotoCraft. No workspace dependencies (L0, publishable), no C, no unsafe. Implemented from the public ICC.1:2010 (v4.3) and ICC.1:2001-04 (v2) specifications, CIE 15, and Adobe's published black point compensation paper.

API

use photocraft_cms::{Builtin, Intent, Profile, Transform};

let src = Profile::parse(&icc_bytes)?;                    // v2/v4: matrix/TRC, gray TRC, mft1/mft2/mAB/mBA
let dst = Builtin::CoatedCmyk.profile();
let t = Transform::new(&src, dst, Intent::RelativeColorimetric, /*bpc*/ true)?;
t.convert_u8(&rgba8, 4, &mut cmyka8, 5, /*copy alpha*/ true);   // also convert_u16 / convert_f32 / apply (in place)
let mut out = [0.0; 4];
t.eval(&[1.0, 0.0, 0.0], &mut out);                        // exact single colour
  • Transform::proof(src, proof, display, intent, bpc, simulate_paper): soft-proof chain.
  • GamutCheck::new(src, proof, ΔE): out-of-gamut test (gamut warning).
  • Lut3d::from_transform(&t, 33).to_rgba16f_bytes(): display transform as a 3D texture.
  • transform::cached(src, dst, opts): process-wide transform cache.
  • Profile::to_bytes(): original bytes of parsed profiles (byte-exact), or an ICC v4.3 encoding.
  • Profile::same_colors(&other): the same colour space whatever the encoding (every sample of a device grid within ΔE 0.5 through both), e.g. Photoshop's sRGB IEC61966-2.1 and the built-in sRGB. content_hash() compares bytes and suits cache keys only.

Evaluation

  • Exact path: a float stage pipeline (curves, matrices, CLUTs, Lab↔XYZ, PCS encodings, BPC / absolute scaling). Float buffers use it by default (TransformOptions::precise_float).
  • Integer buffers: matrix/TRC chains use per-code input tables + matrix + output tables indexed by x^(1/4) (accurate near black even for pure gamma curves); chains containing a CLUT are sampled into a device link (33³ for 3 inputs, 17⁴ for 4, 4096 for 1) evaluated with tetrahedral interpolation (4D: linear on the first input between two tetrahedra); purely analytic chains (e.g. Lab ↔ RGB) are evaluated exactly. Buffers ≥ 16k pixels run on rayon (native only).
  • Rendering intents: AToB0/1/2 and BToA0/1/2 by intent with AToB0/BToA0 fallback; absolute colorimetric scales by media white (wtpt; v2 display profiles treated as D50; a zero, negative or non-finite white is refused with CmsError::Invalid); BPC uses neutral black points (Y only) mapped linearly in XYZ.

Built-in profiles (all CC0-1.0, generated by this crate)

id description
srgb sRGB IEC61966-2.1 (Rec. 709 primaries, D65 Bradford-adapted, sRGB TRC)
display-p3 Display P3
adobe-rgb-compat Adobe RGB (1998)-compatible (published primaries, gamma 563/256)
prophoto-compat ProPhoto-compatible (ROMM primaries, D50, gamma 1.8)
linear-srgb sRGB primaries, linear
rec2020 Rec. 2020 primaries, Rec. 709 OETF
gray-gamma-2.2, sgray gray gamma 2.2; gray with the sRGB curve (default gray working space)
lab-d50 Lab identity (v4 encoding)
coated-cmyk PhotoCraft Coated CMYK (synthetic, 300% TAC, medium GCR) — default CMYK

The CMYK profile

Adobe's CMYK profiles (U.S. Web Coated SWOP, Coated FOGRA39) are proprietary, and the freely downloadable characterisation-based profiles (ECI/FOGRA, colord, Ghostscript) carry redistribution conditions or unclear licences, so PhotoCraft generates its own (src/synth.rs): a Yule–Nielsen modified Neugebauer model (n = 2) over the 16 overprints with ISO 12647-2 coated-paper Lab aims for paper/C/M/Y/RGB overprints, parabolic dot gain (14 % CMY, 17 % K at 50 %), GCR black generation (starts at 20 % gray component, K max 95 %), total ink limit 300 %, perceptual tables with L* black-point scaling and soft chroma compression against a sampled gamut boundary. profiles/photocraft-coated-cmyk.icc (237 KB, AToB 11⁴ lut16, BToA 21³ lut16) is that output, dedicated to the public domain (CC0-1.0). Regenerate with

PHOTOCRAFT_REGEN_PROFILES=1 cargo test -p photocraft-cms --release --test regen

It is a plausible coated-offset profile, not a measured characterisation: use your printer's profile for production print.

Not implemented / approximate

  • v4.4 mpet (multiProcessElements, D2Bx/B2Dx) tags, named colour, device link and abstract profiles as transform endpoints, chad-based adaptation of v2 absolute colorimetry.
  • BPC destination black uses the BToA/AToB round trip directly (Adobe's curve fit for ill-behaved LUT profiles is not implemented); v2/v4 perceptual reference black mixing is not modelled beyond the PRMG black for v4 LUT profiles.
  • Profile ID (MD5) is not computed when writing (left zero, which the spec allows).