mirror of
https://github.com/storytold/photocraft.git
synced 2026-10-28 18:22:06 +01:00
Crop: a W x H crop on an Indexed Color document resamples with Nearest Neighbor (#7722)
The Crop tool's W x H x Resolution mode resampled with the chosen filter (Bicubic by default) even on an Indexed Color document, so the result held blends outside the colour table. Like Image Size (#6019), it now falls back to Nearest Neighbor there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
d95fdf3181
commit
d20a0782da
@@ -531,7 +531,9 @@ impl CropTarget {
|
||||
/// Applies the target to a document that has just been cropped (inside the crop's history step).
|
||||
fn apply(&self, doc: &mut Document) {
|
||||
if let Some((w, h)) = self.size {
|
||||
resample_doc(doc, w, h, self.filter);
|
||||
// As for Image Size: an Indexed Color document holds only its colour table's colours (#6019).
|
||||
let filter = if doc.mode == ColorMode::Indexed { Resample::Nearest } else { self.filter };
|
||||
resample_doc(doc, w, h, filter);
|
||||
}
|
||||
if let Some(r) = self.resolution {
|
||||
doc.resolution_dpi = r;
|
||||
@@ -1420,6 +1422,32 @@ mod tests {
|
||||
assert_eq!((doc(&s).size, doc(&s).resolution_dpi), (Size::new(30, 10), 150.0));
|
||||
}
|
||||
|
||||
/// #7722: a W x H crop of an Indexed Color document resamples like Image Size (#6019), with
|
||||
/// Nearest Neighbor, so no pixel gets a blend that isn't in the colour table.
|
||||
#[test]
|
||||
fn crop_target_resamples_indexed_color_with_nearest_neighbor() {
|
||||
let mut s = Session::new();
|
||||
s.execute("file.new", json!({"width": 2, "height": 1})).unwrap();
|
||||
s.execute("edit.fill", json!({"color": "#ff0000"})).unwrap();
|
||||
s.execute("select.rect", json!({"x": 1, "y": 0, "width": 1, "height": 1})).unwrap();
|
||||
s.execute("edit.fill", json!({"color": "#0000ff"})).unwrap();
|
||||
s.execute("select.deselect", json!({})).unwrap();
|
||||
s.execute("image.mode.indexedColor", json!({})).unwrap();
|
||||
for resample in [None, Some("bicubic"), Some("automatic"), Some("bilinear"), Some("lanczos")] {
|
||||
let mut p = json!({"x": 0, "y": 0, "width": 2, "height": 1, "targetWidth": 8, "targetHeight": 1});
|
||||
if let Some(r) = resample {
|
||||
p["resample"] = json!(r);
|
||||
}
|
||||
s.execute("image.crop", p).unwrap();
|
||||
let surf = doc(&s).layers[0].surface().unwrap();
|
||||
for x in 0..8 {
|
||||
let px = surf.pixel(x, 0);
|
||||
assert!(px[..3] == [1.0, 0.0, 0.0] || px[..3] == [0.0, 0.0, 1.0], "{resample:?}: no blended colour at x {x}: {px:?}");
|
||||
}
|
||||
s.execute("history.undo", json!({})).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn crop_target_accepts_whole_number_floats() {
|
||||
// `json.dumps(100.0)` and many other JSON writers send whole numbers as floats.
|
||||
|
||||
Reference in New Issue
Block a user