From a01e04590567102883c93aa15cf78759b70c97cc Mon Sep 17 00:00:00 2001 From: bflatastic Date: Wed, 7 Oct 2026 11:42:05 +0700 Subject: [PATCH] Fix #255: selection exports report the encoder's warnings document.exportSelection (the MCP export tool's `selection: true`) now replies with `format` and the encoder's `warnings`, the same list a whole-document export gives: lossy WebP written lossless, blend modes left out of SVG Tiny 1.2, PDF layers at 1.4 and the rest. A selection export that approximates nothing replies with an empty list. Root cause: export_selection encoded with `encode`, which drops the warnings encode_with_warnings returns, and its reply carried only path, bytes and bounds. The params doc and docs/mcp.md now describe the reply. Co-Authored-By: Claude Opus 5.5 --- crates/engine/src/cmd/fileio/export.rs | 8 +++++--- crates/engine/src/cmd/fileio/mod.rs | 2 +- crates/engine/src/tests_file.rs | 27 ++++++++++++++++++++++++++ docs/mcp.md | 2 +- 4 files changed, 34 insertions(+), 5 deletions(-) diff --git a/crates/engine/src/cmd/fileio/export.rs b/crates/engine/src/cmd/fileio/export.rs index 79fd3aa0..543eda48 100644 --- a/crates/engine/src/cmd/fileio/export.rs +++ b/crates/engine/src/cmd/fileio/export.rs @@ -11,7 +11,7 @@ use crate::DocState; use super::super::*; use super::encode::single_artboard; -use super::{ARTBOARD_PARAMS, Format, default_name, encode, encode_all, merge, writable, write_encoded, write_or_return}; +use super::{ARTBOARD_PARAMS, Format, default_name, encode, encode_all, encode_with_warnings, merge, writable, write_encoded, write_or_return}; pub(super) fn serialize(s: &mut Session, p: &Value) -> Result { let f = writable("document.serialize", Some(str_param(p, "format").unwrap_or("vectorcraft")), None)?; @@ -151,8 +151,10 @@ pub(super) fn export_selection(s: &mut Session, p: &Value) -> Result { let expanded = expand_presets(s, C, p)?; let p = &*expanded; let (d, bounds) = selection(s, C)?; - let bytes = encode(&d, f.id, &without_artboards(p))?; - write_or_return(path, &bytes, json!({ "bounds": [bounds.x0, bounds.y0, bounds.width(), bounds.height()] })) + // The encoder's warnings (options accepted but not applied, features approximated or left + // out), as document.export reports them. + let (bytes, warnings) = encode_with_warnings(&d, f.id, &without_artboards(p))?; + write_or_return(path, &bytes, json!({ "format": f.id, "warnings": warnings, "bounds": [bounds.x0, bounds.y0, bounds.width(), bounds.height()] })) } /// File → Save for Office Documents: one artboard as a PNG at `ppi`, on white unless diff --git a/crates/engine/src/cmd/fileio/mod.rs b/crates/engine/src/cmd/fileio/mod.rs index fe66845b..88b7de09 100644 --- a/crates/engine/src/cmd/fileio/mod.rs +++ b/crates/engine/src/cmd/fileio/mod.rs @@ -105,7 +105,7 @@ pub fn specs() -> Vec { "Export Selection…", ["File"], None, - "{path?, format?: png|jpg|webp|svg|svgz|pdf (default: from the extension, else png), scale?: 1, …the format's options} the selected objects cropped to their bounds (template layers left out) → {path, bytes, bounds} (no path → {dataBase64, bounds})", + "{path?, format?: png|jpg|webp|svg|svgz|pdf (default: from the extension, else png), scale?: 1, …the format's options} the selected objects cropped to their bounds (template layers left out) → {path, format, bytes, warnings, bounds} (no path → {dataBase64, format, bytes, warnings, bounds}); warnings say what the format approximated or left out, as for document.export", has_selection, export::export_selection ), diff --git a/crates/engine/src/tests_file.rs b/crates/engine/src/tests_file.rs index c9ab6a62..56d180e1 100644 --- a/crates/engine/src/tests_file.rs +++ b/crates/engine/src/tests_file.rs @@ -168,6 +168,33 @@ fn export_selection_crops_to_the_selection() { assert_eq!(text.matches("