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.
This commit is contained in:
Don Omondi
2026-11-04 21:59:04 +07:00
committed by bflatastic
parent 204b57e046
commit ef5a4d967a
3 changed files with 46 additions and 1 deletions
@@ -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);
+13
View File
@@ -170,6 +170,19 @@ fn run_ui_part2(app: &mut VectorcraftApp, id: &str, p: &Value) -> Option<Result<
let mut params = if p.is_object() { p.clone() } else { json!({}) };
params["format"] = json!("png");
params["path"] = json!(path);
// No artboard named: the artboard in use rather than the first (#5502), or each one the
// Artboard tool has selected, one file each.
let named = ["useArtboards", "rect"].iter().chain(vectorcraft_engine::cmd::fileio::ARTBOARD_PARAMS.iter()).any(|k| !params[*k].is_null());
let n = app.session.active().map_or(0, |d| d.doc.artboards.len());
if !named && n > 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)
}),
+2 -1
View File
@@ -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. |