LR-IMP-PROFILES: red / green / blue curves only with the master curve; neutral test values

Lightroom Classic reads `ToneCurvePV2012Red/Green/Blue` only together with
`ToneCurvePV2012`: a packet with a channel curve and no master curve leaves the
photo unchanged there (rendered on a chart: the channel curve alone has no
effect, with an identity master curve it applies). Imports now do the same.

The preset-packet test helper uses made-up as-shot values.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Exalted5373andClaude Opus 5.5 committed 2026-10-08 16:25:25 -07:00
1 parent 09d5284e5a
commit 31aa638383
3 files changed
+29 -7

No files matched your search

+27 -6
View File
@@ -244,11 +244,14 @@ pub fn to_partial(props: &Props, raw: Option<bool>) -> Value {
put(o, "curve.master", c);
}
}
for (crs, ch) in
[("ToneCurvePV2012", "master"), ("ToneCurvePV2012Red", "red"), ("ToneCurvePV2012Green", "green"), ("ToneCurvePV2012Blue", "blue")]
{
if let Some(c) = curve(props, &format!("crs:{crs}")) {
put(o, &format!("curve.{ch}"), c);
// Lightroom Classic reads the red / green / blue curves only together with the master 2012
// curve: a channel curve without `ToneCurvePV2012` leaves the photo unchanged
if let Some(c) = curve(props, "crs:ToneCurvePV2012") {
put(o, "curve.master", c);
for (crs, ch) in [("ToneCurvePV2012Red", "red"), ("ToneCurvePV2012Green", "green"), ("ToneCurvePV2012Blue", "blue")] {
if let Some(c) = curve(props, &format!("crs:{crs}")) {
put(o, &format!("curve.{ch}"), c);
}
}
}
@@ -572,7 +575,7 @@ mod tests {
<rdf:Description rdf:about="" xmlns:crs="http://ns.adobe.com/camera-raw-settings/1.0/"
crs:PresetType="Normal" crs:Cluster="" crs:UUID="0123ABCD" crs:SupportsAmount2="True" crs:SupportsAmount="True"
crs:RequiresRGBTables="False" crs:Contrast2012="+25" crs:LensProfileEnable="0" crs:OverrideLookVignette="False"
crs:CropConstrainToWarp="0" crs:AsShotTemperature="7450" crs:AsShotTint="23" {extra_attrs}>
crs:CropConstrainToWarp="0" crs:AsShotTemperature="5500" crs:AsShotTint="10" {extra_attrs}>
<crs:SortName><rdf:Alt><rdf:li xml:lang="x-default"/></rdf:Alt></crs:SortName>
<crs:Description><rdf:Alt><rdf:li xml:lang="x-default"/></rdf:Alt></crs:Description>
{extra_elems}
@@ -580,6 +583,24 @@ mod tests {
)
}
#[test]
fn channel_curves_need_the_master_curve() {
// Lightroom ignores a red / green / blue curve without `ToneCurvePV2012`
let packet = |master: &str| {
format!(
r#"<x:xmpmeta xmlns:x="adobe:ns:meta/"><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about="" xmlns:crs="http://ns.adobe.com/camera-raw-settings/1.0/" crs:ToneCurveName2012="Custom">{master}
<crs:ToneCurvePV2012Green><rdf:Seq><rdf:li>0, 0</rdf:li><rdf:li>64, 40</rdf:li><rdf:li>255, 255</rdf:li></rdf:Seq></crs:ToneCurvePV2012Green>
</rdf:Description></rdf:RDF></x:xmpmeta>"#
)
};
let alone = to_partial(&props(&packet("")), Some(true));
assert!(alone.pointer("/curve/green").is_none(), "{alone}");
let master = "<crs:ToneCurvePV2012><rdf:Seq><rdf:li>0, 0</rdf:li><rdf:li>255, 255</rdf:li></rdf:Seq></crs:ToneCurvePV2012>";
let with = to_partial(&props(&packet(master)), Some(true));
assert!(with.pointer("/curve/green").is_some() && with.pointer("/curve/master").is_some(), "{with}");
}
fn unmapped(x: &str) -> Vec<String> {
to_partial_report(&props(x), None, None, 1.5).1
}
+1
View File
@@ -49,6 +49,7 @@
white, empty Point Color slots…) as settings that couldn't be carried over.
- A preset whose lens-profile switch is off no longer turns off the lens corrections built into a DNG (iPhone ProRAW
and other files with embedded distortion / vignetting corrections), matching what the preset does elsewhere.
- A red / green / blue curve in an XMP preset without the master curve is ignored, as Lightroom ignores it.
- Imported `.cube` LUT profiles appear in the Profile menu and the profile browser, grouped by their folder, and stay
favourites across restarts (issue #328).
+1 -1
View File
@@ -117,7 +117,7 @@ names are read (e.g. `Exposure2012`, not the older `Exposure`).
| `ParametricShadows`, `ParametricDarks`, `ParametricLights`, `ParametricHighlights` | `curve.shadows/darks/lights/highlights` | |
| `ParametricShadowSplit`, `ParametricMidtoneSplit`, `ParametricHighlightSplit` | `curve.split_shadows/split_mid/split_highlights` | |
| `CurveRefineSaturation` | `curve.refine_saturation` | 0..100 (100 = curve saturation unchanged) |
| `ToneCurvePV2012`, `ToneCurvePV2012Red/Green/Blue` | `curve.master/red/green/blue` | `"x, y"` points in 0..255 → 0..1; a straight 0→255 line = no curve |
| `ToneCurvePV2012`, `ToneCurvePV2012Red/Green/Blue` | `curve.master/red/green/blue` | `"x, y"` points in 0..255 → 0..1; a straight 0→255 line = no curve; the red / green / blue curves are read only with `ToneCurvePV2012` (Lightroom Classic ignores them without it) |
| `SplitToningShadowHue/Saturation`, `SplitToningHighlightHue/Saturation` | `grading.shadows/highlights.hue/sat` | |
| `ColorGradeShadowLum`, `ColorGradeHighlightLum` | `grading.shadows/highlights.lum` | |
| `ColorGradeMidtoneHue/Sat/Lum`, `ColorGradeGlobalHue/Sat/Lum` | `grading.midtones/global.*` | |