Spec baseline exposure, Camera Raw tone and profile sync (D21)
camera-profiles.md §11-§14 close what 0.20.0 left open. Baseline exposure is the file's plus the profile's offset, applied as a gain on the camera matrix, and a copied profile carries the DNG's baseline so a CR2 lands at the same brightness. The view transform gains a Camera Raw curve — the profile's ProfileToneCurve, else the ACR3 default — applied Camera Raw's way, on the outer channels in linear ProPhoto, and it is the default for every raw (D21, the user's choice). Profiles sync through .darkroom-derived/profiles on the server as a step of the derived sync pass, not as a catalog table.
This commit is contained in:
+115
-10
@@ -172,22 +172,17 @@ action sits on that line.
|
||||
|
||||
## 6. Not done, and why
|
||||
|
||||
- **`ProfileToneCurve` is read and ignored.** D19 gives tone to the view transform, one for every
|
||||
body, and rejected per-body curves as its defaults. A profile's curve is a per-body curve. If it
|
||||
comes back, it comes back as an option of the view transform, not as a stage here. The 6D's
|
||||
Adobe Standard has none, so the case that matters today loses nothing.
|
||||
- **`BaselineExposure` is not applied** (it is not today either). Adobe Standard was tuned with it,
|
||||
and the 6D's is +0.25 EV. Separate change; it moves every photograph's brightness.
|
||||
- ~~**`ProfileToneCurve` is read and ignored.**~~ *Done after 0.20.0: §12, D21.* It came back as
|
||||
an option of the view transform, as this bullet said it would, and that option is the default
|
||||
for raws.
|
||||
- ~~**`BaselineExposure` is not applied.**~~ *Done after 0.20.0: §11.*
|
||||
- **The interpolation follows the as-shot neutral, not the white-balance slider**, as the matrix
|
||||
does. Camera Raw re-blends on every temperature change; doing so here means the matrix moves too,
|
||||
which is its own change.
|
||||
- **Masks select on the matrix's colour.** A colour-range mask sees colour before the profile, as
|
||||
it sees colour before every other operation. Deterministic, and a mask is drawn on the picture
|
||||
the user sees only approximately anyway.
|
||||
- **The profiles directory does not sync.** A CR2 rendered on a desktop with a copied 6D profile
|
||||
and on a tablet without one will differ. The panel line says which profile each device used, so
|
||||
the difference is visible rather than silent. Syncing the directory with the library is the
|
||||
follow-up.
|
||||
- ~~**The profiles directory does not sync.**~~ *Done after 0.20.0: §13.*
|
||||
- **Rec.2020 working primaries** stay deferred (D19); nothing here depends on them.
|
||||
|
||||
## 7. What it costs
|
||||
@@ -256,3 +251,113 @@ is inside its control's range, and every preset changes something.
|
||||
4. `dr-ui`: profile line, copy-out action, labels; the profiles directory set at start-up on
|
||||
desktop and Android.
|
||||
5. The *Vivid* presets.
|
||||
|
||||
---
|
||||
|
||||
# After 0.20.0: tone, exposure and sync
|
||||
|
||||
0.20.0 shipped the tables and §1's measurement showed they were not the gap to Lightroom's colour.
|
||||
The three items §6 left open are closed here. Draft of 2026-10-03.
|
||||
|
||||
## 11. Baseline exposure
|
||||
|
||||
`BaselineExposure` (DNG tag 50730) is the stops a converter adds so a camera's middle grey lands
|
||||
where its maker meant it; the 6D's DNGs say +0.25. `BaselineExposureOffset` (51109) is a profile's
|
||||
correction to it. The DNG SDK's total is their sum, and so is this one's.
|
||||
|
||||
- **Applied as a gain on the camera matrix** in `dr-gpu` when a raw is uploaded:
|
||||
`cam_to_srgb · 2^total`. A uniform gain commutes with every scene operation before the view
|
||||
transform, and the camera-space tap and the white-balance probe read camera RGB before the
|
||||
matrix, so neither changes. `RawImage::color_matrix` itself stays the file's: a merge writes a
|
||||
linear DNG from it and must not bake a gain into the pixels it also declares in a tag.
|
||||
- **A copied profile carries the DNG's baseline.** When an embedded profile is saved as a `.dcp`
|
||||
(§4) its `BaselineExposureOffset` is written as the DNG's `BaselineExposure` plus the profile's
|
||||
own offset. A CR2 has no baseline of its own, so its total is then the DNG's: the two files of
|
||||
one body render at one brightness. The cost: a DNG that embeds no profile, carries its own
|
||||
baseline, and matches a copied `.dcp` counts the baseline twice. Every Adobe-written DNG embeds
|
||||
its profile, so that DNG is a hand-made one.
|
||||
|
||||
## 12. Camera Raw tone (D21)
|
||||
|
||||
Lightroom's richer colour is its tone curve (§1). Camera Raw renders a raw through the profile's
|
||||
`ProfileToneCurve`, or, for a profile that has none — Adobe Standard among them — through the
|
||||
*ACR3 default curve*, a 1025-point table published in the DNG SDK and carried by RawTherapee
|
||||
(GPLv3) as `adobe_camera_raw_default_curve`.
|
||||
|
||||
**How it is applied** is half of what it does. Camera Raw does not run the curve on each channel:
|
||||
`RefBaselineRGBTone` runs it on the largest and smallest channel and places the middle one at the
|
||||
same fraction between them as before. Hue is kept; saturation rises where the curve is steep —
|
||||
the shadows and midtones — which is exactly where Adobe Standard's look table desaturated to
|
||||
compensate. It runs in linear ProPhoto, on values clipped to `[0, 1]`, and its output is linear.
|
||||
|
||||
**As the view transform**, not as a stage. D19 has one rendering, last; this is a second kind of
|
||||
that rendering, chosen by a new parameter on `view_transform`:
|
||||
|
||||
| `curve` | What it is | Default for |
|
||||
|---|---|---|
|
||||
| Camera Raw | the profile's curve, else ACR3, via RGBTone in ProPhoto | every raw (D21) |
|
||||
| Sigmoid | D19's log-logistic curve | — |
|
||||
|
||||
A JPEG is still not rendered again (FR-DEV-3j). Film simulation still replaces the view transform
|
||||
when a stock is chosen.
|
||||
|
||||
**The two sliders keep meaning something** under Camera Raw:
|
||||
|
||||
- `white` (stops above grey at which the scene reaches display white) sets the input scale:
|
||||
`2^(4 − white)`. At its default of 4 the scale is 1 — sensor white is display white, as in
|
||||
Camera Raw.
|
||||
- `contrast` bends the input about middle grey before the curve, as a power of
|
||||
`contrast / 1.4`: 1 at its default, so the curve is Camera Raw's untouched.
|
||||
|
||||
**What the ACR curve gives up** is D19's shoulder. Values above display white clip, as they do
|
||||
in Camera Raw; highlight recovery is the highlights slider's job before it. Sigmoid stays one
|
||||
click away for a photograph that wants the shoulder.
|
||||
|
||||
**A profile's own curve** is a list of `(x, y)` pairs. It is resampled at decode onto the same
|
||||
1025 points with a natural cubic spline, the DNG SDK's `dng_spline_solver`. A curve that is the
|
||||
identity is treated as absent, as RawTherapee does.
|
||||
|
||||
**On the GPU** the curve rides in the profile buffer (`@binding(8)`) after the tables: a third
|
||||
header entry gives its length, then the samples. The placeholder bound for a source without a
|
||||
profile carries the ACR3 curve, so a CR2 with no `.dcp` still renders through Camera Raw's tone.
|
||||
|
||||
## 13. Profiles sync
|
||||
|
||||
The profiles directory travels with the library, in the server folder that already carries what
|
||||
every device must agree on: `<library root>/.darkroom-derived/profiles/`. The scanner excludes
|
||||
its parent, as it excludes the trash.
|
||||
|
||||
- **A step of the derived sync pass** (`derived_sync::run`), after the catalog and before the
|
||||
place file, and like the place file it never fails the pass. It lists the server folder and the
|
||||
local one; uploads every local `.dcp` the server lacks, or holds at a different size; downloads
|
||||
every one the device lacks, reading through a placeholder where the library is a synced folder,
|
||||
and writing `.tmp` then renaming so a half-written file is never parsed. If it fetched
|
||||
anything, it reloads the profile set.
|
||||
- **Files are immutable and named for what they hold** (`<camera> <profile>.dcp`), so a name and a
|
||||
size say whether two copies are the same. Two devices that copy the same profile write the same
|
||||
name; neither wins over anything.
|
||||
- **Not a catalog table.** A schema change stops an older peer merging the catalog at all
|
||||
(see the memory of 0.13.3), and a blob of ~120 KB would ride in every catalog upload.
|
||||
- **One directory per install**, the union of every library's profiles. A profile describes a
|
||||
camera, not a library, so a profile one library brought is right for the same camera in
|
||||
another.
|
||||
- **Not handled: deleting.** There is no way to remove a profile from the app; a file removed by
|
||||
hand on one device comes back from the server on the next pass. A tombstone list is the
|
||||
follow-up if deleting is added.
|
||||
|
||||
## 14. Acceptance for §11–§13
|
||||
|
||||
- The ACR3 table is 1025 points from 0 to 1, monotone, and matches RawTherapee's values.
|
||||
- RGBTone: grey goes through the curve unchanged in hue; a colour keeps its hue (the middle
|
||||
channel's fraction between the outer two is unchanged); a curve that is the identity changes
|
||||
nothing; the shader agrees with the CPU reference on a device.
|
||||
- Camera Raw is the default curve for a raw; Sigmoid at the defaults renders to the bit what 0.20.0
|
||||
rendered without baseline exposure.
|
||||
- A DNG with `BaselineExposure` +0.25 renders a flat grey 0.25 EV brighter than the same pixels
|
||||
with none; a `.dcp` copied from it carries `BaselineExposureOffset` 0.25 and gives a CR2 the same
|
||||
total.
|
||||
- A profile resampled from `(0,0) (0.5,0.6) (1,1)` passes through its points.
|
||||
- Sync: a `.dcp` present only locally is uploaded; one present only on the server is downloaded,
|
||||
parsed and matched on the next decode; a file of the same name and size is left alone.
|
||||
- Measured again on `_MG_9080`: mean saturation at defaults closer to Lightroom's 0.49 than 0.20.0's
|
||||
0.35.
|
||||
|
||||
@@ -2437,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 |
|
||||
| D21 | Camera Raw tone for raws | **DECIDED 2026-10-03** — the view transform gains a Camera Raw curve (profile's, else ACR3 default, via RGBTone in ProPhoto), the default for every raw; Sigmoid stays a choice |
|
||||
| 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
|
||||
@@ -2772,6 +2773,28 @@ 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.
|
||||
|
||||
### D21 — Camera Raw tone for raws · **DECIDED 2026-10-03**
|
||||
|
||||
**The view transform has two curves, and Camera Raw's is the default for every raw.** It is the
|
||||
profile's `ProfileToneCurve`, or the ACR3 default curve where the profile has none or there is no
|
||||
profile, applied Camera Raw's way — on the largest and smallest channel in linear ProPhoto, the
|
||||
middle placed proportionally — after `BaselineExposure`. D19's sigmoid stays as the other choice.
|
||||
Design: [camera-profiles.md](camera-profiles.md) §11–§13.
|
||||
|
||||
*Why.* Measured on the library's 6D DNGs after D20 (camera-profiles.md §1): the profile tables
|
||||
lowered saturation, because Adobe's look tables were tuned to sit under this curve. The user's
|
||||
complaint was that Lightroom's rendering is more colourful, and this curve is most of the reason.
|
||||
Chosen by the user over limiting it to raws with a profile, or making it opt-in.
|
||||
|
||||
*What it reverses in D19.* D19 rejected per-body curves as defaults because their provenance was
|
||||
unknown. A DCP's curve and the ACR3 table have known provenance — Adobe's, published — and so the
|
||||
objection that retired the base curves does not apply. D19's other half stands: nothing before
|
||||
the view transform clamps, and the curve is the view transform, last.
|
||||
|
||||
*What it costs.* Every raw renders differently again, and highlights above display white clip
|
||||
where the sigmoid rolled them off; Sigmoid is one click away. Previews refresh only when rendered
|
||||
again; tablet and desktop release together.
|
||||
|
||||
### D16 — plugin licensing · **OPEN, post-v1**
|
||||
|
||||
> Deferred with §3.10 on 2026-09-19. Still to be answered before the format is published as
|
||||
|
||||
Reference in New Issue
Block a user