Lightroom catalog import: size radial masks with the stored image's aspect (part of #1806)

This commit is contained in:
Marco Arnulfo
2026-10-29 23:14:32 +01:00
parent b3f569a824
commit 307ec1a053
2 changed files with 15 additions and 4 deletions
+8 -4
View File
@@ -703,7 +703,11 @@ fn mapped_settings(
if !props.contains_key("crs:HasCrop") && CROP.iter().any(|k| props.contains_key(*k)) {
props.insert("crs:HasCrop".into(), vec!["True".into()]);
}
let (mut partial, mut unknown) = crate::crs::to_partial_report(&props, Some(&values), target, aspect);
// Mask edges are fractions of the stored image, like the crop's, so radii go to long-edge units
// with its aspect: `aspect` is the photo's in LightCraft, which is the shown one for a photo
// already in the library and only stands in when the catalog has no file size.
let mask_aspect = if stored_aspect.is_finite() && stored_aspect > 0.0 { stored_aspect } else { aspect };
let (mut partial, mut unknown) = crate::crs::to_partial_report(&props, Some(&values), target, mask_aspect);
catalog_crop(&mut partial, orientation, stored_aspect);
catalog_masks(&mut partial, orientation);
if deferred > 0 {
@@ -767,9 +771,9 @@ fn catalog_crop(partial: &mut Value, orientation: Orientation, stored_aspect: f6
/// Lightroom's masks in LightCraft's frame. Like the crop's corners, their positions are on the
/// stored image (before orientation), normalized to its size; LightCraft's are on the oriented
/// image. So the points go through the orientation, a radial's radii (in long-edge units) swap when
/// the axes do, and a mirror turns its angle the other way. A quarter turn keeps the angle: the
/// ellipse turned 90° is the same ellipse with its radii swapped.
/// image. So the points go through the orientation, a radial's radii (in long-edge units, from the
/// stored image's aspect) swap when the axes do, and a mirror turns its angle the other way. A
/// quarter turn keeps the angle: the ellipse turned 90° is the same ellipse with its radii swapped.
fn catalog_masks(partial: &mut Value, orientation: Orientation) {
if orientation == Orientation::Normal {
return;
@@ -332,6 +332,13 @@ fn catalog_masks_follow_the_photo_orientation() {
assert_eq!(masks(Orientation::Rotate180), [0.9, 0.8, 0.7, 0.4, 0.9, 0.8, r.0, r.1, 10.0, 0.9, 0.8, 0.7, 0.4]);
assert_eq!(masks(Orientation::FlipH), [0.9, 0.2, 0.7, 0.6, 0.9, 0.2, r.0, r.1, -10.0, 0.9, 0.2, 0.7, 0.6]);
assert_eq!(masks(Orientation::Transpose), [0.2, 0.1, 0.6, 0.3, 0.2, 0.1, r.1, r.0, -10.0, 0.2, 0.1, 0.6, 0.3]);
// a photo already in the library has its shown size (portrait here), but Lightroom's edges are
// fractions of the stored image: a circle on a 3:2 stored image stays a circle
let s = r#"s = { MaskGroupBasedCorrections = { { What = "Correction", CorrectionAmount = 1, LocalExposure2012 = 0.1, CorrectionMasks = {
{ What = "Mask/CircularGradient", Left = 0.3, Right = 0.5, Top = 0.3, Bottom = 0.6, Version = 2, Flipped = true } } } } }"#;
let (partial, _) = mapped_settings(s, crate::crs::Target::RawAbsolute, 1.0 / 1.5, Orientation::Rotate90, 1.5).unwrap();
let radial = &partial["masks"][0]["components"][0]["shape"];
assert!(close(&radial["rx"], 0.1) && close(&radial["ry"], 0.1), "{radial}");
}
/// The `crs` corners and angle Lightroom would store for LightCraft crop `g` on a stored image