4.7 KiB
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 withCmsError::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).