conversion_worker.rs (3998B)
1 use magick_rust::{MagickError, MagickWand}; 2 use std::path::PathBuf; 3 use std::result::Result; 4 use tracing::info; 5 use walkdir::WalkDir; 6 7 use relm4::{ComponentSender, Worker}; 8 9 #[derive(Debug)] 10 pub enum ConversionWorkerInputMsg { 11 ConvertFolder(PathBuf, PathBuf), 12 } 13 14 #[derive(Debug)] 15 pub enum ConversionWorkerMsg { 16 ConversionStarted(usize), 17 ProgressUpdate(f64), 18 ConversionComplete, 19 ConversionFailed(String), 20 } 21 22 pub struct ConversionWorker; 23 24 impl Worker for ConversionWorker { 25 type Init = (); 26 type Input = ConversionWorkerInputMsg; 27 type Output = ConversionWorkerMsg; 28 29 fn init(_init: Self::Init, _sender: ComponentSender<Self>) -> Self { 30 Self 31 } 32 33 fn update(&mut self, msg: ConversionWorkerInputMsg, sender: ComponentSender<Self>) { 34 match msg { 35 ConversionWorkerInputMsg::ConvertFolder(input_path, output_path) => { 36 // Walk directory, find all heic files, convert them to jpg and update progress 37 info!("Converting folder {:?}", input_path); 38 let result = self.convert_folder(input_path, output_path, &sender); 39 40 // Send the result of the conversion back 41 match result { 42 Ok(_) => sender 43 .output(ConversionWorkerMsg::ConversionComplete) 44 .unwrap(), 45 Err(e) => sender 46 .output(ConversionWorkerMsg::ConversionFailed(e.to_string())) 47 .unwrap(), 48 } 49 } 50 } 51 } 52 } 53 54 impl ConversionWorker { 55 fn convert_folder( 56 &self, 57 input_path: PathBuf, 58 output_path: PathBuf, 59 sender: &ComponentSender<Self>, 60 ) -> Result<(), MagickError> { 61 // Start the conversion 62 info!("Converting folder {:?} to {:?}", input_path, output_path); 63 64 // Use walkdir to find all heic files in the input directory 65 let heic_files: Vec<PathBuf> = WalkDir::new(input_path) 66 .follow_links(true) 67 .same_file_system(false) 68 .into_iter() 69 .filter_map(|entry| { 70 let entry = entry.ok()?; 71 let path = entry.path(); 72 let extension = path.extension(); 73 //info!("Found file {:?}", path); 74 if path.is_file() && extension.map_or(false, |ext| ext.eq_ignore_ascii_case("heic")) 75 { 76 Some(path.to_path_buf()) 77 } else { 78 None 79 } 80 }) 81 .collect(); 82 info!("Found {} heic files", heic_files.len()); 83 sender 84 .output(ConversionWorkerMsg::ConversionStarted(heic_files.len())) 85 .unwrap(); 86 87 // Convert each heic file to jpg 88 for (index, heic_file) in heic_files.iter().enumerate() { 89 info!("Converting file {:?}", heic_file); 90 let output_file = output_path 91 .join(heic_file.file_stem().unwrap()) 92 .with_extension("jpg"); 93 94 // Convert the file 95 self.convert_heic_to_jpg(heic_file.to_path_buf(), output_file)?; 96 97 // Update the progress 98 sender 99 .output(ConversionWorkerMsg::ProgressUpdate( 100 (index + 1) as f64 / heic_files.len() as f64, 101 )) 102 .unwrap(); 103 } 104 info!("Conversion complete"); 105 Ok(()) 106 } 107 108 fn convert_heic_to_jpg( 109 &self, 110 input_file: PathBuf, 111 output_file: PathBuf, 112 ) -> Result<(), MagickError> { 113 // Create a MagickWand 114 let mut wand = MagickWand::new(); 115 116 // Read the input file 117 info!("Reading file {:?}", input_file); 118 wand.read_image(input_file.to_str().unwrap())?; 119 120 // Convert the image to jpg 121 wand.set_image_format("jpg")?; 122 info!("Converting to jpg"); 123 wand.write_image(output_file.to_str().unwrap())?; 124 125 Ok(()) 126 } 127 }