Skip to content

Bucket A.1: tone curve (tonecurve mv5) Path C decoder — needs darktable session for baseline #94

@chipi

Description

@chipi

Split out from #90 — A.1 was deferred during the v1.8.0 Bucket A pass because it has a meaningfully different cost shape from the other A items.

Why this needs its own issue

The other Bucket A items (A.2 dehaze, A.3 tint, A.5 Color Grading, A.6 Texture) all decode short flat structs (16–60 bytes, scalar fields). The tonecurve mv5 struct is qualitatively different:

```c
typedef struct dt_iop_tonecurve_params_t
{
dt_iop_tonecurve_node_t tonecurve[3][20]; // 3 channels x 20 nodes x (x,y) = 480 bytes
int tonecurve_nodes[3]; // active node count per channel = 12 bytes
int tonecurve_type[3]; // curve interpolation type per channel = 12 bytes
dt_iop_tonecurve_autoscale_t tonecurve_autoscale_ab; // 4 bytes
int tonecurve_preset; // 4 bytes
int tonecurve_unbound_ab; // 4 bytes
dt_iop_rgb_norms_t preserve_colors; // 4 bytes
} dt_iop_tonecurve_params_t;
```

Total: 520 bytes, with the dominant payload being 60 (x,y) float pairs.

Why darktable session is needed

Constructing a 520-byte tonecurve op_params from struct knowledge alone is risky:

  1. The 60 node slots are mostly inactive — tonecurve_nodes[i] says how many of the 20 are real. The unused-slot bytes might be zero, might be uninitialized garbage, might be set by darktable on save. No empirical baseline = no way to verify.
  2. The tonecurve_type[i] enum + tonecurve_autoscale_ab enum + preserve_colors enum each have several legal values. The safe-to-ship default isn't obvious from the source.
  3. Curve nodes need to be photographically meaningful. A decoder that pins arbitrary node positions wouldn't pass visual review; we want presets a photographer would recognize (S-curve, lifted shadows, filmic etc).

The clean path is: open darktable's GUI, draw 3-4 known curves (identity, gentle S-curve, lifted shadows, filmic), export each as .dtstyle, capture the bytes. Those become both the empirical baseline for the decoder AND the discrete vocabulary entries. Then the parameterized version can synthesize curves between them.

Scope

  1. Capture baselines from darktable GUI — author 4 reference dtstyles in darktable, export, drop into vocabulary/packs/expressive-baseline/layers/L3/tonecurve/:
    • tone_identity.dtstyle — straight-line baseline (bytes for an unmodified curve)
    • curve_filmic_subtle.dtstyle — mild S-curve
    • curve_filmic_strong.dtstyle — stronger S-curve
    • curve_lifted_shadows.dtstyle — lifted blacks, rolled highlights
  2. Reverse-engineer the 520-byte struct against these baselines — diff the bytes between identity and each preset to confirm offsets for the L curve's first few nodes.
  3. Build the decoder at src/chemigram/core/parameterize/tonecurve.py with at minimum a "node-pull" parameterization (e.g. --param shadow_pull=V moves the low-end node up/down by V).
  4. Register in _PATCH_REGISTRY, _modversion_drift, and _AXIS_FIELD_INDICES-style table if the patch function would otherwise hit C901.
  5. Ship the parameterized tonecurve entry with at least one axis (likely s_curve_strength or shadow_pull).
  6. 5-layer coverage per ADR-080.

What to expect on ship

  • Brings Lightroom daily-use parity from 19/23 to 20/23.
  • 14th Path C decoder.
  • 31st parameterized entry.
  • This issue's complexity is real but bounded — once the empirical baselines exist, the decoder shape is well-understood from prior bytes-diff exercises (saw it work cleanly on toneequalizer and colorbalancergb, both larger structs than tonecurve).

Reference

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions