From ef5a4d967a4893a7a1586127c900e9b3d8d5ec79 Mon Sep 17 00:00:00 2001 From: Don Omondi <282319807+mockydevs@users.noreply.github.com> Date: Wed, 4 Nov 2026 09:46:07 -0500 Subject: [PATCH] Fix #5502: Export As PNG exports the active artboard, not always the first File > Export > Export As PNG... opened PNG Options with no artboard chosen, and a single-image export without one writes the first artboard, whichever was in use. With no artboard choice given, it now takes the active artboard, or each artboard the Artboard tool has selected (one file each). A choice the caller gives is kept. --- crates/ui-egui/src/dialogs/tests_export.rs | 31 ++++++++++++++++++++++ crates/ui-egui/src/menus/run.rs | 13 +++++++++ docs/ui-parity.md | 3 ++- 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/crates/ui-egui/src/dialogs/tests_export.rs b/crates/ui-egui/src/dialogs/tests_export.rs index f658c31b0..891fb586b 100644 --- a/crates/ui-egui/src/dialogs/tests_export.rs +++ b/crates/ui-egui/src/dialogs/tests_export.rs @@ -106,6 +106,37 @@ fn export_as_png_picks_the_file_then_shows_png_options() { assert_eq!(&written.borrow()[0].1[16..20], 120u32.to_be_bytes(), "60 pt at 144 ppi"); } +/// File › Export › Export As PNG… exports the artboard in use, not the first (#5502), and each +/// artboard the Artboard tool has selected, one file each. +#[test] +fn export_as_png_exports_the_active_artboard() { + let (mut app, written) = app(2); + // The ellipse is on the first artboard; the second is empty. + let opaque = |bytes: &[u8]| image::load_from_memory(bytes).unwrap().to_rgba8().pixels().any(|p| p.0[3] > 0); + app.view_mut().unwrap().artboard = 1; + app.run("file.export.png", json!({})).unwrap(); + assert_eq!(app.ui.dialog.as_ref().unwrap().fields["artboard"], json!(1)); + frame(&mut app); + confirm(&mut app).unwrap(); + assert!(!opaque(&written.borrow()[0].1), "the second artboard, which is empty"); + app.view_mut().unwrap().artboard = 0; + app.run("file.export.png", json!({})).unwrap(); + frame(&mut app); + confirm(&mut app).unwrap(); + assert!(opaque(&written.borrow()[1].1), "the first artboard, with the ellipse"); + // A choice given is kept. + app.run("file.export.png", json!({"useArtboards": false})).unwrap(); + assert!(app.ui.dialog.as_ref().unwrap().fields.get("artboard").is_none_or(serde_json::Value::is_null)); + app.ui.dialog = None; + // Artboards the Artboard tool selected: one file each. + app.select_tool("artboard"); + app.session.set_tool_option("selected", &json!([0, 1])); + app.run("file.export.png", json!({})).unwrap(); + frame(&mut app); + confirm(&mut app).unwrap(); + assert_eq!(names(&written)[2..], ["/out/Untitled-1-Artboard-1.png", "/out/Untitled-1-Artboard-2.png"]); +} + #[test] fn export_as_with_a_range_then_png_options_writes_one_file_per_artboard() { let (mut app, written) = app(3); diff --git a/crates/ui-egui/src/menus/run.rs b/crates/ui-egui/src/menus/run.rs index 80fe0a184..2d134f76f 100644 --- a/crates/ui-egui/src/menus/run.rs +++ b/crates/ui-egui/src/menus/run.rs @@ -170,6 +170,19 @@ fn run_ui_part2(app: &mut VectorcraftApp, id: &str, p: &Value) -> Option 0 { + match crate::panels::artboards::picked(app, n).as_slice() { + [i] => params["artboard"] = json!(i), + several => { + params["artboards"] = json!(several); + params["useArtboards"] = json!(true); + } + } + } crate::dialogs::open_raster_options(app, f, params); Ok(Value::Null) }), diff --git a/docs/ui-parity.md b/docs/ui-parity.md index 26f56b16f..bbfcdc069 100644 --- a/docs/ui-parity.md +++ b/docs/ui-parity.md @@ -1,6 +1,6 @@ # UI and interaction parity -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-04 · **Change:** minor (New Document's units belong to the chosen preset; Recent and Saved cards keep their own units; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x; Units › East Asian Type acts, with Q and Ha units; scores unchanged) · **Target:** Adobe Illustrator 2026 (30.x) +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-04 · **Change:** minor (File › Export › Export As PNG exports the active artboard, or each one the Artboard tool selected, not always the first, #5502; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x; Units › East Asian Type acts, with Q and Ha units; scores unchanged) · **Target:** Adobe Illustrator 2026 (30.x) ## Feature submission evidence @@ -30,6 +30,7 @@ Artboard Options forwards the active Artboard tool's Scale Artwork with Artboard | Date | Change | Summary | |---|---|---| +| 2026-11-04 | minor | File › Export › Export As PNG… exports the active artboard, or each artboard the Artboard tool has selected (one file each), instead of always the first (#5502); a choice the caller gives is kept; scores and estimates unchanged | | 2026-11-04 | minor | Document Tools add-on (a VectorCraft addition): Object › Plug-ins › Document Tools › Batch Trace Folder asks for a folder of images and a destination folder and traces each image into it (#4921); scores and estimates unchanged | | 2026-11-03 | minor | The Action Options row cites the public Actions panel page and describes its controls. Scores and estimates remain unchanged. | | 2026-11-03 | minor | Enclosing Lasso provides whole-object enclosure selection as an add-on with no default shortcut or Basic toolbar slot. Scores and estimates remain unchanged. |