mirror of
https://github.com/storytold/photocraft.git
synced 2026-10-26 02:47:07 -06:00
85 lines
4.7 KiB
Markdown
85 lines
4.7 KiB
Markdown
# 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
|
||
|
||
```rust
|
||
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
|
||
|
||
```sh
|
||
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).
|