Merge pull request #2937 from dotCooCoo/fix/ai-image-left-out-warns

.ai import: the editing data reader warns about each image it can't read
This commit is contained in:
BFlat
2026-10-19 00:09:38 +07:00
committed by GitHub
2 changed files with 51 additions and 4 deletions
+17 -4
View File
@@ -2012,9 +2012,15 @@ impl<'a> Reader<'a> {
/// An image of operands `vals` and samples `data`.
fn image_from(&mut self, vals: Vec<V>, data: &[u8]) -> Result<(), String> {
let space = self.raster.as_ref().and_then(|r| r.space.clone()).unwrap_or_default();
let Some(m) = vals.iter().find_map(|v| if let V::Arr(a) = v { Some(Self::nums(a)) } else { None }) else { return Ok(()) };
let Some(m) = vals.iter().find_map(|v| if let V::Arr(a) = v { Some(Self::nums(a)) } else { None }) else {
self.warn("an image VectorCraft can't read was left out");
return Ok(());
};
let n = Self::nums(&vals);
let [_, _, _, _, w, h, bits, kind, alpha, _, binary, ..] = n.as_slice() else { return Ok(()) };
let [_, _, _, _, w, h, bits, kind, alpha, _, binary, ..] = n.as_slice() else {
self.warn("an image VectorCraft can't read was left out");
return Ok(());
};
let (w, h) = (*w as u64, *h as u64);
if w == 0 || h == 0 || w.saturating_mul(h) > MAX_PIXELS || ![1.0, 8.0].contains(bits) {
self.warn("an image VectorCraft can't read was left out");
@@ -2080,7 +2086,10 @@ impl<'a> Reader<'a> {
rgba.extend_from_slice(&[px[0], px[1], px[2], a]);
}
}
let Some(img) = image::RgbaImage::from_raw(w as u32, h as u32, rgba) else { return Ok(()) };
let Some(img) = image::RgbaImage::from_raw(w as u32, h as u32, rgba) else {
self.warn("an image VectorCraft can't read was left out");
return Ok(());
};
let mut png = vec![];
if img.write_to(&mut std::io::Cursor::new(&mut png), image::ImageFormat::Png).is_err() {
self.warn("an image VectorCraft can't read was left out");
@@ -2096,10 +2105,14 @@ impl<'a> Reader<'a> {
// The matrix is an art-space matrix (y up) applied to the pixels with their rows running
// downwards, (u, -v): pixels → (u, -v) → art space. Flipping the matrix's result instead
// gives the same place only when the image isn't rotated (b = c = 0).
let [a, b, c, d, tx, ty] = m else { return Ok(()) };
let [a, b, c, d, tx, ty] = m else {
self.warn("an image VectorCraft can't read was left out");
return Ok(());
};
let to_doc = self.space();
let xf = to_doc * Affine::new([*a, *b, *c, *d, *tx, *ty]) * FLIP;
if !xf.as_coeffs().iter().all(|v| v.is_finite()) || xf.determinant().abs() < 1e-12 {
self.warn("an image VectorCraft can't read was left out");
return Ok(());
}
let mask = alpha.and_then(|a| self.alpha_mask(a, w, h, xf));
+34
View File
@@ -677,6 +677,40 @@ fn images_with_alpha_channels() {
assert!(art(&r.doc).is_empty() && r.warnings.iter().any(|w| w.contains("cut short")));
}
/// Editing data `data` opens without its one image and with the warning "an image VectorCraft can't read was left out" once.
fn image_left_out_with_a_warning(data: &[u8]) {
let r = read(data).unwrap();
assert!(art(&r.doc).is_empty(), "{:#?}", art(&r.doc));
let left_out = r.warnings.iter().filter(|w| *w == "an image VectorCraft can't read was left out").count();
assert_eq!(left_out, 1, "{:?}", r.warnings);
}
#[test]
fn an_image_without_a_matrix_is_left_out_with_a_warning() {
image_left_out_with_a_warning(&image("", (1, 1), ("DeviceRGB", 3, 0), &[255, 0, 0], 3));
}
#[test]
fn an_image_with_too_few_operands_is_left_out_with_a_warning() {
// The operands hold 10 numbers after the matrix, one short of the binary flag.
let text = String::from_utf8(image("[ 1 0 0 1 0 100 ]", (1, 1), ("DeviceRGB", 3, 0), b"abc", 3)).unwrap();
let data = text.replacen("] 0 0 1 1 1 1 8 3 0 0 1 0 4 4 0 0\n", "] 0 0 1 1 1 1 8 3 0 0\n", 1);
assert_ne!(data, text);
image_left_out_with_a_warning(data.as_bytes());
}
#[test]
fn an_image_whose_matrix_isnt_six_numbers_is_left_out_with_a_warning() {
image_left_out_with_a_warning(&image("[ 1 0 0 1 ]", (1, 1), ("DeviceRGB", 3, 0), &[255, 0, 0], 3));
}
#[test]
fn an_image_whose_matrix_has_no_area_is_left_out_with_a_warning() {
image_left_out_with_a_warning(&image("[ 0 0 0 0 0 0 ]", (1, 1), ("DeviceRGB", 3, 0), &[255, 0, 0], 3));
// This matrix maps the image onto a line.
image_left_out_with_a_warning(&image("[ 1 2 2 4 0 100 ]", (1, 1), ("DeviceRGB", 3, 0), &[255, 0, 0], 3));
}
/// The raster matrix `[a b c d tx ty]` is an art-space matrix (y up) applied to the image's pixels
/// with their rows running downwards, `(u, -v)`: art x = a·u − c·v + tx, art y = b·u − d·v + ty.
/// Without rotation (b = c = 0) that is the same as flipping the matrix's result; a rotated image