use std::process::Command;
use crate::converters::scad::which_tool;
use crate::{Error, Job, Result, extension_of};
pub fn heic_to_image(job: &Job) -> Result<()> {
if which_tool("heif-convert") {
return run_status(
Command::new("heif-convert").arg(job.input).arg(job.output),
"heif-convert",
);
}
if which_tool("magick") {
return run_status(
Command::new("magick").arg(job.input).arg(job.output),
"magick",
);
}
if which_tool("ffmpeg") {
return run_status(
Command::new("ffmpeg")
.args(["-y", "-hide_banner", "-loglevel", "error", "-i"])
.arg(job.input)
.arg(job.output),
"ffmpeg",
);
}
if cfg!(target_os = "macos") && which_tool("sips") {
let to = extension_of(job.output).unwrap_or_default();
let format = match to.as_str() {
"jpeg" | "jpg" => "jpeg",
"png" => "png",
"tif" | "tiff" => "tiff",
_ => "png",
};
return run_status(
Command::new("sips")
.args(["-s", "format", format])
.arg(job.input)
.args(["--out"])
.arg(job.output),
"sips",
);
}
Err(Error::MissingTool {
from: "heic".to_string(),
to: extension_of(job.output).unwrap_or_default(),
tool: "heif-convert",
})
}
pub fn pdf_to_png(job: &Job) -> Result<()> {
if which_tool("pdftoppm") {
let staging = tempfile::tempdir()?;
let prefix = staging.path().join("page");
let status = Command::new("pdftoppm")
.args(["-png", "-f", "1", "-l", "1", "-singlefile"])
.arg(job.input)
.arg(&prefix)
.status()
.map_err(|e| Error::ToolFailed {
tool: "pdftoppm",
message: e.to_string(),
})?;
if !status.success() {
return Err(Error::ToolFailed {
tool: "pdftoppm",
message: format!("pdftoppm exited with status {status}"),
});
}
let produced = staging.path().join("page.png");
std::fs::rename(&produced, job.output)
.or_else(|_| std::fs::copy(&produced, job.output).map(|_| ()))?;
return Ok(());
}
if which_tool("magick") {
return run_status(
Command::new("magick")
.arg("-density")
.arg("150")
.arg(format!("{}[0]", job.input.display()))
.arg(job.output),
"magick",
);
}
Err(Error::MissingTool {
from: "pdf".to_string(),
to: "png".to_string(),
tool: "pdftoppm",
})
}
fn run_status(cmd: &mut Command, tool: &'static str) -> Result<()> {
let status = cmd.status().map_err(|e| Error::ToolFailed {
tool,
message: e.to_string(),
})?;
if !status.success() {
return Err(Error::ToolFailed {
tool,
message: format!("{tool} exited with status {status}"),
});
}
Ok(())
}