From 2ca27de40bb3d689e445060219db55c4c57c7617 Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Sat, 31 Oct 2026 20:57:37 -0700 Subject: [PATCH] .ai save: the no-PDF-content warning names the editing data A .ai saved with pdfCompatible false warned that other apps show empty pages, also when the file carries the editing copy of its art. With the editing copy the warning now says that apps that read its editing data open it; with editingData false it is unchanged. --- crates/engine/src/cmd/fileio/save.rs | 7 ++++++- crates/engine/src/tests/saveoptions.rs | 6 +++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/crates/engine/src/cmd/fileio/save.rs b/crates/engine/src/cmd/fileio/save.rs index 1a9d77ebb..35cef3e56 100644 --- a/crates/engine/src/cmd/fileio/save.rs +++ b/crates/engine/src/cmd/fileio/save.rs @@ -574,6 +574,9 @@ fn blank_pages(doc: &Document) -> Document { /// Why a `.ai` file saved without PDF content looks empty elsewhere. const NOT_PDF_COMPATIBLE: &str = "saved without PDF content: VectorCraft opens it as before, other apps show empty pages"; +/// The same, for a file that carries the editing copy of its art. +const NOT_PDF_COMPATIBLE_EDITING: &str = + "saved without PDF content: VectorCraft and apps that read its editing data open it, other apps show empty pages"; /// `e`, an error of the export encoders, under the save command `cmd` instead of /// `document.export`. @@ -631,6 +634,7 @@ pub(super) fn encode_ai(cmd: &str, f: &Format, doc: &Document, p: &Value) -> Res }; let native = || super::native::ai_native(cmd, doc, &native_options); let other_apps: AiEditingData = super::encode::options(f, ¶ms)?; + let carries_editing = std::cell::Cell::new(false); let private = || { if !other_apps.editing_data.unwrap_or(true) { return Ok(None); @@ -651,12 +655,13 @@ pub(super) fn encode_ai(cmd: &str, f: &Format, doc: &Document, p: &Value) -> Res let (data, lost) = vectorcraft_eps::ai_private_data(art, &o).map_err(|e| bad(cmd, e))?; // Placed files that weren't found are written as their previews here too. resolved_warnings.extend(lost); + carries_editing.set(true); Ok(Some((data, resolved_warnings))) }; let (bytes, mut warnings) = super::pdf::encode_carrying(cmd, &pages, ¶ms, native, private)?; warnings.extend(placed_warnings); if !pdf_compatible { - warnings.push(NOT_PDF_COMPATIBLE.to_string()); + warnings.push(if carries_editing.get() { NOT_PDF_COMPATIBLE_EDITING } else { NOT_PDF_COMPATIBLE }.to_string()); } Ok(Encoded { warnings, ..Encoded::one(bytes) }) } diff --git a/crates/engine/src/tests/saveoptions.rs b/crates/engine/src/tests/saveoptions.rs index ff17ef34e..feca82401 100644 --- a/crates/engine/src/tests/saveoptions.rs +++ b/crates/engine/src/tests/saveoptions.rs @@ -196,7 +196,11 @@ fn ai_without_pdf_content_and_compression() { }; let (full, _) = ai(&mut s, json!({})); let (blank, warnings) = ai(&mut s, json!({"pdfCompatible": false})); - assert!(warnings.as_array().unwrap().iter().any(|w| w.as_str().unwrap().contains("without PDF content")), "{warnings}"); + let says = |w: &Value, text: &str| w.as_array().unwrap().iter().any(|w| w.as_str().unwrap().contains(text)); + assert!(says(&warnings, "without PDF content") && says(&warnings, "apps that read its editing data open it"), "{warnings}"); + // Without the editing copy, other apps show empty pages. + let (_, plain) = ai(&mut s, json!({"pdfCompatible": false, "editingData": false})); + assert!(says(&plain, "VectorCraft opens it as before") && !says(&plain, "editing data"), "{plain}"); // The pages are empty (an import of a page finds no art), the document comes back whole. let page = |s: &mut Session, b: &[u8]| { s.execute("document.open", &json!({"name": "x.ai", "dataBase64": vectorcraft_format::base64_encode(b), "pages": "1"})).unwrap();