diff --git a/crates/eps/src/import/ai/read.rs b/crates/eps/src/import/ai/read.rs index d77862d1c..a9ccf6d9a 100644 --- a/crates/eps/src/import/ai/read.rs +++ b/crates/eps/src/import/ai/read.rs @@ -22,7 +22,8 @@ //! (y down, its centre the template box's), where they start at the point of art space's origin, //! the first row the top one. Each is a linked image showing the preview until its file is found. //! - Art with an appearance the format can't write as plain art (several fills or strokes, -//! effects, brushes) comes first as that look, drawn (a group), then the object itself on `%_` +//! effects, brushes) comes first as that look, drawn (a group, or an image where an effect +//! rasterizes it), then the object itself on `%_` //! lines and `1 (style) XW`: the drawn look is kept, named after the object. //! - Patterns: `%AI3_BeginPattern: (name)`, `(name) llx lly urx ury` (the tile, in the pattern's //! space, y up), the tile's art (on `%_` lines in newer files), `E`, `%AI3_EndPattern`; each is @@ -1549,9 +1550,10 @@ impl<'a> Reader<'a> { let (Some(object), Some(look)) = (n.checked_sub(1).and_then(|i| f.children.get(i)), n.checked_sub(2).and_then(|i| f.children.get(i))) else { return; }; + // The look is a group of paths, or one image where an effect (a blur, a shadow) rasterizes it. if !self.hidden_ids.contains(&object.id) || self.hidden_ids.contains(&look.id) != hidden - || !matches!(look.kind, NodeKind::Group { clip: false, .. }) + || !matches!(look.kind, NodeKind::Group { clip: false, .. } | NodeKind::Image(_)) { return; } diff --git a/crates/eps/src/import/ai/tests.rs b/crates/eps/src/import/ai/tests.rs index 18fd9cb02..52a11cc11 100644 --- a/crates/eps/src/import/ai/tests.rs +++ b/crates/eps/src/import/ai/tests.rs @@ -539,6 +539,21 @@ fn image(matrix: &str, (w, h): (u32, u32), (space, kind, alpha): (&str, u32, u32 out } +/// An effect that rasterizes (a blur) leaves its drawn look as one image, then the object itself on +/// `%_` lines: the image stands for the object, as for a drawn look that's a group. +#[test] +fn a_drawn_look_that_is_an_image_stands_for_its_object() { + let mut data = image("[ 10 0 0 10 50 90 ]", (1, 1), ("DeviceRGB", 3, 0), &[255, 0, 0], 3); + let object = format!("%_0 Ae\r\n%_u\r\n%_{}f\r\n%_U\r\n1 (Blurred) XW\r\n", rect_path(0.0, 0.0, 10.0, 10.0).replace('\n', "\r\n%_")); + let at = data.windows(6).position(|w| w == b"N\r\nLB\r").unwrap() + 3; + data.splice(at..at, object.into_bytes()); + let r = read(&data).unwrap(); + let a = art(&r.doc); + assert_eq!(a.len(), 1, "{a:#?}"); + assert!(matches!(a[0].kind, NodeKind::Image(_)), "{:?}", a[0].kind); + assert!(r.warnings.iter().any(|w| w.contains("drawn look (1)")), "{:?}", r.warnings); +} + fn pixels(doc: &Document) -> (image::RgbaImage, kurbo::Affine) { let a = art(doc); let NodeKind::Image(im) = &a[0].kind else { panic!("{:?}", a[0].kind) };