Fix up merged PRs: GIF export goes through main's export path

The Export dialog's GIF choice runs through SlideApp::export_as (desktop and web download),
.gif is a writable output extension for convert/run, and the CLI help pages describe GIF output
and --export-params. A file.export `slides` range string ("1-3,5") works for GIF as for PDF.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Brandon Thomas
2026-10-14 14:54:35 -04:00
co-authored by Claude Opus 5.5
parent c354f02279
commit ed13dd6158
4 changed files with 12 additions and 6 deletions
+7 -4
View File
@@ -50,19 +50,22 @@ OUT-t0.250.png and so on. Prints each image's path, size, transition and time.
usage: "convert IN OUT",
summary: "save a presentation in the format OUT's extension names",
details: "Opens IN (.deckcraft or .pptx) and writes it to OUT, in the format OUT's extension names:
.deckcraft, .pptx, .pdf, .txt or .md for the outline, .png or .jpg for the first slide. Any other
extension is written as .deckcraft. Prints OUT.
.deckcraft, .pptx, .pdf, .txt or .md for the outline, .png or .jpg for the first slide, .gif for an
animated GIF with one frame per slide. Other extensions are refused. Prints OUT.
deckcraft-cli convert deck.deckcraft deck.pptx",
},
Subcommand {
name: "run",
usage: "run [--in FILE | --sample] [--cmd COMMAND[=PARAMS]]... [--save OUT] [--export OUT] [--print]",
usage: "run [--in FILE | --sample] [--cmd COMMAND[=PARAMS]]... [--save OUT] [--export OUT [--export-params JSON]] [--print]",
summary: "run commands on a presentation, then save or export it",
details: "Runs commands, in order, on one presentation: FILE with --in, the sample presentation with --sample,
else a new one with an empty title slide. Then --save writes the presentation: .deckcraft keeps
everything; .pptx, .pdf and .md (the outline) are written as convert writes them. --export writes the
current slide as .png or .jpg, or the presentation as .pdf or .pptx.
current slide as .png or .jpg, or the presentation as .pdf, .pptx or an animated .gif (one frame per
slide). --export-params passes file.export options as one JSON object, such as
'{\"width\": \"large\", \"secondsPerSlide\": 3, \"loop\": false, \"slides\": [0, 1, 2]}' for a GIF
(`deckcraft-cli describe file.export` lists them).
Each --cmd is one command: COMMAND is a command id, then `=`, then the command's parameters as one
JSON object. Quote it for the shell. A command that needs no parameters is just its id.
+1 -1
View File
@@ -21,7 +21,7 @@ fn convert_rejects_output_formats_it_cannot_write() {
let out = Command::new(env!("CARGO_BIN_EXE_deckcraft-cli")).args(["run", "--sample", "--export"]).arg(&input).output().unwrap();
assert!(out.status.success(), "{}", String::from_utf8_lossy(&out.stderr));
for name in ["out.odp", "out.gif", "out.svg", "out.outline", "out"] {
for name in ["out.odp", "out.bmp", "out.svg", "out.outline", "out"] {
let target = dir.join(name);
let out = cli(&[Path::new("convert"), &input, &target]);
assert!(!out.status.success(), "{name}: convert should fail");
+2 -1
View File
@@ -237,7 +237,8 @@ fn writable_format_for_path_rejects_formats_deckcraft_does_not_write() {
assert_eq!(f("a.pdf"), Some("pdf"));
assert_eq!(f("a.jpg"), Some("jpeg"));
assert_eq!(f("a.txt"), Some("outline"));
for path in ["a.odp", "a.gif", "a.svg", "a.outline", "a", "dir.v2/a"] {
assert_eq!(f("a.gif"), Some("gif"));
for path in ["a.odp", "a.bmp", "a.svg", "a.outline", "a", "dir.v2/a"] {
assert_eq!(f(path), None, "{path}");
}
}
+2
View File
@@ -506,6 +506,7 @@ impl SlideApp {
"pptx" => ("pptx", "pptx", false),
"outline" | "txt" => ("txt", "outline", false),
"deckcraft" => ("deckcraft", "deckcraft", false),
"gif" => ("gif", "gif", false),
other => {
self.set_status(format!("DeckCraft can't export “{other}”"));
return false;
@@ -535,6 +536,7 @@ impl SlideApp {
Ok(if format == "png" { img.to_png_at(dpi) } else { img.to_jpeg_at(92, Some(dpi)) })
}
"pdf" => deckcraft_engine::cmd::file::pdf_bytes(&doc, &extra),
"gif" => deckcraft_engine::cmd::file::gif_bytes(&doc, &extra),
other => deckcraft_engine::cmd::file::save_bytes(&doc, other),
};
self.download(&suggested, bytes)