LR-IMP-PROFILES: red / green / blue curves only with the master and all three channel curves
Lightroom Classic 15.6 imports an XMP packet's channel curves only when it holds ToneCurvePV2012 and all three of ToneCurvePV2012Red/Green/Blue; any partial set (master + one or two channels, channels without the master) imports without channel curves. #416 read them whenever the master curve was present. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
68e45585d0
commit
c732452d35
|
|
@ -244,13 +244,19 @@ pub fn to_partial(props: &Props, raw: Option<bool>) -> Value {
|
|||
put(o, "curve.master", 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
|
||||
// Lightroom Classic reads the red / green / blue curves only when the packet holds the master
|
||||
// 2012 curve and all three channel curves (as its own packets always do): a packet missing any
|
||||
// of them imports without channel curves (master + red, master + red + green, or red / green /
|
||||
// blue without the master all leave the photo's channels unchanged there)
|
||||
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);
|
||||
let channels = [("ToneCurvePV2012Red", "red"), ("ToneCurvePV2012Green", "green"), ("ToneCurvePV2012Blue", "blue")]
|
||||
.map(|(crs, ch)| (curve(props, &format!("crs:{crs}")), ch));
|
||||
if channels.iter().all(|(c, _)| c.is_some()) {
|
||||
for (c, ch) in channels {
|
||||
if let Some(c) = c {
|
||||
put(o, &format!("curve.{ch}"), c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -584,21 +590,34 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn channel_curves_need_the_master_curve() {
|
||||
// Lightroom ignores a red / green / blue curve without `ToneCurvePV2012`
|
||||
let packet = |master: &str| {
|
||||
fn channel_curves_need_the_master_and_all_channel_curves() {
|
||||
// Lightroom applies red / green / blue curves only when the master and all three are present
|
||||
let seq = |name: &str, pts: &str| format!("<crs:{name}><rdf:Seq>{pts}</rdf:Seq></crs:{name}>");
|
||||
let identity = "<rdf:li>0, 0</rdf:li><rdf:li>255, 255</rdf:li>";
|
||||
let bent = "<rdf:li>0, 0</rdf:li><rdf:li>64, 40</rdf:li><rdf:li>255, 255</rdf:li>";
|
||||
let packet = |curves: &[String]| {
|
||||
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>"#
|
||||
<rdf:Description rdf:about="" xmlns:crs="http://ns.adobe.com/camera-raw-settings/1.0/" crs:ToneCurveName2012="Custom">{}
|
||||
</rdf:Description></rdf:RDF></x:xmpmeta>"#,
|
||||
curves.concat()
|
||||
)
|
||||
};
|
||||
let alone = to_partial(&props(&packet("")), Some(true));
|
||||
let partial = |curves: &[String]| to_partial(&props(&packet(curves)), Some(true));
|
||||
let (master, red, green, blue) = (
|
||||
seq("ToneCurvePV2012", identity),
|
||||
seq("ToneCurvePV2012Red", identity),
|
||||
seq("ToneCurvePV2012Green", bent),
|
||||
seq("ToneCurvePV2012Blue", identity),
|
||||
);
|
||||
// a channel curve alone, or with the master but without its two siblings: ignored
|
||||
let alone = partial(std::slice::from_ref(&green));
|
||||
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}");
|
||||
let master_and_green = partial(&[master.clone(), green.clone()]);
|
||||
assert!(master_and_green.pointer("/curve/green").is_none() && master_and_green.pointer("/curve/master").is_some(), "{master_and_green}");
|
||||
// all four: read
|
||||
let all = partial(&[master, red, green, blue]);
|
||||
assert!(["/curve/master", "/curve/red", "/curve/green", "/curve/blue"].iter().all(|p| all.pointer(p).is_some()), "{all}");
|
||||
}
|
||||
|
||||
fn unmapped(x: &str) -> Vec<String> {
|
||||
|
|
|
|||
|
|
@ -81,7 +81,8 @@
|
|||
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.
|
||||
- XMP presets apply their red / green / blue curves only when they also have the master curve and all three channel
|
||||
curves, as Lightroom does: a preset with just one channel curve (or no master curve) leaves the channels alone.
|
||||
- Imported `.cube` LUT profiles appear in the Profile menu and the profile browser, grouped by their folder, and stay
|
||||
favourites across restarts (issue #328).
|
||||
|
||||
|
|
|
|||
|
|
@ -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; the red / green / blue curves are read only with `ToneCurvePV2012` (Lightroom Classic ignores them without it) |
|
||||
| `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 when `ToneCurvePV2012` and all three channel curves are present (Lightroom Classic ignores them otherwise: a master + red-only packet renders without the red curve) |
|
||||
| `SplitToningShadowHue/Saturation`, `SplitToningHighlightHue/Saturation` | `grading.shadows/highlights.hue/sat` | |
|
||||
| `ColorGradeShadowLum`, `ColorGradeHighlightLum` | `grading.shadows/highlights.lum` | |
|
||||
| `ColorGradeMidtoneHue/Sat/Lum`, `ColorGradeGlobalHue/Sat/Lum` | `grading.midtones/global.*` | |
|
||||
|
|
|
|||
Loading…
Reference in New Issue