Spec DCP camera profiles (D20)

The library's Canon 6D DNGs were written by Lightroom and embed Adobe
Standard with its HueSatMap and LookTable; DarkRoom renders them through
the matrix alone, which is most of why the same file looks flatter here
than in Lightroom.

camera-profiles.md designs the deferred half of FR-DEV-3e: the tables
applied by a camera_profile scene operation after exposure, the profile
taken from the DNG or from a matched .dcp, tables carried with the
decoded image like the matrix, a look-strength control, and copying an
embedded profile out where its policy allows. FR-DEV-3e gains item 4
and D20 records the placement and what was rejected.
This commit is contained in:
2026-10-02 22:37:58 -04:00
parent 0b06e31bf3
commit 05ac2416c6
2 changed files with 278 additions and 2 deletions
+40 -2
View File
@@ -433,9 +433,18 @@ camera RGB, where its multipliers are defined, and every other operation receive
colour. Before D19 the edits ran in camera RGB and the matrix came after them, so a hue in the
colour mixer and the weights in `luminance()` meant something different on every body.
**Deferred but not foreclosed:** full `.dcp` support with `HueSatDeltas`, `ProfileLookTable`, and
~~**Deferred but not foreclosed:** full `.dcp` support with `HueSatDeltas`, `ProfileLookTable`, and
dual-illuminant interpolation. The stage shall be structured so these are additions rather than a
pipeline reordering.
pipeline reordering.~~ *Amended 2026-10-02 (D20):* dual-illuminant interpolation of the matrices
was built with item 1. The tables follow, designed in [camera-profiles.md](camera-profiles.md):
4. **DCP tables.** `ProfileHueSatMap` (both illuminants, blended as the matrices are) and
`ProfileLookTable`, read from the profile embedded in a DNG or from a `.dcp` file in the
profiles directory matched by `UniqueCameraModel`, the embedded one first. They are applied by a
`camera_profile` scene operation after exposure, with a switch and a look strength (0–200 %),
on by default where a profile exists. `ProfileToneCurve` is read and not applied: tone is the
view transform's (D19). An embedded profile whose `ProfileEmbedPolicy` allows copying can be
saved as a `.dcp` for other files from the same body. The application ships no profile.
Rationale for the reduced scope: a bare 3×3 matrix produces the flat, poor-skin-tone rendering
characteristic of dcraw defaults, which is the documented reason people abandon darktable in the
@@ -448,6 +457,9 @@ measurements, and their provenance was not known well enough to keep them as def
*Acceptance:* the default render is subjectively comparable to the camera's own JPEG — through
FR-DEV-3j's default, for every body. ΔE2000 validation against ColorChecker references applies
once DCP support lands.
For item 4: the lookup follows the DNG SDK's on `[0, 1]` and leaves values above 1.0 above it;
grey and an identity table pass through unchanged; the shader agrees with the CPU reference; with
the switch off, or no profile, the render is unchanged to the bit (camera-profiles.md §8).
**FR-DEV-3f — Look emulation.** Support HaldCLUT import, which inherits the existing free film
simulation ecosystem at near-zero implementation cost, plus reading the in-RAF film simulation tag
@@ -2425,6 +2437,7 @@ Rationale, evidence, and the eliminated alternatives are recorded in
| D12 | Scope versus pace | **DECIDED 2026-09-19** — settled by events; full scope stands, no v1 date |
| D18 | Derived images | **DECIDED 2026-09-19** — a merge writes a new source file; no multi-source Version |
| D19 | Scene-referred pipeline | **DECIDED 2026-09-27** — edits on unbounded scene-linear colour; one view transform, last; per-body base curves retired |
| D20 | DCP camera profiles | **DECIDED 2026-10-02** — HueSatMap and LookTable as a scene operation after exposure; embedded profile first, then a matched `.dcp`; tone curve not applied; none shipped |
### D11 — product positioning
@@ -2730,6 +2743,31 @@ unbounded, but several fragments floor at zero, which clips a colour outside sRG
mixer's bands and the colour grading wheel would need their hues re-measured. Gamut compression
beyond the output transform's clip goes with it.
### D20 — DCP camera profiles · **DECIDED 2026-10-02**
**A camera profile's `HueSatMap` and `LookTable` are applied by a `camera_profile` scene
operation at order 25, after exposure, converting into linear ProPhoto and back inside its own
fragment.** Design and the full argument: [camera-profiles.md](camera-profiles.md).
*Why now.* The library's 9,348 Canon 6D DNGs carry Adobe Standard's tables, which Lightroom
rendered them through, and DarkRoom ignored them. That gap is most of why the same file looks
flatter here.
*Why there.* The matrix snippet stays what D19 made it, and every copy of it (masks, picker,
camera-space tap) stays correct without changing. Hue and saturation are invariant under the
uniform gains that precede order 25, so a 2.5-D HueSatMap gives the same answer there as straight
after the matrix, and the LookTable sees the photographer's exposure, as it does in the SDK.
*Rejected.* Extending the matrix snippet: every duplicate of it would have had to follow. Two
operations, one per table: the HueSatMap has no control of its own and commutes to the same place.
Applying `ProfileToneCurve`: a per-body tone curve is what D19 retired. Shipping Adobe's profiles:
they are not ours to ship. Handing the tables to the graph through a setter, as lens profiles are:
every render path would have to remember to call it. They travel with the decoded image, as the
matrix does.
*What it costs.* Every DNG with an embedded profile renders differently; previews refresh only when
rendered again; tablet and desktop release together. The profiles directory does not sync yet.
### D16 — plugin licensing · **OPEN, post-v1**
> Deferred with §3.10 on 2026-09-19. Still to be answered before the format is published as