From e66bca39b28713d5b7368c925d6f298d47aad300 Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Wed, 21 Oct 2026 15:36:45 -0700 Subject: [PATCH] Export: legacy .ai gives the size note for an image with empty data An image whose data is empty failed to decode before the size check, so a version 7 .ai said it couldn't be decoded. The writer now checks for empty data first and gives "an image that is empty or too large for legacy .ai was left out". docs/mcp.md now says the DXF decode note applies to R13 and later; R12 leaves out every image with its own note. --- crates/eps/src/legacy_ai.rs | 7 ++++++- crates/eps/src/tests_legacy_ai.rs | 22 ++++++++++++++++++++++ docs/mcp.md | 5 +++-- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/crates/eps/src/legacy_ai.rs b/crates/eps/src/legacy_ai.rs index af34ea176..ebe9a943e 100644 --- a/crates/eps/src/legacy_ai.rs +++ b/crates/eps/src/legacy_ai.rs @@ -1305,7 +1305,12 @@ impl<'a> Writer<'a> { if !invertible(m) { return; } - let Some(img) = self.doc.images.get(&im.key).and_then(|b| image::load_from_memory(&b.bytes).ok()) else { + let blob = self.doc.images.get(&im.key); + if blob.is_some_and(|b| b.bytes.is_empty()) { + self.warn(LARGE_IMAGE); + return; + } + let Some(img) = blob.and_then(|b| image::load_from_memory(&b.bytes).ok()) else { self.warn(UNDECODED); return; }; diff --git a/crates/eps/src/tests_legacy_ai.rs b/crates/eps/src/tests_legacy_ai.rs index 731e2537c..048daf834 100644 --- a/crates/eps/src/tests_legacy_ai.rs +++ b/crates/eps/src/tests_legacy_ai.rs @@ -382,6 +382,28 @@ fn images_are_written_in_the_form_the_specification_shows() { assert!(rgb.iter().zip([247.0, 148.0, 29.0]).all(|(c, want)| (c * 255.0 - want).abs() < 0.1), "{rgb:?}"); } +/// An image whose data is empty is left out with the note for empty or too large images, and an +/// image whose data can't be decoded is left out with the decode note. +#[test] +fn empty_images_get_the_size_note_and_undecodable_ones_the_decode_note() { + let notes = |bytes: Vec| { + let mut doc = Document::new(100.0, 100.0); + doc.layers.clear(); + let layer = doc.add_layer(Some("Images")); + let blob = ImageBlob::new("image/png", bytes); + let key = blob.content_key(); + doc.images.insert(key.clone(), blob); + let im = ImageObject { key, width: 4, height: 2, xf: Affine::IDENTITY, link: None, placement: Default::default() }; + let node = Node::new(doc.alloc_id(), NodeKind::Image(Box::new(im))); + doc.insert(Some(layer), usize::MAX, node).unwrap(); + let out = export_legacy_ai(&doc, &LegacyAiOptions::default()).unwrap(); + assert!(rasters(&String::from_utf8(out.bytes).unwrap()).is_empty()); + out.warnings + }; + assert_eq!(notes(vec![]), [LARGE_IMAGE]); + assert_eq!(notes(b"not an image".to_vec()), [UNDECODED]); +} + #[test] fn a_gradient_fill_and_its_stroke_are_one_object() { let mut doc = Document::new(100.0, 100.0); diff --git a/docs/mcp.md b/docs/mcp.md index f61279e49..0e8c4bb15 100644 --- a/docs/mcp.md +++ b/docs/mcp.md @@ -3207,8 +3207,9 @@ width profiles, arrowheads) as filled outlines; `"editability"` keeps type as te `alterPaths` writes every stroke as its filled outline, `outlineText` outlines type, `selectedOnly` writes only the selected objects in their layers (every export takes it), and `useArtboards: true` writes one drawing per chosen artboard holding the art over it. What DXF can't hold (gradients and patterns as one colour, blending, opacity masks, -raster effects, clipping) comes back in `warnings`. An image that can't be decoded is left out with no linked file, -and `warnings` carries "an image couldn't be decoded and is missing from the picture" once for all such images. +raster effects, clipping) comes back in `warnings`. In R13 and later, an image that can't be decoded is left out with +no linked file, and `warnings` carries "an image couldn't be decoded and is missing from the picture" once for all such +images. DWG can't be written (no openly licensed writer exists): `document.formats` lists it under `unsupported` with that hint, and exporting to it answers with the hint to export DXF. PICT files are not supported either and say so when