From f76e8d8a3139d49fc08cf978851cc0978ad68443 Mon Sep 17 00:00:00 2001 From: Matteo Paonessa Date: Sat, 20 Jul 2024 11:51:27 +0200 Subject: [PATCH] Allow conversion and keeping dates #70 --- Cargo.lock | 15 ++++++----- Cargo.toml | 7 ++--- src/main.rs | 72 ++++++++++++++++++++++++++++++++++++++++++++------ src/options.rs | 13 ++++++--- 4 files changed, 86 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7c8e543..a9bb17a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -145,8 +145,9 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "caesiumclt" -version = "0.19.3" +version = "0.20.0" dependencies = [ + "filetime", "human_bytes", "indicatif", "infer", @@ -542,9 +543,9 @@ dependencies = [ [[package]] name = "infer" -version = "0.15.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb33622da908807a06f9513c19b3c1ad50fab3e4137d82a78107d502075aa199" +checksum = "bc150e5ce2330295b8616ce0e3f53250e53af31759a9dbedad1621ba29151847" dependencies = [ "cfb", ] @@ -593,8 +594,8 @@ checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libcaesium" -version = "0.15.4" -source = "git+https://github.com/Lymphatus/libcaesium?tag=0.15.4#bf5fcec976da5d2526c235e93cadd4ef4fb73581" +version = "0.16.1" +source = "git+https://github.com/Lymphatus/libcaesium?rev=0.16.1#ef402d1a1dfe417907f2379cab88c2e3b245ac4c" dependencies = [ "bytes", "gifsicle", @@ -678,9 +679,9 @@ dependencies = [ [[package]] name = "mozjpeg-sys" -version = "1.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74c4fe4006093b2948ccb37bb413b6b9da2d654a9a50419b5861b0f4e8ad4da9" +checksum = "9cf2a48f2f79f47fcce75d125d112e113a93f4a6f3cd8cc5b4cd6e16589d050f" dependencies = [ "cc", "dunce", diff --git a/Cargo.toml b/Cargo.toml index f4c1f8f..0af2280 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "caesiumclt" -version = "0.19.3" +version = "0.20.0" authors = ["Matteo Paonessa "] edition = "2021" @@ -10,8 +10,9 @@ structopt = "0.3" indicatif = "0.17" walkdir = "2.5" num_cpus = "1.16" -infer = "0.15" +infer = "0.16" rayon = "1.10" rand = "0.8" human_bytes = { version = "0.4", default-features = false } -libcaesium = { git = "https://github.com/Lymphatus/libcaesium", tag = "0.15.4" } \ No newline at end of file +filetime = "0.2" +libcaesium = { git = "https://github.com/Lymphatus/libcaesium", rev = "0.16.1" } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 4db2b43..2276ce7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,8 @@ use std::fs; use std::path::Path; use std::sync::{Arc, Mutex}; - +use caesium::SupportedFileTypes; +use filetime::{FileTime, set_file_times}; use human_bytes::human_bytes; use indicatif::ProgressBar; use indicatif::ProgressDrawTarget; @@ -27,12 +28,21 @@ struct CompressionResult { pub result: bool, } +struct OutputFormat { + pub file_type: SupportedFileTypes, + pub extension: String +} + fn main() { let opt = options::get_opts(); let mut verbose = opt.verbose; let args = opt.files; let dry_run = opt.dry_run; let output_dir = opt.output; + let output_format = map_output_format(opt.output_format); + let convert = output_format.file_type != SupportedFileTypes::Unkn; + let keep_dates = opt.keep_dates; + if opt.quiet { verbose = 0; } @@ -86,12 +96,13 @@ fn main() { let results = Arc::new(Mutex::new(Vec::new())); files.par_iter().for_each(|input_file| { - let input_size = match fs::metadata(input_file) { - Ok(s) => s.len(), + let input_file_metadata = fs::metadata(input_file); + let (input_size, input_mtime, input_atime) = match input_file_metadata { + Ok(s) => (s.len(), FileTime::from_last_modification_time(&s), FileTime::from_last_access_time(&s)), Err(e) => { let error_message = format!("Cannot get file size for {}, Error: {}", input_file.display(), e); log(error_message.as_str(), 202, Warning, verbose); - 0 + (0, FileTime::now(), FileTime::now()) } }; @@ -130,7 +141,11 @@ fn main() { .map(char::from) .collect(); let random_suffixed_name = format!("{}.{}", filename_str, random_suffix); - let final_output_full_path = output_dir.clone().join(filename); + let mut final_output_full_path = output_dir.clone().join(filename); + if convert { + final_output_full_path.set_extension(output_format.extension.clone()); + } + let output_full_path = output_dir.clone().join(random_suffixed_name); let output_full_dir = output_full_path.parent().unwrap_or_else(|| Path::new("/")); compression_result.output_path = final_output_full_path.display().to_string(); @@ -156,7 +171,13 @@ fn main() { Some(ofp) => ofp }; if !dry_run { - match caesium::compress(input_full_path.to_string(), output_full_path_str.to_string(), &compression_parameters) { + let result = if convert { + caesium::convert(input_full_path.to_string(), output_full_path_str.to_string(), &compression_parameters, output_format.file_type) + } else { + caesium::compress(input_full_path.to_string(), output_full_path_str.to_string(), &compression_parameters) + }; + + match result { Ok(_) => { compression_result.result = true; let output_metadata = fs::metadata(output_full_path.clone()); @@ -183,7 +204,7 @@ fn main() { }; final_output_size = existing_file_size; } else { - match fs::rename(output_full_path, final_output_full_path) { + match fs::rename(output_full_path, final_output_full_path.clone()) { Ok(_) => {} Err(e) => { compression_result.error = format!("Cannot rename existing file. Error: {}.", e); @@ -192,7 +213,7 @@ fn main() { }; } } else { - match fs::rename(output_full_path, final_output_full_path) { + match fs::rename(output_full_path, final_output_full_path.clone()) { Ok(_) => {} Err(e) => { compression_result.error = format!("Cannot rename existing file. Error: {}.", e); @@ -201,6 +222,16 @@ fn main() { }; } compression_result.compressed_size = final_output_size; + if compression_result.result && keep_dates { + + + match set_file_times(final_output_full_path, input_atime, input_mtime) { + Ok(_) => {} + Err(_) => { + compression_result.error = "Cannot set original file dates.".into(); + } + } + } results.lock().unwrap().push(compression_result); } Err(e) => { @@ -273,3 +304,28 @@ fn setup_progress_bar(len: u64, verbose: u8) -> ProgressBar { progress_bar } + +fn map_output_format(format: String) -> OutputFormat { + match format.to_lowercase().as_str() { + "jpg|jpeg" => OutputFormat { + file_type: SupportedFileTypes::Jpeg, + extension: format + }, + "png" => OutputFormat { + file_type: SupportedFileTypes::Png, + extension: format + }, + "webp" => OutputFormat { + file_type: SupportedFileTypes::WebP, + extension: format + }, + "tiff|tif" => OutputFormat { + file_type: SupportedFileTypes::Tiff, + extension: format + }, + _ =>OutputFormat { + file_type: SupportedFileTypes::Unkn, + extension: "".to_string() + }, + } +} diff --git a/src/options.rs b/src/options.rs index d3c29ce..a607fcd 100644 --- a/src/options.rs +++ b/src/options.rs @@ -1,5 +1,4 @@ use std::path::PathBuf; - use structopt::clap::arg_enum; use structopt::StructOpt; @@ -16,7 +15,7 @@ arg_enum! { } -#[derive(StructOpt, Debug)] +#[derive(StructOpt)] #[structopt(name = "", about = "CaesiumCLT - Command Line Tools for image compression")] pub struct Opt { /// sets output file quality between [0-100], 0 for optimization @@ -52,7 +51,7 @@ pub struct Opt { pub overwrite: OverwritePolicy, /// do not compress files but just show output paths - #[structopt(short = "d", long)] + #[structopt(long = "dry-run", short = "d", long)] pub dry_run: bool, /// suppress all output @@ -71,6 +70,14 @@ pub struct Opt { #[structopt(long, default_value = "1")] pub verbose: u8, + /// convert the image to the selected format (jpg, png, webp, tiff) + #[structopt(long = "output-format", default_value = "none")] + pub output_format: String, + + /// keep original file date information + #[structopt(long = "keep-dates")] + pub keep_dates: bool, + /// Files to process #[structopt(name = "FILE", parse(from_os_str))] pub files: Vec,