use anyhow::Result;
use ctrlc;
use indicatif::{ProgressBar, ProgressStyle};
use log::debug;
use std::collections::BTreeMap;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command as StdCommand;
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
};
use std::time::SystemTime;
pub fn clut_all_images(
clut_path: &PathBuf,
images: &BTreeMap<u32, PathBuf>,
output_dir: &Path,
) -> Result<()> {
let pb = ProgressBar::new(images.len() as u64);
pb.set_style(ProgressStyle::default_bar().template(
"{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} ({eta_precise})",
)?);
debug!("Starting to process images...");
let start_time = SystemTime::now();
let is_terminated = Arc::new(AtomicBool::new(false));
let is_terminated_clone = Arc::clone(&is_terminated);
ctrlc::set_handler(move || {
is_terminated_clone.store(true, Ordering::SeqCst);
})
.expect("Error setting Ctrl+C handler");
for (index, input_image) in images.values().enumerate() {
if is_terminated.load(Ordering::SeqCst) {
debug!("Process interrupted by user. Exiting...");
break;
}
debug!("Processing image {}: {:?}", index + 1, input_image);
clut_image(input_image, clut_path, output_dir, &is_terminated);
pb.inc(1);
debug!("Image {} processed successfully.", index + 1);
}
pb.finish_with_message("Processing complete!");
debug!(
"All images processed successfully in {:?}.",
start_time.elapsed()?
);
Ok(())
}
fn clut_image(
input_image: &Path,
clut_path: &Path,
output_dir: &Path,
is_terminated: &Arc<AtomicBool>,
) {
let file_name = input_image.file_name().unwrap();
let output_path = output_dir.join(file_name);
if is_terminated.load(Ordering::SeqCst) {
debug!(
"Skipping {} due to termination request.",
file_name.to_string_lossy()
);
return;
}
let status = StdCommand::new("convert")
.arg(clut_path)
.arg(input_image)
.arg("-clut")
.arg(&output_path)
.status()
.expect("Failed to run convert command");
if !status.success() {
eprintln!("Failed to apply CLUT: {:?}", input_image);
}
}