From 4fdf1a723ba89bbf075ecd6dd87f496be264dc97 Mon Sep 17 00:00:00 2001 From: Nigel Ihza Firdausy <106657905+Ni-zav@users.noreply.github.com> Date: Tue, 13 Oct 2026 13:48:04 +0700 Subject: [PATCH] fix(batch): skip recorded Quick Export steps when writing batch output (#4747) * fix(batch): ignore recorded Quick Export and use batch output * fix(batch): ignore recorded Quick Export and use batch output * cargo fmt Co-Authored-By: Claude Opus 5.5 --------- Co-authored-by: Brandon Thomas Co-authored-by: Claude Opus 5.5 --- crates/engine/src/file_cmds.rs | 2 +- crates/engine/src/file_cmds/tests.rs | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/crates/engine/src/file_cmds.rs b/crates/engine/src/file_cmds.rs index 5e9f7455c8..7470e78231 100644 --- a/crates/engine/src/file_cmds.rs +++ b/crates/engine/src/file_cmds.rs @@ -988,7 +988,7 @@ fn batch(s: &mut Session, p: &Value) -> Result { // Each result goes to the destination folder, which overrides the action's recorded Save / // Save As steps (Photoshop's "Override Action 'Save As' Commands"). Recorded view steps // (zoom, fit) don't change the output, so they are skipped (#2752). - steps.retain(|(id, _)| !crate::actions_cmds::shell_save_command(id) && !crate::actions_cmds::shell_view_command(id)); + steps.retain(|(id, _)| !crate::actions_cmds::shell_save_command(id) && !crate::actions_cmds::shell_view_command(id) && id != "file.export.quickExport"); if let Some((id, _)) = steps.iter().find(|(id, _)| crate::commands::find(id).is_none()) { return Err(EngineError::BadParams { cmd: cmd.into(), msg: format!("unknown command `{id}` in the action") }); } diff --git a/crates/engine/src/file_cmds/tests.rs b/crates/engine/src/file_cmds/tests.rs index fdfcf6c4b5..73c09020a5 100644 --- a/crates/engine/src/file_cmds/tests.rs +++ b/crates/engine/src/file_cmds/tests.rs @@ -756,6 +756,18 @@ fn load_files_into_stack_and_image_processor_and_batch() { let inv = photocraft_io::import("a.png", &std::fs::read(join(&out, "a.png")).unwrap()).unwrap().document; let px = photocraft_compose::render(&inv, Rect::new(1, 1, 2, 2)).px[0]; assert!(px[0] < 0.01 && px[1] > 0.99 && px[2] > 0.99, "red inverted to cyan: {px:?}"); + // A recorded Quick Export writes to the current document path, but Batch owns + // the destination. Replaying it would fail for scratch documents with no save path. + let quick_out = join(&dir, "batch-with-quick-export"); + let r = s + .execute( + "file.automate.batch", + json!({"steps": [["image.adjustments.invert", {}], ["file.export.quickExport", {}]], "input": input, "output": quick_out, "format": "png"}), + ) + .unwrap(); + assert_eq!(r["files"].as_array().unwrap().len(), 2, "{r}"); + assert!(r["errors"].as_array().unwrap().is_empty(), "{r}"); + assert!(std::path::Path::new(&join(&quick_out, "a.png")).is_file()); assert!(s.execute("file.automate.batch", json!({"steps": [["no.such.command", {}]], "input": input, "output": out})).is_err()); }