Never crash: Fix export size panic for very long strips

Apply the 1 px and 65535 px bounds in turn instead of clamping between bounds that can cross.
This commit is contained in:
Michael Anderson committed 2026-10-13 10:45:34 -05:00
1 parent b3d392b499
commit 337f02b4dc
2 files changed
+34 -2

No files matched your search

+30 -2
View File
@@ -131,8 +131,9 @@ impl Resize {
ResizeMode::Percent => v / 100.0,
};
let k = if self.dont_enlarge { k.min(1.0) } else { k };
// at least one pixel, at most the encoders' 65535 limit
k.clamp(1.0 / short, 65_535.0 / long)
// at least one pixel, at most the encoders' 65535 limit; the limit wins for a photo more
// than 65535 times as long as it is short (where `clamp` would panic: min above max)
k.max(1.0 / short).min(65_535.0 / long)
}
/// Output size for a `w × h` (cropped, full-resolution) photo.
@@ -2783,6 +2784,33 @@ mod tests {
}
}
/// A photo more than 65535 times as long as it is short (a 70000 × 1 strip) made `scale`
/// clamp with its lower bound above its upper one, which panics, in the export and in the
/// Export dialog's preview on the UI thread. The encoders' limit wins, the short edge keeps a
/// pixel.
#[test]
fn resize_survives_photos_too_long_for_the_encoders() {
let modes = [
json!({"longEdge": 2000}),
json!({"shortEdge": 1}),
json!({"width": 500, "height": 500}),
json!({"megapixels": 1}),
json!({"percent": 50}),
json!({"percent": 1000, "dontEnlarge": false}),
];
for p in modes {
for (w, h) in [(70_000.0, 1.0), (1.0, 70_000.0), (1e9, 3.0), (65_536.0, 1.0)] {
let r = ExportOptions::from_json(&p).resize.unwrap();
let (ow, oh) = r.apply(w, h);
assert!((1..=65_535).contains(&ow) && (1..=65_535).contains(&oh), "{p} on {w}×{h}: {ow}×{oh}");
assert!(r.scale(w, h).is_finite());
}
}
// (a short edge under a pixel would be scaled up to one, which the limit then caps)
assert_eq!(Resize::long_edge(2000).apply(70_000.0, 1.0), (65_535, 1));
assert_eq!(Resize::long_edge(2000).apply(1.0, 70_000.0), (1, 65_535));
}
/// A flat field of a saturated green inside Display P3 but outside sRGB, rendered into `space`.
fn p3_green(space: OutputSpace) -> Rgba8 {
use lightcraft_color::{DISPLAY_P3, REC2020};
+4
View File
@@ -2,6 +2,10 @@
## 2026-10-13
### Reliability
- Exporting a photo more than 65,535 times as long as it is wide (a one-pixel strip), or opening the Export dialog's
watermark preview for it, no longer crashes LightCraft; the export is capped at the encoders' 65,535 pixels.
### Slider drags on large raws
- Dragging a slider no longer re-renders the edited photo's filmstrip thumbnail on every frame; it follows once you
let go. On a 64 MP raw the first of those renders decoded the whole file again, which held up the loupe's