mirror of
https://github.com/storytold/deckcraft.git
synced 2026-10-24 10:37:03 -06:00
Merge PR #444 from MarekSpodBiedry: CLI: render-transition refuses --t values that would share one file name (#423)
# Conflicts: # apps/deckcraft-cli/src/main.rs
This commit is contained in:
@@ -351,6 +351,7 @@ fn render_transition(args: &[String]) -> Result<(), String> {
|
||||
if ts.is_empty() {
|
||||
return Err("render-transition needs --t".into());
|
||||
}
|
||||
let paths = frame_paths(&out, &ts)?;
|
||||
let mut s = Session::new();
|
||||
open(&mut s, Some(&input), false)?;
|
||||
let st = s.doc().map_err(|e| e.to_string())?;
|
||||
@@ -368,27 +369,38 @@ fn render_transition(args: &[String]) -> Result<(), String> {
|
||||
(prev.map(|p| render::render_slide(doc, p, &opts)), render::render_slide(doc, i, &opts), parts)
|
||||
});
|
||||
let aspect = sw / doc.slide_size.height.max(1.0);
|
||||
for t in &ts {
|
||||
for (t, path) in ts.iter().zip(&paths) {
|
||||
let img = match &cached {
|
||||
Some((old, new, parts)) => {
|
||||
render::composite_transition(old.as_ref(), new, parts.as_ref(), &render::transition_frame(&tr.kind, &tr.option, *t, aspect))
|
||||
}
|
||||
None => render::render_transition(doc, i, *t, &opts),
|
||||
};
|
||||
let path = if ts.len() == 1 {
|
||||
out.clone()
|
||||
} else {
|
||||
let p = std::path::Path::new(&out);
|
||||
let stem = p.file_stem().and_then(|x| x.to_str()).unwrap_or("frame");
|
||||
let name = format!("{stem}-t{t:.3}.png");
|
||||
p.with_file_name(name).to_string_lossy().into_owned()
|
||||
};
|
||||
std::fs::write(&path, img.to_png_at(render::dpi_for_scale(opts.scale))).map_err(|e| format!("{path}: {e}"))?;
|
||||
std::fs::write(path, img.to_png_at(render::dpi_for_scale(opts.scale))).map_err(|e| format!("{path}: {e}"))?;
|
||||
outln!("{path} ({}×{}) {} {} t={t}", img.width, img.height, tr.kind, tr.option);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Output path of each frame. A single frame goes to OUT; several get `-t<value>` (three decimals)
|
||||
/// before the extension. Values that round to the same name would overwrite each other, so that is an error.
|
||||
fn frame_paths(out: &str, ts: &[f64]) -> Result<Vec<String>, String> {
|
||||
if ts.len() == 1 {
|
||||
return Ok(vec![out.to_string()]);
|
||||
}
|
||||
let p = std::path::Path::new(out);
|
||||
let stem = p.file_stem().and_then(|x| x.to_str()).unwrap_or("frame");
|
||||
let mut paths: Vec<String> = Vec::with_capacity(ts.len());
|
||||
for t in ts {
|
||||
let path = p.with_file_name(format!("{stem}-t{t:.3}.png")).to_string_lossy().into_owned();
|
||||
if paths.contains(&path) {
|
||||
return Err(format!("--t values round to the same three decimals: more than one frame would be written to {path}"));
|
||||
}
|
||||
paths.push(path);
|
||||
}
|
||||
Ok(paths)
|
||||
}
|
||||
|
||||
fn convert(args: &[String]) -> Result<(), String> {
|
||||
if args.first().is_some_and(|a| is_help(a)) {
|
||||
outln!("{USAGE}");
|
||||
@@ -591,3 +603,25 @@ mod slide_index_tests {
|
||||
assert!(missing_slide(1, 1).contains("index 0"));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod frame_path_tests {
|
||||
use super::frame_paths;
|
||||
|
||||
#[test]
|
||||
fn single_frame_uses_out_as_is() {
|
||||
assert_eq!(frame_paths("a/b.png", &[0.5]), Ok(vec!["a/b.png".to_string()]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn frames_get_distinct_names() {
|
||||
let paths = frame_paths("f.png", &[0.0, 0.25, 1.0]).unwrap_or_default();
|
||||
assert_eq!(paths, ["f-t0.000.png", "f-t0.250.png", "f-t1.000.png"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn values_rounding_to_one_name_are_rejected() {
|
||||
assert!(frame_paths("f.png", &[0.1001, 0.1002]).is_err());
|
||||
assert!(frame_paths("f.png", &[0.5, 0.5]).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user