mirror of
https://github.com/storytold/deckcraft.git
synced 2026-10-24 10:37:03 -06:00
Fix up #87: the web PNG/JPEG export path in SlideApp::export_as downloads every slide
Port web_image_files into main's export_as (keeping its DPI tags) and drop the PR's old dialogs.rs export branch, which main no longer has. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
8700a2da92
commit
a4ea5b66db
@@ -2605,22 +2605,6 @@ mod alt_text_tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// Images for the browser download: the current slide, or every slide (named `<name>1.png`, `<name>2.png`... like the native export) when `all`.
|
||||
fn web_image_files(doc: &deckcraft_model::Presentation, current: usize, all: bool, name: &str, ext: &str) -> Vec<(String, Vec<u8>)> {
|
||||
let slides: Vec<usize> = if all { (0..doc.slides.len()).collect() } else { vec![current] };
|
||||
let single = slides.len() == 1;
|
||||
slides
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(k, i)| {
|
||||
let img = deckcraft_render::render_slide(doc, i, &deckcraft_render::RenderOpts { scale: 2.0, ..Default::default() });
|
||||
let bytes = if ext == "png" { img.to_png() } else { img.to_jpeg(92) };
|
||||
let file = if single { format!("{name}.{ext}") } else { format!("{name}{}.{ext}", k + 1) };
|
||||
(file, bytes)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use deckcraft_model::text::{Action, Hyperlink, Run, TextBody};
|
||||
|
||||
@@ -470,10 +470,13 @@ impl SlideApp {
|
||||
let Some(doc) = self.session.active().map(|d| d.doc.clone()) else { return false };
|
||||
let bytes = match format {
|
||||
"png" | "jpeg" => {
|
||||
let scale = 2.0;
|
||||
let img = deckcraft_render::render_slide(&doc, slide, &deckcraft_render::RenderOpts { scale, ..Default::default() });
|
||||
let dpi = deckcraft_render::dpi_for_scale(scale);
|
||||
Ok(if format == "png" { img.to_png_at(dpi) } else { img.to_jpeg_at(92, Some(dpi)) })
|
||||
// Every slide for "all slides", one download each, named like the desktop export (#64).
|
||||
let name = self.session.active().map(|d| d.title()).unwrap_or_else(|| "Presentation".into());
|
||||
let mut any = false;
|
||||
for (file, bytes) in web_image_files(&doc, slide, all, &name, ext) {
|
||||
any = self.download(&file, Ok(bytes)) || any;
|
||||
}
|
||||
return any;
|
||||
}
|
||||
"pdf" => deckcraft_engine::cmd::file::pdf_bytes(&doc, &extra),
|
||||
other => deckcraft_engine::cmd::file::save_bytes(&doc, other),
|
||||
@@ -1292,6 +1295,25 @@ pub fn now_ms() -> f64 {
|
||||
}
|
||||
}
|
||||
|
||||
/// Images for the browser download: the current slide, or every slide (named `<name>1.png`,
|
||||
/// `<name>2.png`... like the native export) when `all`.
|
||||
fn web_image_files(doc: &deckcraft_model::Presentation, current: usize, all: bool, name: &str, ext: &str) -> Vec<(String, Vec<u8>)> {
|
||||
let slides: Vec<usize> = if all { (0..doc.slides.len()).collect() } else { vec![current] };
|
||||
let single = slides.len() == 1;
|
||||
let scale = 2.0;
|
||||
let dpi = deckcraft_render::dpi_for_scale(scale);
|
||||
slides
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(k, i)| {
|
||||
let img = deckcraft_render::render_slide(doc, i, &deckcraft_render::RenderOpts { scale, ..Default::default() });
|
||||
let bytes = if ext == "png" { img.to_png_at(dpi) } else { img.to_jpeg_at(92, Some(dpi)) };
|
||||
let file = if single { format!("{name}.{ext}") } else { format!("{name}{}.{ext}", k + 1) };
|
||||
(file, bytes)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
fn js_now() -> f64 {
|
||||
js_sys::Date::now()
|
||||
@@ -1324,6 +1346,23 @@ mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
/// The browser "PNG images (all slides)" export yields one image per slide, not just the selected one (#64).
|
||||
#[test]
|
||||
fn web_export_all_slides_gives_one_file_per_slide() {
|
||||
let mut doc = deckcraft_model::Presentation::default();
|
||||
if let Some(first) = doc.slides.first().cloned() {
|
||||
doc.slides.push(first.clone());
|
||||
doc.slides.push(first);
|
||||
}
|
||||
assert_eq!(doc.slides.len(), 3);
|
||||
let all = web_image_files(&doc, 1, true, "Deck", "png");
|
||||
let names: Vec<&str> = all.iter().map(|(n, _)| n.as_str()).collect();
|
||||
assert_eq!(names, ["Deck1.png", "Deck2.png", "Deck3.png"]);
|
||||
let one = web_image_files(&doc, 1, false, "Deck", "png");
|
||||
assert_eq!(one.len(), 1);
|
||||
assert_eq!(one[0].0, "Deck.png");
|
||||
}
|
||||
|
||||
fn title_text(app: &SlideApp) -> String {
|
||||
let d = app.session.active().unwrap();
|
||||
let sh = &d.doc.slides[0].shapes[0];
|
||||
|
||||
Reference in New Issue
Block a user