diff --git a/core/dr-pipeline/ops/vignetting.yaml b/core/dr-pipeline/ops/vignetting.yaml new file mode 100644 index 0000000..879faa6 --- /dev/null +++ b/core/dr-pipeline/ops/vignetting.yaml @@ -0,0 +1,40 @@ +# A hand-written node, and the first thing in `Attribute::Optics`. +# +# Written, tested and unreferenced until now: `src/ops/vignetting.rs` has +# existed with a full descriptor and a working polynomial, and without an entry +# here it was never in `chain()` — so it reached no photograph and no panel. +# This file is the whole of what was missing, which is the point of `ops/` +# being the one place the pipeline's order is written down. +id: vignetting +order: 5 + +attributes: [optics] +rust: Vignetting + +why_rust: | + It carries a lens profile's `pa` coefficients, which are not parameters: they + come from the body and lens that took the photograph, not from the + photographer, and no `uniforms:` expression could produce them. The one + parameter that *is* theirs — the manual trim — is composed with `k1` in Rust, + because the profile and the trim have to reach the shader as a single + polynomial rather than as two the fragment would have to add up. + +placement: | + First in the chain, ahead of white balance and exposure. + + Vignetting is what the lens did to the light before the sensor measured it, + so undoing it belongs with reading the file rather than with editing the + picture — everything downstream is then working on the frame the lens would + have delivered had it been even. + + The ordering is load-bearing rather than tidy. Correcting a corner means + *dividing* by an attenuation below one, which pushes those pixels up: a fast + prime wide open needs about two stops there. Run after the tonal stages, that + recovery happens once the highlights have already been rolled off and + clipped, so it lifts values that no longer have anywhere to go and the + corners posterise instead of brightening. Run here, the headroom to hold them + still exists (ARCH §5.2). + + Before distortion and chromatic aberration in intent, though those are + `lens::Warp`s rather than nodes and compose ahead of the fetch, so no `order:` + relates the two. diff --git a/core/dr-pipeline/src/framing.rs b/core/dr-pipeline/src/framing.rs index a8737c4..646a960 100644 --- a/core/dr-pipeline/src/framing.rs +++ b/core/dr-pipeline/src/framing.rs @@ -893,9 +893,16 @@ impl Framing { /// The WGSL mapping an output pixel to a **normalised centred** source /// position, ready for the warp chain. /// - /// Leaves the result in `p`: centre `(0, 0)`, `r == 1` at the corner — - /// exactly the space [`crate::lens`] documents, so lens correction - /// composes on top of this without either stage naming the other. + /// Leaves the result in `p`: centre `(0, 0)`, spanning `±0.5 * aspect` — + /// the space [`crate::lens`] documents, so lens correction composes on top + /// of this without either stage naming the other. + /// + /// **`p` is centred but not corner-normalised**, and this used to claim it + /// was. Its length at the corner is `0.5 * length(aspect)`, not 1. The + /// corner-normalised radius the radial corrections need is published + /// separately as `radius` by `operation::sample_source`, which divides by + /// exactly that; anything reading `length(p)` as a lens radius is off by + /// an aspect-dependent factor. /// /// `aspect` is left in scope alongside it, since the warp chain and the /// sampler both need it to return to texture coordinates. diff --git a/core/dr-pipeline/src/lens.rs b/core/dr-pipeline/src/lens.rs index a1753f7..f545c1d 100644 --- a/core/dr-pipeline/src/lens.rs +++ b/core/dr-pipeline/src/lens.rs @@ -41,6 +41,12 @@ //! `(0, 0)`, and the radius is scaled so that `r == 1` at the corner. Both //! properties matter. //! +//! Note which variable carries which. The shader's `p` supplies the centring +//! and spans `±0.5 * aspect`; the corner normalisation is applied on top of it +//! by `operation::sample_source`, which publishes the result as `radius`. A +//! warp reading `length(p)` and calling it `r` would be evaluating its +//! polynomial short of where the profile was fitted. +//! //! Centring is what makes the polynomial meaningful — lens distortion is //! radially symmetric about the optical axis, so a formula written about any //! other origin would need cross terms to say the same thing. diff --git a/core/dr-pipeline/src/mask.rs b/core/dr-pipeline/src/mask.rs index 5d5cc53..86b2db2 100644 --- a/core/dr-pipeline/src/mask.rs +++ b/core/dr-pipeline/src/mask.rs @@ -55,7 +55,7 @@ use std::fmt::Write as _; use std::sync::Arc; use crate::coverage::Coverage; -use crate::descriptor::{OpDescriptor, ParamId}; +use crate::descriptor::{Attribute, OpDescriptor, ParamId}; use crate::operation::Operation; use crate::ops; @@ -777,8 +777,8 @@ pub struct MaskLayer { pub ops: Vec>, } -/// The chain a mask layer holds: every point operation, and none of the -/// neighbourhood ones. +/// The chain a mask layer holds: every point operation, and neither the +/// neighbourhood ones nor the optical corrections. /// /// A layer's adjustments are fused into the colour dispatch and multiplied by /// the mask afterwards, which is exactly why a layer needs no per-operation @@ -795,10 +795,26 @@ pub struct MaskLayer { /// Filtering here means a local sharpening or denoise control simply does not /// appear until there is a stage that can honour it, which is the honest /// state of affairs. +/// **The optical corrections are excluded on their own grounds**, which are +/// not the neighbourhood argument above: they would work perfectly and mean +/// nothing. +/// +/// `Attribute::Optics` describes what the *lens* did to the whole frame. Its +/// corrections are radial about the optical axis, and the `radius` they read +/// is the distance from the centre of the photograph — a layer's mask does not +/// and cannot move it. So a vignetting slider inside a mask would not correct +/// the falloff within the selected region; it would lay a frame-centred radial +/// ramp over the picture and then multiply it by the mask. That is a +/// well-defined operation nobody would ever want, and worse, it is one whose +/// name promises something else entirely. +/// +/// The general rule the two exclusions share: a layer holds an operation only +/// where restricting it to a region is a thing a photographer could mean. fn layer_chain() -> Vec> { ops::chain() .into_iter() .filter(|o| o.detail().is_none()) + .filter(|o| !o.descriptor().attributes.contains(&Attribute::Optics)) .collect() } @@ -1463,33 +1479,49 @@ mod tests { #[test] fn a_layer_offers_only_the_operations_it_can_actually_apply() { + // Two exclusions, for two different reasons, and the test states both + // because they fail in different ways. + // // A layer's adjustments are fused into the colour dispatch and then // multiplied by the mask. A neighbourhood operation cannot take that // route: it is a dispatch of its own, run after the fused pass and // after the masks are already applied, so there is nowhere to hand it - // one layer's mask. + // one layer's mask. Left in, it moves and nothing happens. + // + // An optical correction *can* take that route, and that is the + // problem. It is radial about the frame's optical axis, which a mask + // cannot move, so it would lay a frame-centred ramp over the whole + // picture and multiply it by the mask. Left in, it moves and the wrong + // thing happens — under a name that promises the right one. // // The panel builds itself from `capabilities()` and names no - // operation, so anything left in this chain becomes a control. One - // that cannot work is worse than one that is missing: it moves, the - // picture does not change, and nothing says why. + // operation, so anything left in this chain becomes a control. let layer = lit_layer("m1", 1.0); let ids: Vec<&str> = layer.capabilities().iter().map(|c| c.id.0).collect(); let global = crate::ops::chain(); + let local_means_something = |op: &Box| { + op.detail().is_none() + && !op + .descriptor() + .attributes + .contains(&crate::descriptor::Attribute::Optics) + }; + for op in &global { let id = op.descriptor().id.0; assert_eq!( ids.contains(&id), - op.detail().is_none(), - "{id} is offered as a local adjustment but cannot be one, \ - or is a point operation and has gone missing from a layer" + local_means_something(op), + "{id} is offered as a local adjustment but cannot meaningfully \ + be one, or is an ordinary point operation and has gone \ + missing from a layer" ); } assert!( - ids.len() < global.len() || global.iter().all(|o| o.detail().is_none()), + ids.len() < global.len() || global.iter().all(local_means_something), "the filter dropped nothing, so either it is not running or the \ - chain has no neighbourhood operation left to drop" + chain has nothing left that a layer cannot carry" ); // And a clone must rebuild the same chain: it copies parameters across diff --git a/core/dr-pipeline/src/operation.rs b/core/dr-pipeline/src/operation.rs index cebcf2f..0e58330 100644 --- a/core/dr-pipeline/src/operation.rs +++ b/core/dr-pipeline/src/operation.rs @@ -1074,6 +1074,23 @@ pub(crate) fn sample_source(interpolate: bool) -> &'static str { let source_px = uv_src * vec2(src_dims); // A free angle puts output pixels between source pixels. Nearest-neighbour // here is what makes a straightened horizon stair-step, so interpolate. + // Distance from the optical axis, normalised so the corner is exactly 1. + // + // Published beside `source_px` and for the same reason: a fragment is + // handed a colour with no way back to a coordinate, and the radial + // corrections need one. Derived from `p` after the whole coordinate stage, + // so it measures the *source* frame — which is what a lens profile is + // calibrated against, and why an off-centre crop still gets the falloff + // its corner actually had rather than one centred on the crop. + // + // **The division is the part that is easy to leave out.** `p` spans + // `+/-0.5 * aspect`, so at the corner its length is `0.5 * length(aspect)` + // -- about 0.901 on a 3:2 frame, not 1. Lensfun's polynomials are fitted + // against a corner radius of 1, so passing `length(p)` straight in + // evaluates every one of them short of where it was measured, and by an + // amount that changes with the aspect ratio. It reads as a correction that + // is simply too weak, which is indistinguishable from a bad profile. + let radius = length(p) / (0.5 * length(aspect)); var c = sample_bilinear(uv_src, src_dims); " } else { @@ -1101,6 +1118,23 @@ pub(crate) fn sample_source(interpolate: bool) -> &'static str { // put, and its *amount* is handled separately by how much film a pixel // covers -- see `dr_film::Grain`. let source_px = uv_src * vec2(src_dims); + // Distance from the optical axis, normalised so the corner is exactly 1. + // + // Published beside `source_px` and for the same reason: a fragment is + // handed a colour with no way back to a coordinate, and the radial + // corrections need one. Derived from `p` after the whole coordinate stage, + // so it measures the *source* frame — which is what a lens profile is + // calibrated against, and why an off-centre crop still gets the falloff + // its corner actually had rather than one centred on the crop. + // + // **The division is the part that is easy to leave out.** `p` spans + // `+/-0.5 * aspect`, so at the corner its length is `0.5 * length(aspect)` + // -- about 0.901 on a 3:2 frame, not 1. Lensfun's polynomials are fitted + // against a corner radius of 1, so passing `length(p)` straight in + // evaluates every one of them short of where it was measured, and by an + // amount that changes with the aspect ratio. It reads as a correction that + // is simply too weak, which is indistinguishable from a bad profile. + let radius = length(p) / (0.5 * length(aspect)); var c = textureLoad(source, coord, 0).rgb; " } diff --git a/core/dr-pipeline/src/ops/mod.rs b/core/dr-pipeline/src/ops/mod.rs index 15b169a..46caca1 100644 --- a/core/dr-pipeline/src/ops/mod.rs +++ b/core/dr-pipeline/src/ops/mod.rs @@ -54,6 +54,14 @@ //! than `Operation`, because they rewrite *coordinates* before the source is //! sampled rather than transforming a colour after it. They are not part of //! the develop chain and do not appear in `ops/`. +//! +//! [`vignetting`] is the exception, and the reason the split is drawn at +//! coordinates rather than at "lens correction": it applies a gain to the +//! pixel already fetched, so it is an ordinary node in `ops/` like any other. +//! What it needs that a colour fragment is not otherwise given is the pixel's +//! distance from the optical axis, which the sampler publishes as `radius` +//! — corner-normalised there, because the profile coefficients are fitted +//! against a corner radius of 1 and the prologue's `p` is not. // Hand-written nodes. Each is listed in `ops/` with `rust:`, which is what // places it in the chain; these are the implementations that entry points at. diff --git a/core/dr-pipeline/tests/declared_parity.rs b/core/dr-pipeline/tests/declared_parity.rs index 3048e00..bce9d46 100644 --- a/core/dr-pipeline/tests/declared_parity.rs +++ b/core/dr-pipeline/tests/declared_parity.rs @@ -402,6 +402,7 @@ fn every_declared_node_is_checked() { "noise_reduction", "texture", "tone_curve", + "vignetting", ], "the set of hand-written nodes changed; if that is deliberate, update \ this list and the module documentation above" diff --git a/docs/traceability.md b/docs/traceability.md index da76c7e..29df6eb 100644 --- a/docs/traceability.md +++ b/docs/traceability.md @@ -9,7 +9,7 @@ Denominators are parsed from [`requirements.md`](requirements.md) at run time, n | Metric | Value | |---|---| -| Source files scanned | 334 | +| Source files scanned | 335 | | TRACES tags found | 1086 | | Requirements defined | 180 | | Requirements covered | 127 | @@ -60,15 +60,15 @@ _None._ | FR-DEV-1 | [`core/dr-pipeline/src/graph.rs:1`](../core/dr-pipeline/src/graph.rs#L1), [`core/dr-pipeline/src/sidecar.rs:1`](../core/dr-pipeline/src/sidecar.rs#L1) | | FR-DEV-2 | [`core/dr-pipeline/src/operation.rs:389`](../core/dr-pipeline/src/operation.rs#L389) | | FR-DEV-3 | [`core/dr-gpu/src/adjust.rs:2203`](../core/dr-gpu/src/adjust.rs#L2203), [`core/dr-gpu/src/adjust.rs:651`](../core/dr-gpu/src/adjust.rs#L651), [`core/dr-gpu/src/adjust.rs:770`](../core/dr-gpu/src/adjust.rs#L770), [`core/dr-gpu/src/adjust.rs:84`](../core/dr-gpu/src/adjust.rs#L84), [`core/dr-gpu/tests/tone_curve.rs:1`](../core/dr-gpu/tests/tone_curve.rs#L1), [`core/dr-pipeline/src/coverage.rs:122`](../core/dr-pipeline/src/coverage.rs#L122), [`core/dr-pipeline/src/coverage.rs:1`](../core/dr-pipeline/src/coverage.rs#L1), [`core/dr-pipeline/src/detail.rs:434`](../core/dr-pipeline/src/detail.rs#L434), [`core/dr-pipeline/src/detail.rs:524`](../core/dr-pipeline/src/detail.rs#L524), [`core/dr-pipeline/src/framing.rs:177`](../core/dr-pipeline/src/framing.rs#L177), [`core/dr-pipeline/src/framing.rs:234`](../core/dr-pipeline/src/framing.rs#L234), [`core/dr-pipeline/src/framing.rs:314`](../core/dr-pipeline/src/framing.rs#L314), [`core/dr-pipeline/src/framing.rs:498`](../core/dr-pipeline/src/framing.rs#L498), [`core/dr-pipeline/src/framing.rs:753`](../core/dr-pipeline/src/framing.rs#L753), [`core/dr-pipeline/src/graph.rs:170`](../core/dr-pipeline/src/graph.rs#L170), [`core/dr-pipeline/src/graph.rs:578`](../core/dr-pipeline/src/graph.rs#L578), [`core/dr-pipeline/src/mask.rs:151`](../core/dr-pipeline/src/mask.rs#L151), [`core/dr-pipeline/src/operation.rs:330`](../core/dr-pipeline/src/operation.rs#L330), [`core/dr-pipeline/src/operation.rs:516`](../core/dr-pipeline/src/operation.rs#L516), [`core/dr-pipeline/src/ops/capture_sharpen.rs:1`](../core/dr-pipeline/src/ops/capture_sharpen.rs#L1), [`core/dr-pipeline/src/ops/capture_sharpen.rs:210`](../core/dr-pipeline/src/ops/capture_sharpen.rs#L210), [`core/dr-pipeline/src/ops/curve.rs:100`](../core/dr-pipeline/src/ops/curve.rs#L100), [`core/dr-pipeline/src/ops/curve.rs:1`](../core/dr-pipeline/src/ops/curve.rs#L1), [`core/dr-pipeline/src/ops/curve.rs:219`](../core/dr-pipeline/src/ops/curve.rs#L219), [`core/dr-pipeline/src/ops/curve.rs:635`](../core/dr-pipeline/src/ops/curve.rs#L635), [`core/dr-pipeline/src/ops/local_contrast.rs:1`](../core/dr-pipeline/src/ops/local_contrast.rs#L1), [`core/dr-pipeline/src/ops/noise_reduction.rs:1`](../core/dr-pipeline/src/ops/noise_reduction.rs#L1), [`core/dr-pipeline/src/ops/noise_reduction.rs:273`](../core/dr-pipeline/src/ops/noise_reduction.rs#L273), [`core/dr-pipeline/src/sidecar.rs:1048`](../core/dr-pipeline/src/sidecar.rs#L1048), [`core/dr-pipeline/src/sidecar.rs:158`](../core/dr-pipeline/src/sidecar.rs#L158), [`core/dr-pipeline/src/sidecar.rs:1714`](../core/dr-pipeline/src/sidecar.rs#L1714), [`core/dr-pipeline/src/sidecar.rs:1774`](../core/dr-pipeline/src/sidecar.rs#L1774), [`core/dr-pipeline/tests/tone_curve.rs:1`](../core/dr-pipeline/tests/tone_curve.rs#L1), [`core/dr-segment/src/refine.rs:850`](../core/dr-segment/src/refine.rs#L850), [`ui/dr-ui/src/develop.rs:103`](../ui/dr-ui/src/develop.rs#L103), [`ui/dr-ui/src/develop.rs:1506`](../ui/dr-ui/src/develop.rs#L1506), [`ui/dr-ui/src/develop.rs:165`](../ui/dr-ui/src/develop.rs#L165), [`ui/dr-ui/src/develop.rs:1922`](../ui/dr-ui/src/develop.rs#L1922), [`ui/dr-ui/src/develop.rs:2136`](../ui/dr-ui/src/develop.rs#L2136), [`ui/dr-ui/src/develop.rs:2154`](../ui/dr-ui/src/develop.rs#L2154), [`ui/dr-ui/src/develop.rs:2168`](../ui/dr-ui/src/develop.rs#L2168), [`ui/dr-ui/src/develop.rs:2190`](../ui/dr-ui/src/develop.rs#L2190), [`ui/dr-ui/src/develop.rs:2336`](../ui/dr-ui/src/develop.rs#L2336), [`ui/dr-ui/src/develop.rs:2434`](../ui/dr-ui/src/develop.rs#L2434), [`ui/dr-ui/src/develop.rs:328`](../ui/dr-ui/src/develop.rs#L328), [`ui/dr-ui/src/develop.rs:365`](../ui/dr-ui/src/develop.rs#L365), [`ui/dr-ui/src/develop.rs:3855`](../ui/dr-ui/src/develop.rs#L3855), [`ui/dr-ui/src/develop.rs:3885`](../ui/dr-ui/src/develop.rs#L3885), [`ui/dr-ui/src/develop.rs:3951`](../ui/dr-ui/src/develop.rs#L3951), [`ui/dr-ui/src/develop.rs:3965`](../ui/dr-ui/src/develop.rs#L3965), [`ui/dr-ui/src/develop.rs:4157`](../ui/dr-ui/src/develop.rs#L4157), [`ui/dr-ui/src/develop.rs:4817`](../ui/dr-ui/src/develop.rs#L4817), [`ui/dr-ui/src/develop.rs:4938`](../ui/dr-ui/src/develop.rs#L4938), [`ui/dr-ui/src/develop.rs:5094`](../ui/dr-ui/src/develop.rs#L5094), [`ui/dr-ui/src/develop.rs:5230`](../ui/dr-ui/src/develop.rs#L5230), [`ui/dr-ui/src/develop.rs:5274`](../ui/dr-ui/src/develop.rs#L5274), [`ui/dr-ui/src/develop.rs:5324`](../ui/dr-ui/src/develop.rs#L5324), [`ui/dr-ui/src/develop.rs:588`](../ui/dr-ui/src/develop.rs#L588), [`ui/dr-ui/src/develop.rs:649`](../ui/dr-ui/src/develop.rs#L649), [`ui/dr-ui/src/develop.rs:795`](../ui/dr-ui/src/develop.rs#L795), [`ui/dr-ui/src/develop.rs:842`](../ui/dr-ui/src/develop.rs#L842), [`ui/dr-ui/src/develop.rs:871`](../ui/dr-ui/src/develop.rs#L871), [`ui/dr-ui/src/lib.rs:1696`](../ui/dr-ui/src/lib.rs#L1696), [`ui/dr-ui/src/lib.rs:2498`](../ui/dr-ui/src/lib.rs#L2498), [`ui/dr-ui/src/lib.rs:2694`](../ui/dr-ui/src/lib.rs#L2694), [`ui/dr-ui/src/lib.rs:2866`](../ui/dr-ui/src/lib.rs#L2866), [`ui/dr-ui/src/lib.rs:2930`](../ui/dr-ui/src/lib.rs#L2930), [`ui/dr-ui/src/lib.rs:2984`](../ui/dr-ui/src/lib.rs#L2984), [`ui/dr-ui/src/lib.rs:389`](../ui/dr-ui/src/lib.rs#L389), [`ui/dr-ui/src/lib.rs:432`](../ui/dr-ui/src/lib.rs#L432), [`ui/dr-ui/src/lib.rs:455`](../ui/dr-ui/src/lib.rs#L455), [`ui/dr-ui/src/library.rs:539`](../ui/dr-ui/src/library.rs#L539), [`ui/dr-ui/src/masks_ui.rs:249`](../ui/dr-ui/src/masks_ui.rs#L249), [`ui/dr-ui/src/masks_ui.rs:41`](../ui/dr-ui/src/masks_ui.rs#L41), [`ui/dr-ui/src/masks_ui.rs:884`](../ui/dr-ui/src/masks_ui.rs#L884), [`ui/dr-ui/src/masks_ui.rs:998`](../ui/dr-ui/src/masks_ui.rs#L998), [`ui/dr-ui/src/presets.rs:394`](../ui/dr-ui/src/presets.rs#L394), [`ui/dr-ui/src/segmentation.rs:116`](../ui/dr-ui/src/segmentation.rs#L116), [`ui/dr-ui/src/segmentation.rs:330`](../ui/dr-ui/src/segmentation.rs#L330), [`ui/dr-ui/src/segmentation.rs:346`](../ui/dr-ui/src/segmentation.rs#L346), [`ui/dr-ui/src/segmentation.rs:476`](../ui/dr-ui/src/segmentation.rs#L476), [`ui/dr-ui/src/segmentation.rs:504`](../ui/dr-ui/src/segmentation.rs#L504), [`ui/dr-ui/ui/adjust.slint:547`](../ui/dr-ui/ui/adjust.slint#L547), [`ui/dr-ui/ui/adjust.slint:666`](../ui/dr-ui/ui/adjust.slint#L666), [`ui/dr-ui/ui/app.slint:150`](../ui/dr-ui/ui/app.slint#L150), [`ui/dr-ui/ui/app.slint:196`](../ui/dr-ui/ui/app.slint#L196), [`ui/dr-ui/ui/app.slint:2046`](../ui/dr-ui/ui/app.slint#L2046), [`ui/dr-ui/ui/app.slint:984`](../ui/dr-ui/ui/app.slint#L984), [`ui/dr-ui/ui/masks.slint:612`](../ui/dr-ui/ui/masks.slint#L612) | -| FR-DEV-3a | [`core/dr-pipeline/ops/exposure.yaml:1`](../core/dr-pipeline/ops/exposure.yaml#L1), [`core/dr-pipeline/src/descriptor.rs:194`](../core/dr-pipeline/src/descriptor.rs#L194), [`core/dr-pipeline/src/descriptor.rs:234`](../core/dr-pipeline/src/descriptor.rs#L234), [`core/dr-pipeline/src/descriptor.rs:258`](../core/dr-pipeline/src/descriptor.rs#L258), [`core/dr-pipeline/src/descriptor.rs:313`](../core/dr-pipeline/src/descriptor.rs#L313), [`core/dr-pipeline/src/framing.rs:395`](../core/dr-pipeline/src/framing.rs#L395), [`core/dr-pipeline/src/graph.rs:24`](../core/dr-pipeline/src/graph.rs#L24), [`core/dr-pipeline/src/graph.rs:251`](../core/dr-pipeline/src/graph.rs#L251), [`core/dr-pipeline/src/graph.rs:46`](../core/dr-pipeline/src/graph.rs#L46), [`core/dr-pipeline/src/graph.rs:59`](../core/dr-pipeline/src/graph.rs#L59), [`core/dr-pipeline/src/mask.rs:1092`](../core/dr-pipeline/src/mask.rs#L1092), [`core/dr-pipeline/src/operation.rs:232`](../core/dr-pipeline/src/operation.rs#L232), [`core/dr-pipeline/src/operation.rs:365`](../core/dr-pipeline/src/operation.rs#L365), [`core/dr-pipeline/src/ops/curve.rs:319`](../core/dr-pipeline/src/ops/curve.rs#L319), [`ui/dr-ui/src/develop.rs:1403`](../ui/dr-ui/src/develop.rs#L1403), [`ui/dr-ui/src/lib.rs:749`](../ui/dr-ui/src/lib.rs#L749), [`ui/dr-ui/tests/ui_names_no_operation.rs:1`](../ui/dr-ui/tests/ui_names_no_operation.rs#L1) | +| FR-DEV-3a | [`core/dr-pipeline/ops/exposure.yaml:1`](../core/dr-pipeline/ops/exposure.yaml#L1), [`core/dr-pipeline/src/descriptor.rs:194`](../core/dr-pipeline/src/descriptor.rs#L194), [`core/dr-pipeline/src/descriptor.rs:234`](../core/dr-pipeline/src/descriptor.rs#L234), [`core/dr-pipeline/src/descriptor.rs:258`](../core/dr-pipeline/src/descriptor.rs#L258), [`core/dr-pipeline/src/descriptor.rs:313`](../core/dr-pipeline/src/descriptor.rs#L313), [`core/dr-pipeline/src/framing.rs:395`](../core/dr-pipeline/src/framing.rs#L395), [`core/dr-pipeline/src/graph.rs:24`](../core/dr-pipeline/src/graph.rs#L24), [`core/dr-pipeline/src/graph.rs:251`](../core/dr-pipeline/src/graph.rs#L251), [`core/dr-pipeline/src/graph.rs:46`](../core/dr-pipeline/src/graph.rs#L46), [`core/dr-pipeline/src/graph.rs:59`](../core/dr-pipeline/src/graph.rs#L59), [`core/dr-pipeline/src/mask.rs:1108`](../core/dr-pipeline/src/mask.rs#L1108), [`core/dr-pipeline/src/operation.rs:232`](../core/dr-pipeline/src/operation.rs#L232), [`core/dr-pipeline/src/operation.rs:365`](../core/dr-pipeline/src/operation.rs#L365), [`core/dr-pipeline/src/ops/curve.rs:319`](../core/dr-pipeline/src/ops/curve.rs#L319), [`ui/dr-ui/src/develop.rs:1403`](../ui/dr-ui/src/develop.rs#L1403), [`ui/dr-ui/src/lib.rs:749`](../ui/dr-ui/src/lib.rs#L749), [`ui/dr-ui/tests/ui_names_no_operation.rs:1`](../ui/dr-ui/tests/ui_names_no_operation.rs#L1) | | FR-DEV-3b | [`core/dr-pipeline/src/descriptor.rs:258`](../core/dr-pipeline/src/descriptor.rs#L258), [`core/dr-pipeline/src/framing.rs:395`](../core/dr-pipeline/src/framing.rs#L395), [`core/dr-pipeline/src/graph.rs:59`](../core/dr-pipeline/src/graph.rs#L59), [`core/dr-pipeline/src/operation.rs:365`](../core/dr-pipeline/src/operation.rs#L365) | -| FR-DEV-3c | [`core/dr-pipeline/ops/exposure.yaml:1`](../core/dr-pipeline/ops/exposure.yaml#L1), [`core/dr-pipeline/src/graph.rs:251`](../core/dr-pipeline/src/graph.rs#L251), [`core/dr-pipeline/src/graph.rs:46`](../core/dr-pipeline/src/graph.rs#L46), [`core/dr-pipeline/src/mask.rs:1092`](../core/dr-pipeline/src/mask.rs#L1092), [`ui/dr-ui/src/develop.rs:5903`](../ui/dr-ui/src/develop.rs#L5903) | +| FR-DEV-3c | [`core/dr-pipeline/ops/exposure.yaml:1`](../core/dr-pipeline/ops/exposure.yaml#L1), [`core/dr-pipeline/src/graph.rs:251`](../core/dr-pipeline/src/graph.rs#L251), [`core/dr-pipeline/src/graph.rs:46`](../core/dr-pipeline/src/graph.rs#L46), [`core/dr-pipeline/src/mask.rs:1108`](../core/dr-pipeline/src/mask.rs#L1108), [`ui/dr-ui/src/develop.rs:5903`](../ui/dr-ui/src/develop.rs#L5903) | | FR-DEV-3d | [`core/dr-gpu/src/adjust.rs:104`](../core/dr-gpu/src/adjust.rs#L104), [`core/dr-gpu/src/adjust.rs:1079`](../core/dr-gpu/src/adjust.rs#L1079), [`core/dr-gpu/src/adjust.rs:770`](../core/dr-gpu/src/adjust.rs#L770), [`core/dr-gpu/src/adjust.rs:84`](../core/dr-gpu/src/adjust.rs#L84), [`core/dr-gpu/src/adjust.rs:986`](../core/dr-gpu/src/adjust.rs#L986), [`core/dr-gpu/tests/capture_sharpen.rs:434`](../core/dr-gpu/tests/capture_sharpen.rs#L434), [`core/dr-gpu/tests/detail_stage.rs:242`](../core/dr-gpu/tests/detail_stage.rs#L242), [`core/dr-gpu/tests/local_contrast.rs:558`](../core/dr-gpu/tests/local_contrast.rs#L558), [`core/dr-gpu/tests/noise_reduction.rs:556`](../core/dr-gpu/tests/noise_reduction.rs#L556), [`core/dr-pipeline/src/framing.rs:314`](../core/dr-pipeline/src/framing.rs#L314), [`core/dr-pipeline/src/graph.rs:617`](../core/dr-pipeline/src/graph.rs#L617), [`core/dr-pipeline/src/operation.rs:32`](../core/dr-pipeline/src/operation.rs#L32), [`core/dr-pipeline/src/operation.rs:389`](../core/dr-pipeline/src/operation.rs#L389), [`core/dr-pipeline/src/operation.rs:53`](../core/dr-pipeline/src/operation.rs#L53), [`core/dr-pipeline/src/operation.rs:71`](../core/dr-pipeline/src/operation.rs#L71) | -| FR-DEV-3e | [`core/dr-decode/src/base_curve.rs:145`](../core/dr-decode/src/base_curve.rs#L145), [`core/dr-decode/src/base_curve.rs:158`](../core/dr-decode/src/base_curve.rs#L158), [`core/dr-decode/src/base_curve.rs:1`](../core/dr-decode/src/base_curve.rs#L1), [`core/dr-decode/src/base_curve.rs:267`](../core/dr-decode/src/base_curve.rs#L267), [`core/dr-decode/src/base_curve.rs:347`](../core/dr-decode/src/base_curve.rs#L347), [`core/dr-decode/src/base_curve.rs:55`](../core/dr-decode/src/base_curve.rs#L55), [`core/dr-decode/src/lib.rs:121`](../core/dr-decode/src/lib.rs#L121), [`core/dr-decode/src/lib.rs:708`](../core/dr-decode/src/lib.rs#L708), [`core/dr-decode/src/lib.rs:748`](../core/dr-decode/src/lib.rs#L748), [`core/dr-decode/src/profile.rs:102`](../core/dr-decode/src/profile.rs#L102), [`core/dr-decode/src/profile.rs:151`](../core/dr-decode/src/profile.rs#L151), [`core/dr-decode/src/profile.rs:1`](../core/dr-decode/src/profile.rs#L1), [`core/dr-decode/src/profile.rs:235`](../core/dr-decode/src/profile.rs#L235), [`core/dr-decode/src/profile.rs:286`](../core/dr-decode/src/profile.rs#L286), [`core/dr-decode/src/profile.rs:343`](../core/dr-decode/src/profile.rs#L343), [`core/dr-decode/src/profile.rs:458`](../core/dr-decode/src/profile.rs#L458), [`core/dr-decode/src/profile.rs:492`](../core/dr-decode/src/profile.rs#L492), [`core/dr-decode/src/profile.rs:630`](../core/dr-decode/src/profile.rs#L630), [`core/dr-gpu/src/adjust.rs:37`](../core/dr-gpu/src/adjust.rs#L37), [`core/dr-gpu/src/adjust.rs:967`](../core/dr-gpu/src/adjust.rs#L967), [`core/dr-gpu/src/demosaic.rs:121`](../core/dr-gpu/src/demosaic.rs#L121), [`core/dr-gpu/src/demosaic.rs:86`](../core/dr-gpu/src/demosaic.rs#L86), [`core/dr-gpu/tests/base_curve.rs:1`](../core/dr-gpu/tests/base_curve.rs#L1), [`core/dr-pipeline/src/operation.rs:1495`](../core/dr-pipeline/src/operation.rs#L1495), [`core/dr-pipeline/src/operation.rs:1576`](../core/dr-pipeline/src/operation.rs#L1576), [`core/dr-pipeline/src/operation.rs:1601`](../core/dr-pipeline/src/operation.rs#L1601), [`core/dr-pipeline/src/operation.rs:1616`](../core/dr-pipeline/src/operation.rs#L1616), [`core/dr-pipeline/src/operation.rs:1640`](../core/dr-pipeline/src/operation.rs#L1640), [`core/dr-pipeline/src/operation.rs:310`](../core/dr-pipeline/src/operation.rs#L310), [`core/dr-pipeline/src/operation.rs:440`](../core/dr-pipeline/src/operation.rs#L440), [`core/dr-pipeline/src/operation.rs:450`](../core/dr-pipeline/src/operation.rs#L450), [`core/dr-pipeline/src/operation.rs:600`](../core/dr-pipeline/src/operation.rs#L600) | -| FR-DEV-3f | [`core/dr-film/src/bake.rs:271`](../core/dr-film/src/bake.rs#L271), [`core/dr-film/src/bake.rs:62`](../core/dr-film/src/bake.rs#L62), [`core/dr-film/src/boolean_grain.rs:1`](../core/dr-film/src/boolean_grain.rs#L1), [`core/dr-film/src/boolean_grain.rs:78`](../core/dr-film/src/boolean_grain.rs#L78), [`core/dr-film/src/grain.rs:140`](../core/dr-film/src/grain.rs#L140), [`core/dr-film/src/grain.rs:1`](../core/dr-film/src/grain.rs#L1), [`core/dr-film/src/grain.rs:302`](../core/dr-film/src/grain.rs#L302), [`core/dr-film/src/grain.rs:79`](../core/dr-film/src/grain.rs#L79), [`core/dr-film/src/lib.rs:160`](../core/dr-film/src/lib.rs#L160), [`core/dr-film/src/lib.rs:1`](../core/dr-film/src/lib.rs#L1), [`core/dr-film/src/profile.rs:100`](../core/dr-film/src/profile.rs#L100), [`core/dr-film/src/profile.rs:142`](../core/dr-film/src/profile.rs#L142), [`core/dr-film/src/profile.rs:182`](../core/dr-film/src/profile.rs#L182), [`core/dr-film/src/profile.rs:259`](../core/dr-film/src/profile.rs#L259), [`core/dr-film/src/profile.rs:502`](../core/dr-film/src/profile.rs#L502), [`core/dr-film/src/profile.rs:73`](../core/dr-film/src/profile.rs#L73), [`core/dr-gpu/src/adjust.rs:139`](../core/dr-gpu/src/adjust.rs#L139), [`core/dr-gpu/src/adjust.rs:196`](../core/dr-gpu/src/adjust.rs#L196), [`core/dr-gpu/src/adjust.rs:357`](../core/dr-gpu/src/adjust.rs#L357), [`core/dr-gpu/src/adjust.rs:483`](../core/dr-gpu/src/adjust.rs#L483), [`core/dr-gpu/src/adjust.rs:77`](../core/dr-gpu/src/adjust.rs#L77), [`core/dr-gpu/tests/film_sim.rs:191`](../core/dr-gpu/tests/film_sim.rs#L191), [`core/dr-gpu/tests/film_sim.rs:1`](../core/dr-gpu/tests/film_sim.rs#L1), [`core/dr-pipeline/src/graph.rs:102`](../core/dr-pipeline/src/graph.rs#L102), [`core/dr-pipeline/src/graph.rs:125`](../core/dr-pipeline/src/graph.rs#L125), [`core/dr-pipeline/src/graph.rs:325`](../core/dr-pipeline/src/graph.rs#L325), [`core/dr-pipeline/src/operation.rs:1065`](../core/dr-pipeline/src/operation.rs#L1065), [`core/dr-pipeline/src/operation.rs:1094`](../core/dr-pipeline/src/operation.rs#L1094), [`core/dr-pipeline/src/operation.rs:1495`](../core/dr-pipeline/src/operation.rs#L1495), [`core/dr-pipeline/src/operation.rs:296`](../core/dr-pipeline/src/operation.rs#L296), [`core/dr-pipeline/src/operation.rs:310`](../core/dr-pipeline/src/operation.rs#L310), [`core/dr-pipeline/src/ops/film_sim.rs:129`](../core/dr-pipeline/src/ops/film_sim.rs#L129), [`core/dr-pipeline/src/ops/film_sim.rs:153`](../core/dr-pipeline/src/ops/film_sim.rs#L153), [`core/dr-pipeline/src/ops/film_sim.rs:1`](../core/dr-pipeline/src/ops/film_sim.rs#L1), [`core/dr-pipeline/src/ops/film_sim.rs:331`](../core/dr-pipeline/src/ops/film_sim.rs#L331), [`core/dr-pipeline/src/ops/film_sim.rs:43`](../core/dr-pipeline/src/ops/film_sim.rs#L43), [`core/dr-pipeline/src/ops/film_sim.rs:87`](../core/dr-pipeline/src/ops/film_sim.rs#L87), [`core/dr-pipeline/src/ops/film_sim.rs:92`](../core/dr-pipeline/src/ops/film_sim.rs#L92), [`core/dr-pipeline/src/sidecar.rs:113`](../core/dr-pipeline/src/sidecar.rs#L113), [`core/dr-pipeline/src/sidecar.rs:169`](../core/dr-pipeline/src/sidecar.rs#L169), [`core/dr-pipeline/src/sidecar.rs:2060`](../core/dr-pipeline/src/sidecar.rs#L2060), [`core/dr-pipeline/src/sidecar.rs:2136`](../core/dr-pipeline/src/sidecar.rs#L2136), [`core/dr-pipeline/src/sidecar.rs:535`](../core/dr-pipeline/src/sidecar.rs#L535), [`core/dr-pipeline/src/sidecar.rs:662`](../core/dr-pipeline/src/sidecar.rs#L662), [`core/dr-pipeline/src/sidecar.rs:794`](../core/dr-pipeline/src/sidecar.rs#L794), [`core/dr-pipeline/src/state.rs:100`](../core/dr-pipeline/src/state.rs#L100), [`core/dr-pipeline/src/state.rs:115`](../core/dr-pipeline/src/state.rs#L115), [`core/dr-pipeline/src/state.rs:60`](../core/dr-pipeline/src/state.rs#L60), [`ui/dr-ui/src/develop.rs:3602`](../ui/dr-ui/src/develop.rs#L3602), [`ui/dr-ui/src/develop.rs:3619`](../ui/dr-ui/src/develop.rs#L3619), [`ui/dr-ui/src/develop.rs:3631`](../ui/dr-ui/src/develop.rs#L3631), [`ui/dr-ui/src/develop.rs:3669`](../ui/dr-ui/src/develop.rs#L3669), [`ui/dr-ui/src/develop.rs:3678`](../ui/dr-ui/src/develop.rs#L3678), [`ui/dr-ui/src/develop.rs:3781`](../ui/dr-ui/src/develop.rs#L3781), [`ui/dr-ui/src/develop.rs:4194`](../ui/dr-ui/src/develop.rs#L4194), [`ui/dr-ui/src/develop.rs:4209`](../ui/dr-ui/src/develop.rs#L4209), [`ui/dr-ui/src/lib.rs:2472`](../ui/dr-ui/src/lib.rs#L2472), [`ui/dr-ui/src/lib.rs:682`](../ui/dr-ui/src/lib.rs#L682), [`ui/dr-ui/src/lib.rs:740`](../ui/dr-ui/src/lib.rs#L740), [`ui/dr-ui/src/library.rs:530`](../ui/dr-ui/src/library.rs#L530), [`ui/dr-ui/src/library.rs:778`](../ui/dr-ui/src/library.rs#L778), [`ui/dr-ui/src/presets.rs:402`](../ui/dr-ui/src/presets.rs#L402), [`ui/dr-ui/ui/adjust.slint:1072`](../ui/dr-ui/ui/adjust.slint#L1072), [`ui/dr-ui/ui/adjust.slint:996`](../ui/dr-ui/ui/adjust.slint#L996), [`ui/dr-ui/ui/app.slint:2647`](../ui/dr-ui/ui/app.slint#L2647), [`ui/dr-ui/ui/app.slint:712`](../ui/dr-ui/ui/app.slint#L712) | -| FR-DEV-3h | [`core/dr-decode/src/lib.rs:404`](../core/dr-decode/src/lib.rs#L404), [`core/dr-decode/src/preview.rs:29`](../core/dr-decode/src/preview.rs#L29), [`core/dr-pipeline/src/framing.rs:1060`](../core/dr-pipeline/src/framing.rs#L1060), [`core/dr-pipeline/src/framing.rs:328`](../core/dr-pipeline/src/framing.rs#L328), [`core/dr-pipeline/src/framing.rs:498`](../core/dr-pipeline/src/framing.rs#L498), [`core/dr-types/src/lib.rs:339`](../core/dr-types/src/lib.rs#L339), [`core/dr-types/src/lib.rs:447`](../core/dr-types/src/lib.rs#L447), [`core/dr-types/src/lib.rs:459`](../core/dr-types/src/lib.rs#L459), [`core/dr-types/src/lib.rs:475`](../core/dr-types/src/lib.rs#L475), [`ui/dr-ui/src/develop.rs:140`](../ui/dr-ui/src/develop.rs#L140), [`ui/dr-ui/src/develop.rs:2353`](../ui/dr-ui/src/develop.rs#L2353), [`ui/dr-ui/src/segmentation.rs:476`](../ui/dr-ui/src/segmentation.rs#L476) | +| FR-DEV-3e | [`core/dr-decode/src/base_curve.rs:145`](../core/dr-decode/src/base_curve.rs#L145), [`core/dr-decode/src/base_curve.rs:158`](../core/dr-decode/src/base_curve.rs#L158), [`core/dr-decode/src/base_curve.rs:1`](../core/dr-decode/src/base_curve.rs#L1), [`core/dr-decode/src/base_curve.rs:267`](../core/dr-decode/src/base_curve.rs#L267), [`core/dr-decode/src/base_curve.rs:347`](../core/dr-decode/src/base_curve.rs#L347), [`core/dr-decode/src/base_curve.rs:55`](../core/dr-decode/src/base_curve.rs#L55), [`core/dr-decode/src/lib.rs:121`](../core/dr-decode/src/lib.rs#L121), [`core/dr-decode/src/lib.rs:708`](../core/dr-decode/src/lib.rs#L708), [`core/dr-decode/src/lib.rs:748`](../core/dr-decode/src/lib.rs#L748), [`core/dr-decode/src/profile.rs:102`](../core/dr-decode/src/profile.rs#L102), [`core/dr-decode/src/profile.rs:151`](../core/dr-decode/src/profile.rs#L151), [`core/dr-decode/src/profile.rs:1`](../core/dr-decode/src/profile.rs#L1), [`core/dr-decode/src/profile.rs:235`](../core/dr-decode/src/profile.rs#L235), [`core/dr-decode/src/profile.rs:286`](../core/dr-decode/src/profile.rs#L286), [`core/dr-decode/src/profile.rs:343`](../core/dr-decode/src/profile.rs#L343), [`core/dr-decode/src/profile.rs:458`](../core/dr-decode/src/profile.rs#L458), [`core/dr-decode/src/profile.rs:492`](../core/dr-decode/src/profile.rs#L492), [`core/dr-decode/src/profile.rs:630`](../core/dr-decode/src/profile.rs#L630), [`core/dr-gpu/src/adjust.rs:37`](../core/dr-gpu/src/adjust.rs#L37), [`core/dr-gpu/src/adjust.rs:967`](../core/dr-gpu/src/adjust.rs#L967), [`core/dr-gpu/src/demosaic.rs:121`](../core/dr-gpu/src/demosaic.rs#L121), [`core/dr-gpu/src/demosaic.rs:86`](../core/dr-gpu/src/demosaic.rs#L86), [`core/dr-gpu/tests/base_curve.rs:1`](../core/dr-gpu/tests/base_curve.rs#L1), [`core/dr-pipeline/src/operation.rs:1529`](../core/dr-pipeline/src/operation.rs#L1529), [`core/dr-pipeline/src/operation.rs:1610`](../core/dr-pipeline/src/operation.rs#L1610), [`core/dr-pipeline/src/operation.rs:1635`](../core/dr-pipeline/src/operation.rs#L1635), [`core/dr-pipeline/src/operation.rs:1650`](../core/dr-pipeline/src/operation.rs#L1650), [`core/dr-pipeline/src/operation.rs:1674`](../core/dr-pipeline/src/operation.rs#L1674), [`core/dr-pipeline/src/operation.rs:310`](../core/dr-pipeline/src/operation.rs#L310), [`core/dr-pipeline/src/operation.rs:440`](../core/dr-pipeline/src/operation.rs#L440), [`core/dr-pipeline/src/operation.rs:450`](../core/dr-pipeline/src/operation.rs#L450), [`core/dr-pipeline/src/operation.rs:600`](../core/dr-pipeline/src/operation.rs#L600) | +| FR-DEV-3f | [`core/dr-film/src/bake.rs:271`](../core/dr-film/src/bake.rs#L271), [`core/dr-film/src/bake.rs:62`](../core/dr-film/src/bake.rs#L62), [`core/dr-film/src/boolean_grain.rs:1`](../core/dr-film/src/boolean_grain.rs#L1), [`core/dr-film/src/boolean_grain.rs:78`](../core/dr-film/src/boolean_grain.rs#L78), [`core/dr-film/src/grain.rs:140`](../core/dr-film/src/grain.rs#L140), [`core/dr-film/src/grain.rs:1`](../core/dr-film/src/grain.rs#L1), [`core/dr-film/src/grain.rs:302`](../core/dr-film/src/grain.rs#L302), [`core/dr-film/src/grain.rs:79`](../core/dr-film/src/grain.rs#L79), [`core/dr-film/src/lib.rs:160`](../core/dr-film/src/lib.rs#L160), [`core/dr-film/src/lib.rs:1`](../core/dr-film/src/lib.rs#L1), [`core/dr-film/src/profile.rs:100`](../core/dr-film/src/profile.rs#L100), [`core/dr-film/src/profile.rs:142`](../core/dr-film/src/profile.rs#L142), [`core/dr-film/src/profile.rs:182`](../core/dr-film/src/profile.rs#L182), [`core/dr-film/src/profile.rs:259`](../core/dr-film/src/profile.rs#L259), [`core/dr-film/src/profile.rs:502`](../core/dr-film/src/profile.rs#L502), [`core/dr-film/src/profile.rs:73`](../core/dr-film/src/profile.rs#L73), [`core/dr-gpu/src/adjust.rs:139`](../core/dr-gpu/src/adjust.rs#L139), [`core/dr-gpu/src/adjust.rs:196`](../core/dr-gpu/src/adjust.rs#L196), [`core/dr-gpu/src/adjust.rs:357`](../core/dr-gpu/src/adjust.rs#L357), [`core/dr-gpu/src/adjust.rs:483`](../core/dr-gpu/src/adjust.rs#L483), [`core/dr-gpu/src/adjust.rs:77`](../core/dr-gpu/src/adjust.rs#L77), [`core/dr-gpu/tests/film_sim.rs:191`](../core/dr-gpu/tests/film_sim.rs#L191), [`core/dr-gpu/tests/film_sim.rs:1`](../core/dr-gpu/tests/film_sim.rs#L1), [`core/dr-pipeline/src/graph.rs:102`](../core/dr-pipeline/src/graph.rs#L102), [`core/dr-pipeline/src/graph.rs:125`](../core/dr-pipeline/src/graph.rs#L125), [`core/dr-pipeline/src/graph.rs:325`](../core/dr-pipeline/src/graph.rs#L325), [`core/dr-pipeline/src/operation.rs:1065`](../core/dr-pipeline/src/operation.rs#L1065), [`core/dr-pipeline/src/operation.rs:1111`](../core/dr-pipeline/src/operation.rs#L1111), [`core/dr-pipeline/src/operation.rs:1529`](../core/dr-pipeline/src/operation.rs#L1529), [`core/dr-pipeline/src/operation.rs:296`](../core/dr-pipeline/src/operation.rs#L296), [`core/dr-pipeline/src/operation.rs:310`](../core/dr-pipeline/src/operation.rs#L310), [`core/dr-pipeline/src/ops/film_sim.rs:129`](../core/dr-pipeline/src/ops/film_sim.rs#L129), [`core/dr-pipeline/src/ops/film_sim.rs:153`](../core/dr-pipeline/src/ops/film_sim.rs#L153), [`core/dr-pipeline/src/ops/film_sim.rs:1`](../core/dr-pipeline/src/ops/film_sim.rs#L1), [`core/dr-pipeline/src/ops/film_sim.rs:331`](../core/dr-pipeline/src/ops/film_sim.rs#L331), [`core/dr-pipeline/src/ops/film_sim.rs:43`](../core/dr-pipeline/src/ops/film_sim.rs#L43), [`core/dr-pipeline/src/ops/film_sim.rs:87`](../core/dr-pipeline/src/ops/film_sim.rs#L87), [`core/dr-pipeline/src/ops/film_sim.rs:92`](../core/dr-pipeline/src/ops/film_sim.rs#L92), [`core/dr-pipeline/src/sidecar.rs:113`](../core/dr-pipeline/src/sidecar.rs#L113), [`core/dr-pipeline/src/sidecar.rs:169`](../core/dr-pipeline/src/sidecar.rs#L169), [`core/dr-pipeline/src/sidecar.rs:2060`](../core/dr-pipeline/src/sidecar.rs#L2060), [`core/dr-pipeline/src/sidecar.rs:2136`](../core/dr-pipeline/src/sidecar.rs#L2136), [`core/dr-pipeline/src/sidecar.rs:535`](../core/dr-pipeline/src/sidecar.rs#L535), [`core/dr-pipeline/src/sidecar.rs:662`](../core/dr-pipeline/src/sidecar.rs#L662), [`core/dr-pipeline/src/sidecar.rs:794`](../core/dr-pipeline/src/sidecar.rs#L794), [`core/dr-pipeline/src/state.rs:100`](../core/dr-pipeline/src/state.rs#L100), [`core/dr-pipeline/src/state.rs:115`](../core/dr-pipeline/src/state.rs#L115), [`core/dr-pipeline/src/state.rs:60`](../core/dr-pipeline/src/state.rs#L60), [`ui/dr-ui/src/develop.rs:3602`](../ui/dr-ui/src/develop.rs#L3602), [`ui/dr-ui/src/develop.rs:3619`](../ui/dr-ui/src/develop.rs#L3619), [`ui/dr-ui/src/develop.rs:3631`](../ui/dr-ui/src/develop.rs#L3631), [`ui/dr-ui/src/develop.rs:3669`](../ui/dr-ui/src/develop.rs#L3669), [`ui/dr-ui/src/develop.rs:3678`](../ui/dr-ui/src/develop.rs#L3678), [`ui/dr-ui/src/develop.rs:3781`](../ui/dr-ui/src/develop.rs#L3781), [`ui/dr-ui/src/develop.rs:4194`](../ui/dr-ui/src/develop.rs#L4194), [`ui/dr-ui/src/develop.rs:4209`](../ui/dr-ui/src/develop.rs#L4209), [`ui/dr-ui/src/lib.rs:2472`](../ui/dr-ui/src/lib.rs#L2472), [`ui/dr-ui/src/lib.rs:682`](../ui/dr-ui/src/lib.rs#L682), [`ui/dr-ui/src/lib.rs:740`](../ui/dr-ui/src/lib.rs#L740), [`ui/dr-ui/src/library.rs:530`](../ui/dr-ui/src/library.rs#L530), [`ui/dr-ui/src/library.rs:778`](../ui/dr-ui/src/library.rs#L778), [`ui/dr-ui/src/presets.rs:402`](../ui/dr-ui/src/presets.rs#L402), [`ui/dr-ui/ui/adjust.slint:1072`](../ui/dr-ui/ui/adjust.slint#L1072), [`ui/dr-ui/ui/adjust.slint:996`](../ui/dr-ui/ui/adjust.slint#L996), [`ui/dr-ui/ui/app.slint:2647`](../ui/dr-ui/ui/app.slint#L2647), [`ui/dr-ui/ui/app.slint:712`](../ui/dr-ui/ui/app.slint#L712) | +| FR-DEV-3h | [`core/dr-decode/src/lib.rs:404`](../core/dr-decode/src/lib.rs#L404), [`core/dr-decode/src/preview.rs:29`](../core/dr-decode/src/preview.rs#L29), [`core/dr-pipeline/src/framing.rs:1067`](../core/dr-pipeline/src/framing.rs#L1067), [`core/dr-pipeline/src/framing.rs:328`](../core/dr-pipeline/src/framing.rs#L328), [`core/dr-pipeline/src/framing.rs:498`](../core/dr-pipeline/src/framing.rs#L498), [`core/dr-types/src/lib.rs:339`](../core/dr-types/src/lib.rs#L339), [`core/dr-types/src/lib.rs:447`](../core/dr-types/src/lib.rs#L447), [`core/dr-types/src/lib.rs:459`](../core/dr-types/src/lib.rs#L459), [`core/dr-types/src/lib.rs:475`](../core/dr-types/src/lib.rs#L475), [`ui/dr-ui/src/develop.rs:140`](../ui/dr-ui/src/develop.rs#L140), [`ui/dr-ui/src/develop.rs:2353`](../ui/dr-ui/src/develop.rs#L2353), [`ui/dr-ui/src/segmentation.rs:476`](../ui/dr-ui/src/segmentation.rs#L476) | | FR-DEV-4 | [`core/dr-gpu/src/adjust.rs:770`](../core/dr-gpu/src/adjust.rs#L770), [`core/dr-gpu/src/lib.rs:351`](../core/dr-gpu/src/lib.rs#L351), [`ui/dr-ui/ui/crop.slint:1`](../ui/dr-ui/ui/crop.slint#L1) | -| FR-DEV-5 | [`core/dr-pipeline/src/graph.rs:346`](../core/dr-pipeline/src/graph.rs#L346), [`core/dr-pipeline/src/graph.rs:385`](../core/dr-pipeline/src/graph.rs#L385), [`core/dr-pipeline/src/history.rs:102`](../core/dr-pipeline/src/history.rs#L102), [`core/dr-pipeline/src/history.rs:110`](../core/dr-pipeline/src/history.rs#L110), [`core/dr-pipeline/src/history.rs:127`](../core/dr-pipeline/src/history.rs#L127), [`core/dr-pipeline/src/history.rs:184`](../core/dr-pipeline/src/history.rs#L184), [`core/dr-pipeline/src/history.rs:1`](../core/dr-pipeline/src/history.rs#L1), [`core/dr-pipeline/src/history.rs:214`](../core/dr-pipeline/src/history.rs#L214), [`core/dr-pipeline/src/history.rs:234`](../core/dr-pipeline/src/history.rs#L234), [`core/dr-pipeline/src/history.rs:293`](../core/dr-pipeline/src/history.rs#L293), [`core/dr-pipeline/src/history.rs:479`](../core/dr-pipeline/src/history.rs#L479), [`core/dr-pipeline/src/history.rs:489`](../core/dr-pipeline/src/history.rs#L489), [`core/dr-pipeline/src/history.rs:499`](../core/dr-pipeline/src/history.rs#L499), [`core/dr-pipeline/src/history.rs:526`](../core/dr-pipeline/src/history.rs#L526), [`core/dr-pipeline/src/history.rs:86`](../core/dr-pipeline/src/history.rs#L86), [`core/dr-pipeline/src/state.rs:1`](../core/dr-pipeline/src/state.rs#L1), [`core/dr-pipeline/src/state.rs:75`](../core/dr-pipeline/src/state.rs#L75), [`ui/dr-ui/src/develop.rs:3631`](../ui/dr-ui/src/develop.rs#L3631), [`ui/dr-ui/src/develop.rs:4209`](../ui/dr-ui/src/develop.rs#L4209), [`ui/dr-ui/src/develop.rs:4239`](../ui/dr-ui/src/develop.rs#L4239), [`ui/dr-ui/src/develop.rs:4252`](../ui/dr-ui/src/develop.rs#L4252), [`ui/dr-ui/src/develop.rs:4264`](../ui/dr-ui/src/develop.rs#L4264), [`ui/dr-ui/src/develop.rs:4280`](../ui/dr-ui/src/develop.rs#L4280), [`ui/dr-ui/src/develop.rs:4312`](../ui/dr-ui/src/develop.rs#L4312), [`ui/dr-ui/src/develop.rs:4316`](../ui/dr-ui/src/develop.rs#L4316), [`ui/dr-ui/src/develop.rs:4335`](../ui/dr-ui/src/develop.rs#L4335), [`ui/dr-ui/src/develop.rs:4351`](../ui/dr-ui/src/develop.rs#L4351), [`ui/dr-ui/src/develop.rs:738`](../ui/dr-ui/src/develop.rs#L738), [`ui/dr-ui/src/labels.rs:12`](../ui/dr-ui/src/labels.rs#L12), [`ui/dr-ui/src/labels.rs:217`](../ui/dr-ui/src/labels.rs#L217), [`ui/dr-ui/src/lib.rs:1631`](../ui/dr-ui/src/lib.rs#L1631), [`ui/dr-ui/src/lib.rs:1674`](../ui/dr-ui/src/lib.rs#L1674), [`ui/dr-ui/src/lib.rs:1682`](../ui/dr-ui/src/lib.rs#L1682), [`ui/dr-ui/src/lib.rs:2668`](../ui/dr-ui/src/lib.rs#L2668), [`ui/dr-ui/ui/history.slint:1`](../ui/dr-ui/ui/history.slint#L1) | +| FR-DEV-5 | [`core/dr-pipeline/src/graph.rs:346`](../core/dr-pipeline/src/graph.rs#L346), [`core/dr-pipeline/src/graph.rs:385`](../core/dr-pipeline/src/graph.rs#L385), [`core/dr-pipeline/src/history.rs:102`](../core/dr-pipeline/src/history.rs#L102), [`core/dr-pipeline/src/history.rs:110`](../core/dr-pipeline/src/history.rs#L110), [`core/dr-pipeline/src/history.rs:127`](../core/dr-pipeline/src/history.rs#L127), [`core/dr-pipeline/src/history.rs:184`](../core/dr-pipeline/src/history.rs#L184), [`core/dr-pipeline/src/history.rs:1`](../core/dr-pipeline/src/history.rs#L1), [`core/dr-pipeline/src/history.rs:214`](../core/dr-pipeline/src/history.rs#L214), [`core/dr-pipeline/src/history.rs:234`](../core/dr-pipeline/src/history.rs#L234), [`core/dr-pipeline/src/history.rs:293`](../core/dr-pipeline/src/history.rs#L293), [`core/dr-pipeline/src/history.rs:479`](../core/dr-pipeline/src/history.rs#L479), [`core/dr-pipeline/src/history.rs:489`](../core/dr-pipeline/src/history.rs#L489), [`core/dr-pipeline/src/history.rs:499`](../core/dr-pipeline/src/history.rs#L499), [`core/dr-pipeline/src/history.rs:526`](../core/dr-pipeline/src/history.rs#L526), [`core/dr-pipeline/src/history.rs:86`](../core/dr-pipeline/src/history.rs#L86), [`core/dr-pipeline/src/state.rs:1`](../core/dr-pipeline/src/state.rs#L1), [`core/dr-pipeline/src/state.rs:75`](../core/dr-pipeline/src/state.rs#L75), [`ui/dr-ui/src/develop.rs:3631`](../ui/dr-ui/src/develop.rs#L3631), [`ui/dr-ui/src/develop.rs:4209`](../ui/dr-ui/src/develop.rs#L4209), [`ui/dr-ui/src/develop.rs:4239`](../ui/dr-ui/src/develop.rs#L4239), [`ui/dr-ui/src/develop.rs:4252`](../ui/dr-ui/src/develop.rs#L4252), [`ui/dr-ui/src/develop.rs:4264`](../ui/dr-ui/src/develop.rs#L4264), [`ui/dr-ui/src/develop.rs:4280`](../ui/dr-ui/src/develop.rs#L4280), [`ui/dr-ui/src/develop.rs:4312`](../ui/dr-ui/src/develop.rs#L4312), [`ui/dr-ui/src/develop.rs:4316`](../ui/dr-ui/src/develop.rs#L4316), [`ui/dr-ui/src/develop.rs:4335`](../ui/dr-ui/src/develop.rs#L4335), [`ui/dr-ui/src/develop.rs:4351`](../ui/dr-ui/src/develop.rs#L4351), [`ui/dr-ui/src/develop.rs:738`](../ui/dr-ui/src/develop.rs#L738), [`ui/dr-ui/src/labels.rs:12`](../ui/dr-ui/src/labels.rs#L12), [`ui/dr-ui/src/labels.rs:225`](../ui/dr-ui/src/labels.rs#L225), [`ui/dr-ui/src/lib.rs:1631`](../ui/dr-ui/src/lib.rs#L1631), [`ui/dr-ui/src/lib.rs:1674`](../ui/dr-ui/src/lib.rs#L1674), [`ui/dr-ui/src/lib.rs:1682`](../ui/dr-ui/src/lib.rs#L1682), [`ui/dr-ui/src/lib.rs:2668`](../ui/dr-ui/src/lib.rs#L2668), [`ui/dr-ui/ui/history.slint:1`](../ui/dr-ui/ui/history.slint#L1) | | FR-DEV-6 | [`core/dr-pipeline/src/preset.rs:1`](../core/dr-pipeline/src/preset.rs#L1), [`core/dr-pipeline/src/preset.rs:381`](../core/dr-pipeline/src/preset.rs#L381), [`core/dr-pipeline/src/preset.rs:414`](../core/dr-pipeline/src/preset.rs#L414), [`core/dr-pipeline/src/starter.rs:1`](../core/dr-pipeline/src/starter.rs#L1), [`core/dr-preset-xmp/src/lib.rs:1`](../core/dr-preset-xmp/src/lib.rs#L1), [`core/dr-types/src/settings.rs:272`](../core/dr-types/src/settings.rs#L272), [`ui/dr-ui/src/develop.rs:4151`](../ui/dr-ui/src/develop.rs#L4151), [`ui/dr-ui/src/develop.rs:4172`](../ui/dr-ui/src/develop.rs#L4172), [`ui/dr-ui/src/lib.rs:1598`](../ui/dr-ui/src/lib.rs#L1598), [`ui/dr-ui/src/lib.rs:2283`](../ui/dr-ui/src/lib.rs#L2283), [`ui/dr-ui/src/lib.rs:2312`](../ui/dr-ui/src/lib.rs#L2312), [`ui/dr-ui/src/library.rs:1923`](../ui/dr-ui/src/library.rs#L1923), [`ui/dr-ui/src/library.rs:492`](../ui/dr-ui/src/library.rs#L492), [`ui/dr-ui/src/library.rs:520`](../ui/dr-ui/src/library.rs#L520), [`ui/dr-ui/src/library_ui.rs:3185`](../ui/dr-ui/src/library_ui.rs#L3185), [`ui/dr-ui/src/library_ui.rs:3585`](../ui/dr-ui/src/library_ui.rs#L3585), [`ui/dr-ui/src/library_ui.rs:554`](../ui/dr-ui/src/library_ui.rs#L554), [`ui/dr-ui/src/preset_store.rs:1`](../ui/dr-ui/src/preset_store.rs#L1), [`ui/dr-ui/src/presets.rs:1`](../ui/dr-ui/src/presets.rs#L1), [`ui/dr-ui/src/presets.rs:664`](../ui/dr-ui/src/presets.rs#L664), [`ui/dr-ui/src/presets.rs:698`](../ui/dr-ui/src/presets.rs#L698), [`ui/dr-ui/ui/adjust.slint:740`](../ui/dr-ui/ui/adjust.slint#L740), [`ui/dr-ui/ui/adjust.slint:767`](../ui/dr-ui/ui/adjust.slint#L767), [`ui/dr-ui/ui/adjust.slint:801`](../ui/dr-ui/ui/adjust.slint#L801), [`ui/dr-ui/ui/app.slint:1599`](../ui/dr-ui/ui/app.slint#L1599), [`ui/dr-ui/ui/app.slint:2736`](../ui/dr-ui/ui/app.slint#L2736), [`ui/dr-ui/ui/app.slint:784`](../ui/dr-ui/ui/app.slint#L784), [`ui/dr-ui/ui/app.slint:795`](../ui/dr-ui/ui/app.slint#L795), [`ui/dr-ui/ui/library.slint:1564`](../ui/dr-ui/ui/library.slint#L1564), [`ui/dr-ui/ui/library.slint:1570`](../ui/dr-ui/ui/library.slint#L1570), [`ui/dr-ui/ui/library.slint:4117`](../ui/dr-ui/ui/library.slint#L4117), [`ui/dr-ui/ui/library.slint:4132`](../ui/dr-ui/ui/library.slint#L4132), [`ui/dr-ui/ui/presets.slint:105`](../ui/dr-ui/ui/presets.slint#L105), [`ui/dr-ui/ui/presets.slint:113`](../ui/dr-ui/ui/presets.slint#L113), [`ui/dr-ui/ui/presets.slint:19`](../ui/dr-ui/ui/presets.slint#L19), [`ui/dr-ui/ui/presets.slint:276`](../ui/dr-ui/ui/presets.slint#L276), [`ui/dr-ui/ui/presets.slint:297`](../ui/dr-ui/ui/presets.slint#L297), [`ui/dr-ui/ui/presets.slint:5`](../ui/dr-ui/ui/presets.slint#L5), [`ui/dr-ui/ui/presets.slint:60`](../ui/dr-ui/ui/presets.slint#L60), [`ui/dr-ui/ui/settings.slint:101`](../ui/dr-ui/ui/settings.slint#L101), [`ui/dr-ui/ui/settings.slint:557`](../ui/dr-ui/ui/settings.slint#L557) | | FR-DEV-7 | [`core/dr-pipeline/src/history.rs:214`](../core/dr-pipeline/src/history.rs#L214), [`core/dr-pipeline/src/history.rs:499`](../core/dr-pipeline/src/history.rs#L499), [`core/dr-pipeline/src/history.rs:526`](../core/dr-pipeline/src/history.rs#L526), [`ui/dr-ui/src/develop.rs:4280`](../ui/dr-ui/src/develop.rs#L4280), [`ui/dr-ui/src/develop.rs:4312`](../ui/dr-ui/src/develop.rs#L4312), [`ui/dr-ui/src/lib.rs:1682`](../ui/dr-ui/src/lib.rs#L1682), [`ui/dr-ui/src/lib.rs:2668`](../ui/dr-ui/src/lib.rs#L2668), [`ui/dr-ui/ui/history.slint:1`](../ui/dr-ui/ui/history.slint#L1) | | FR-DEV-8 | [`core/dr-gpu/src/detail.rs:405`](../core/dr-gpu/src/detail.rs#L405), [`core/dr-gpu/src/detail.rs:623`](../core/dr-gpu/src/detail.rs#L623), [`core/dr-gpu/tests/detail_instances.rs:1`](../core/dr-gpu/tests/detail_instances.rs#L1), [`core/dr-gpu/tests/spot_removal.rs:1`](../core/dr-gpu/tests/spot_removal.rs#L1), [`core/dr-pipeline/src/detail.rs:410`](../core/dr-pipeline/src/detail.rs#L410), [`core/dr-pipeline/src/detail.rs:434`](../core/dr-pipeline/src/detail.rs#L434), [`core/dr-pipeline/src/detail.rs:469`](../core/dr-pipeline/src/detail.rs#L469), [`core/dr-pipeline/src/detail.rs:555`](../core/dr-pipeline/src/detail.rs#L555), [`core/dr-pipeline/src/graph.rs:114`](../core/dr-pipeline/src/graph.rs#L114), [`core/dr-pipeline/src/graph.rs:192`](../core/dr-pipeline/src/graph.rs#L192), [`core/dr-pipeline/src/graph.rs:686`](../core/dr-pipeline/src/graph.rs#L686), [`core/dr-pipeline/src/operation.rs:330`](../core/dr-pipeline/src/operation.rs#L330), [`core/dr-pipeline/src/operation.rs:554`](../core/dr-pipeline/src/operation.rs#L554), [`core/dr-pipeline/src/sidecar.rs:185`](../core/dr-pipeline/src/sidecar.rs#L185), [`core/dr-pipeline/src/sidecar.rs:354`](../core/dr-pipeline/src/sidecar.rs#L354), [`core/dr-pipeline/src/sidecar.rs:674`](../core/dr-pipeline/src/sidecar.rs#L674), [`core/dr-pipeline/src/sidecar.rs:810`](../core/dr-pipeline/src/sidecar.rs#L810), [`core/dr-pipeline/src/sidecar.rs:864`](../core/dr-pipeline/src/sidecar.rs#L864), [`core/dr-pipeline/src/sidecar.rs:894`](../core/dr-pipeline/src/sidecar.rs#L894), [`core/dr-pipeline/src/spot.rs:115`](../core/dr-pipeline/src/spot.rs#L115), [`core/dr-pipeline/src/spot.rs:151`](../core/dr-pipeline/src/spot.rs#L151), [`core/dr-pipeline/src/spot.rs:1`](../core/dr-pipeline/src/spot.rs#L1), [`core/dr-pipeline/src/spot.rs:207`](../core/dr-pipeline/src/spot.rs#L207), [`core/dr-pipeline/src/spot.rs:387`](../core/dr-pipeline/src/spot.rs#L387), [`core/dr-pipeline/src/spot.rs:472`](../core/dr-pipeline/src/spot.rs#L472), [`core/dr-pipeline/src/spot.rs:582`](../core/dr-pipeline/src/spot.rs#L582), [`core/dr-pipeline/src/spot.rs:673`](../core/dr-pipeline/src/spot.rs#L673), [`core/dr-pipeline/src/state.rs:103`](../core/dr-pipeline/src/state.rs#L103), [`core/dr-pipeline/tests/spot_sidecar.rs:1`](../core/dr-pipeline/tests/spot_sidecar.rs#L1), [`core/dr-pipeline/tests/spots.rs:1`](../core/dr-pipeline/tests/spots.rs#L1), [`ui/dr-ui/src/develop.rs:2505`](../ui/dr-ui/src/develop.rs#L2505), [`ui/dr-ui/src/develop.rs:2543`](../ui/dr-ui/src/develop.rs#L2543), [`ui/dr-ui/src/develop.rs:2608`](../ui/dr-ui/src/develop.rs#L2608), [`ui/dr-ui/src/develop.rs:2691`](../ui/dr-ui/src/develop.rs#L2691), [`ui/dr-ui/src/develop.rs:2705`](../ui/dr-ui/src/develop.rs#L2705), [`ui/dr-ui/src/develop.rs:825`](../ui/dr-ui/src/develop.rs#L825), [`ui/dr-ui/src/labels.rs:53`](../ui/dr-ui/src/labels.rs#L53), [`ui/dr-ui/src/lib.rs:1703`](../ui/dr-ui/src/lib.rs#L1703), [`ui/dr-ui/src/lib.rs:2786`](../ui/dr-ui/src/lib.rs#L2786), [`ui/dr-ui/src/lib.rs:394`](../ui/dr-ui/src/lib.rs#L394), [`ui/dr-ui/src/spots_ui.rs:19`](../ui/dr-ui/src/spots_ui.rs#L19), [`ui/dr-ui/src/spots_ui.rs:1`](../ui/dr-ui/src/spots_ui.rs#L1), [`ui/dr-ui/src/spots_ui.rs:265`](../ui/dr-ui/src/spots_ui.rs#L265), [`ui/dr-ui/ui/adjust.slint:832`](../ui/dr-ui/ui/adjust.slint#L832), [`ui/dr-ui/ui/app.slint:140`](../ui/dr-ui/ui/app.slint#L140), [`ui/dr-ui/ui/app.slint:1949`](../ui/dr-ui/ui/app.slint#L1949), [`ui/dr-ui/ui/app.slint:2124`](../ui/dr-ui/ui/app.slint#L2124), [`ui/dr-ui/ui/app.slint:2548`](../ui/dr-ui/ui/app.slint#L2548), [`ui/dr-ui/ui/icons.slint:338`](../ui/dr-ui/ui/icons.slint#L338), [`ui/dr-ui/ui/spots.slint:172`](../ui/dr-ui/ui/spots.slint#L172), [`ui/dr-ui/ui/spots.slint:48`](../ui/dr-ui/ui/spots.slint#L48), [`ui/dr-ui/ui/spots.slint:5`](../ui/dr-ui/ui/spots.slint#L5) | @@ -112,7 +112,7 @@ _None._ | FR-PLAT-AND-6 | [`apps/darkroom-android/src/lib.rs:388`](../apps/darkroom-android/src/lib.rs#L388) | | FR-PLAT-LIN-1 | [`core/dr-types/src/settings.rs:1`](../core/dr-types/src/settings.rs#L1), [`platform/dr-plat/src/storage.rs:344`](../platform/dr-plat/src/storage.rs#L344), [`ui/dr-ui/src/lib.rs:999`](../ui/dr-ui/src/lib.rs#L999), [`ui/dr-ui/src/preset_store.rs:1`](../ui/dr-ui/src/preset_store.rs#L1), [`ui/dr-ui/src/settings_store.rs:1`](../ui/dr-ui/src/settings_store.rs#L1) | | FR-PLAT-LIN-2 | [`platform/dr-plat/src/display.rs:1`](../platform/dr-plat/src/display.rs#L1), [`platform/dr-plat/src/display/wayland.rs:1`](../platform/dr-plat/src/display/wayland.rs#L1), [`platform/dr-plat/src/display/x11.rs:1`](../platform/dr-plat/src/display/x11.rs#L1) | -| FR-PLG-2 | [`core/dr-pipeline/src/declared/decl.rs:1`](../core/dr-pipeline/src/declared/decl.rs#L1), [`core/dr-pipeline/src/declared/expr.rs:152`](../core/dr-pipeline/src/declared/expr.rs#L152), [`core/dr-pipeline/src/declared/expr.rs:1`](../core/dr-pipeline/src/declared/expr.rs#L1), [`core/dr-pipeline/src/declared/mod.rs:1`](../core/dr-pipeline/src/declared/mod.rs#L1), [`core/dr-pipeline/src/declared/mod.rs:82`](../core/dr-pipeline/src/declared/mod.rs#L82), [`core/dr-pipeline/src/descriptor.rs:15`](../core/dr-pipeline/src/descriptor.rs#L15), [`core/dr-pipeline/src/descriptor.rs:667`](../core/dr-pipeline/src/descriptor.rs#L667), [`core/dr-pipeline/src/operation.rs:232`](../core/dr-pipeline/src/operation.rs#L232), [`core/dr-pipeline/tests/declared_parity.rs:1`](../core/dr-pipeline/tests/declared_parity.rs#L1), [`core/dr-pipeline/tests/declared_parity.rs:240`](../core/dr-pipeline/tests/declared_parity.rs#L240), [`core/dr-pipeline/tests/declared_parity.rs:305`](../core/dr-pipeline/tests/declared_parity.rs#L305), [`core/dr-pipeline/tests/declared_parity.rs:358`](../core/dr-pipeline/tests/declared_parity.rs#L358), [`core/dr-pipeline/tests/declared_parity.rs:416`](../core/dr-pipeline/tests/declared_parity.rs#L416) | +| FR-PLG-2 | [`core/dr-pipeline/src/declared/decl.rs:1`](../core/dr-pipeline/src/declared/decl.rs#L1), [`core/dr-pipeline/src/declared/expr.rs:152`](../core/dr-pipeline/src/declared/expr.rs#L152), [`core/dr-pipeline/src/declared/expr.rs:1`](../core/dr-pipeline/src/declared/expr.rs#L1), [`core/dr-pipeline/src/declared/mod.rs:1`](../core/dr-pipeline/src/declared/mod.rs#L1), [`core/dr-pipeline/src/declared/mod.rs:82`](../core/dr-pipeline/src/declared/mod.rs#L82), [`core/dr-pipeline/src/descriptor.rs:15`](../core/dr-pipeline/src/descriptor.rs#L15), [`core/dr-pipeline/src/descriptor.rs:667`](../core/dr-pipeline/src/descriptor.rs#L667), [`core/dr-pipeline/src/operation.rs:232`](../core/dr-pipeline/src/operation.rs#L232), [`core/dr-pipeline/tests/declared_parity.rs:1`](../core/dr-pipeline/tests/declared_parity.rs#L1), [`core/dr-pipeline/tests/declared_parity.rs:240`](../core/dr-pipeline/tests/declared_parity.rs#L240), [`core/dr-pipeline/tests/declared_parity.rs:305`](../core/dr-pipeline/tests/declared_parity.rs#L305), [`core/dr-pipeline/tests/declared_parity.rs:358`](../core/dr-pipeline/tests/declared_parity.rs#L358), [`core/dr-pipeline/tests/declared_parity.rs:417`](../core/dr-pipeline/tests/declared_parity.rs#L417) | | FR-PLG-2d | [`core/dr-pipeline/src/declared/decl.rs:112`](../core/dr-pipeline/src/declared/decl.rs#L112), [`core/dr-pipeline/src/declared/decl.rs:152`](../core/dr-pipeline/src/declared/decl.rs#L152), [`core/dr-pipeline/src/declared/decl.rs:1`](../core/dr-pipeline/src/declared/decl.rs#L1), [`core/dr-pipeline/src/declared/decl.rs:420`](../core/dr-pipeline/src/declared/decl.rs#L420), [`core/dr-pipeline/src/declared/decl.rs:67`](../core/dr-pipeline/src/declared/decl.rs#L67), [`core/dr-pipeline/src/declared/mod.rs:1`](../core/dr-pipeline/src/declared/mod.rs#L1), [`core/dr-pipeline/src/declared/mod.rs:384`](../core/dr-pipeline/src/declared/mod.rs#L384), [`core/dr-pipeline/src/declared/mod.rs:403`](../core/dr-pipeline/src/declared/mod.rs#L403) | | FR-PLG-8 | [`core/dr-pipeline/src/sidecar.rs:1807`](../core/dr-pipeline/src/sidecar.rs#L1807), [`core/dr-pipeline/src/sidecar.rs:1840`](../core/dr-pipeline/src/sidecar.rs#L1840) | | FR-RAW-1 | [`core/dr-decode/src/lib.rs:243`](../core/dr-decode/src/lib.rs#L243), [`core/dr-types/src/lib.rs:132`](../core/dr-types/src/lib.rs#L132), [`core/dr-types/src/lib.rs:203`](../core/dr-types/src/lib.rs#L203) | diff --git a/ui/dr-ui/src/labels.rs b/ui/dr-ui/src/labels.rs index 28954b2..1610c89 100644 --- a/ui/dr-ui/src/labels.rs +++ b/ui/dr-ui/src/labels.rs @@ -146,6 +146,14 @@ fn catalogued(key: &str) -> Option<&'static str> { // see from there. "op.capture_sharpen" => "Sharpening", "op.framing" => "Crop & Rotate", + // "Lens Vignetting", not the "Vignetting" `derive` would produce, and + // the qualifier is doing real work. This operation corrects the corner + // falloff a lens imposed; the creative vignette that darkens corners on + // purpose is a different operation, belongs to `Effect` rather than + // `Optics`, and will want the plain word when it exists. Naming this + // one for what it corrects means the two can sit in the same panel + // without either having to be renamed to make room. + "op.vignetting" => "Lens Vignetting", // Parameters "param.temperature" => "Temperature",