Import Lightroom presets as looks

A Lightroom preset changes the settings it was saved with and leaves every
other one where the photograph had it. Imported as a whole edit, a preset
holding only a grade reset the exposure, white balance and noise reduction
it was put on top of — the opposite of what the photographer had in
Lightroom.

Imported presets now reach only the operations they name
(`Reach::Named`), the rule the shipped presets already follow.
This commit is contained in:
2026-09-26 13:44:32 -04:00
parent a7b090cf36
commit e82190fdf2
2 changed files with 28 additions and 4 deletions
+26 -2
View File
@@ -44,7 +44,7 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use dr_pipeline::Preset; use dr_pipeline::{Preset, Reach};
use quick_xml::events::Event; use quick_xml::events::Event;
use quick_xml::XmlVersion; use quick_xml::XmlVersion;
@@ -300,7 +300,11 @@ pub fn read_xmp(text: &str) -> Result<Import, ImportError> {
Ok(Import { Ok(Import {
name, name,
preset: Preset::from_params(params), // A look, because that is what a Lightroom preset is: it changes the
// settings it was saved with and leaves every other one where the
// photograph had it. Applied as a whole edit instead, a preset
// holding only a grade would reset the exposure it was put on top of.
preset: Preset::from_params(params).with_reach(Reach::Named),
skipped, skipped,
}) })
} }
@@ -485,6 +489,26 @@ mod tests {
); );
} }
/// TRACES: FR-DEV-6
/// Lightroom's own rule: a preset changes what it was saved with and
/// nothing else, so a grade lands on top of the photograph's correction.
#[test]
fn an_imported_preset_leaves_what_it_does_not_set_alone() {
use dr_pipeline::ops::dehaze;
let import = read_xmp(ATTRIBUTE_FORM).unwrap();
assert_eq!(import.preset.reach(), Reach::Named);
assert!(value(&import, "dehaze", "amount").is_none());
let mut graph = EditGraph::default_chain();
graph.set_param(dehaze::ID, dehaze::AMOUNT, 30.0);
import
.preset
.apply(&mut graph, Scope::adjustments())
.expect_no_film();
assert_eq!(graph.param(dehaze::ID, dehaze::AMOUNT), Some(30.0));
}
#[test] #[test]
fn a_value_that_is_not_a_number_costs_that_setting_and_not_the_file() { fn a_value_that_is_not_a_number_costs_that_setting_and_not_the_file() {
let text = let text =
File diff suppressed because one or more lines are too long