Allow conversion and keeping dates #70

This commit is contained in:
Matteo Paonessa 2024-07-20 11:51:27 +02:00
parent 444faa3d9b
commit f76e8d8a31
4 changed files with 86 additions and 21 deletions

15
Cargo.lock generated
View File

@ -145,8 +145,9 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
[[package]] [[package]]
name = "caesiumclt" name = "caesiumclt"
version = "0.19.3" version = "0.20.0"
dependencies = [ dependencies = [
"filetime",
"human_bytes", "human_bytes",
"indicatif", "indicatif",
"infer", "infer",
@ -542,9 +543,9 @@ dependencies = [
[[package]] [[package]]
name = "infer" name = "infer"
version = "0.15.0" version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb33622da908807a06f9513c19b3c1ad50fab3e4137d82a78107d502075aa199" checksum = "bc150e5ce2330295b8616ce0e3f53250e53af31759a9dbedad1621ba29151847"
dependencies = [ dependencies = [
"cfb", "cfb",
] ]
@ -593,8 +594,8 @@ checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]] [[package]]
name = "libcaesium" name = "libcaesium"
version = "0.15.4" version = "0.16.1"
source = "git+https://github.com/Lymphatus/libcaesium?tag=0.15.4#bf5fcec976da5d2526c235e93cadd4ef4fb73581" source = "git+https://github.com/Lymphatus/libcaesium?rev=0.16.1#ef402d1a1dfe417907f2379cab88c2e3b245ac4c"
dependencies = [ dependencies = [
"bytes", "bytes",
"gifsicle", "gifsicle",
@ -678,9 +679,9 @@ dependencies = [
[[package]] [[package]]
name = "mozjpeg-sys" name = "mozjpeg-sys"
version = "1.1.1" version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74c4fe4006093b2948ccb37bb413b6b9da2d654a9a50419b5861b0f4e8ad4da9" checksum = "9cf2a48f2f79f47fcce75d125d112e113a93f4a6f3cd8cc5b4cd6e16589d050f"
dependencies = [ dependencies = [
"cc", "cc",
"dunce", "dunce",

View File

@ -1,6 +1,6 @@
[package] [package]
name = "caesiumclt" name = "caesiumclt"
version = "0.19.3" version = "0.20.0"
authors = ["Matteo Paonessa <matteo.paonessa@gmail.com>"] authors = ["Matteo Paonessa <matteo.paonessa@gmail.com>"]
edition = "2021" edition = "2021"
@ -10,8 +10,9 @@ structopt = "0.3"
indicatif = "0.17" indicatif = "0.17"
walkdir = "2.5" walkdir = "2.5"
num_cpus = "1.16" num_cpus = "1.16"
infer = "0.15" infer = "0.16"
rayon = "1.10" rayon = "1.10"
rand = "0.8" rand = "0.8"
human_bytes = { version = "0.4", default-features = false } human_bytes = { version = "0.4", default-features = false }
libcaesium = { git = "https://github.com/Lymphatus/libcaesium", tag = "0.15.4" } filetime = "0.2"
libcaesium = { git = "https://github.com/Lymphatus/libcaesium", rev = "0.16.1" }

View File

@ -1,7 +1,8 @@
use std::fs; use std::fs;
use std::path::Path; use std::path::Path;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use caesium::SupportedFileTypes;
use filetime::{FileTime, set_file_times};
use human_bytes::human_bytes; use human_bytes::human_bytes;
use indicatif::ProgressBar; use indicatif::ProgressBar;
use indicatif::ProgressDrawTarget; use indicatif::ProgressDrawTarget;
@ -27,12 +28,21 @@ struct CompressionResult {
pub result: bool, pub result: bool,
} }
struct OutputFormat {
pub file_type: SupportedFileTypes,
pub extension: String
}
fn main() { fn main() {
let opt = options::get_opts(); let opt = options::get_opts();
let mut verbose = opt.verbose; let mut verbose = opt.verbose;
let args = opt.files; let args = opt.files;
let dry_run = opt.dry_run; let dry_run = opt.dry_run;
let output_dir = opt.output; 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 { if opt.quiet {
verbose = 0; verbose = 0;
} }
@ -86,12 +96,13 @@ fn main() {
let results = Arc::new(Mutex::new(Vec::new())); let results = Arc::new(Mutex::new(Vec::new()));
files.par_iter().for_each(|input_file| { files.par_iter().for_each(|input_file| {
let input_size = match fs::metadata(input_file) { let input_file_metadata = fs::metadata(input_file);
Ok(s) => s.len(), 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) => { Err(e) => {
let error_message = format!("Cannot get file size for {}, Error: {}", input_file.display(), e); let error_message = format!("Cannot get file size for {}, Error: {}", input_file.display(), e);
log(error_message.as_str(), 202, Warning, verbose); log(error_message.as_str(), 202, Warning, verbose);
0 (0, FileTime::now(), FileTime::now())
} }
}; };
@ -130,7 +141,11 @@ fn main() {
.map(char::from) .map(char::from)
.collect(); .collect();
let random_suffixed_name = format!("{}.{}", filename_str, random_suffix); 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_path = output_dir.clone().join(random_suffixed_name);
let output_full_dir = output_full_path.parent().unwrap_or_else(|| Path::new("/")); let output_full_dir = output_full_path.parent().unwrap_or_else(|| Path::new("/"));
compression_result.output_path = final_output_full_path.display().to_string(); compression_result.output_path = final_output_full_path.display().to_string();
@ -156,7 +171,13 @@ fn main() {
Some(ofp) => ofp Some(ofp) => ofp
}; };
if !dry_run { 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(_) => { Ok(_) => {
compression_result.result = true; compression_result.result = true;
let output_metadata = fs::metadata(output_full_path.clone()); let output_metadata = fs::metadata(output_full_path.clone());
@ -183,7 +204,7 @@ fn main() {
}; };
final_output_size = existing_file_size; final_output_size = existing_file_size;
} else { } else {
match fs::rename(output_full_path, final_output_full_path) { match fs::rename(output_full_path, final_output_full_path.clone()) {
Ok(_) => {} Ok(_) => {}
Err(e) => { Err(e) => {
compression_result.error = format!("Cannot rename existing file. Error: {}.", e); compression_result.error = format!("Cannot rename existing file. Error: {}.", e);
@ -192,7 +213,7 @@ fn main() {
}; };
} }
} else { } else {
match fs::rename(output_full_path, final_output_full_path) { match fs::rename(output_full_path, final_output_full_path.clone()) {
Ok(_) => {} Ok(_) => {}
Err(e) => { Err(e) => {
compression_result.error = format!("Cannot rename existing file. Error: {}.", e); compression_result.error = format!("Cannot rename existing file. Error: {}.", e);
@ -201,6 +222,16 @@ fn main() {
}; };
} }
compression_result.compressed_size = final_output_size; 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); results.lock().unwrap().push(compression_result);
} }
Err(e) => { Err(e) => {
@ -273,3 +304,28 @@ fn setup_progress_bar(len: u64, verbose: u8) -> ProgressBar {
progress_bar 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()
},
}
}

View File

@ -1,5 +1,4 @@
use std::path::PathBuf; use std::path::PathBuf;
use structopt::clap::arg_enum; use structopt::clap::arg_enum;
use structopt::StructOpt; use structopt::StructOpt;
@ -16,7 +15,7 @@ arg_enum! {
} }
#[derive(StructOpt, Debug)] #[derive(StructOpt)]
#[structopt(name = "", about = "CaesiumCLT - Command Line Tools for image compression")] #[structopt(name = "", about = "CaesiumCLT - Command Line Tools for image compression")]
pub struct Opt { pub struct Opt {
/// sets output file quality between [0-100], 0 for optimization /// sets output file quality between [0-100], 0 for optimization
@ -52,7 +51,7 @@ pub struct Opt {
pub overwrite: OverwritePolicy, pub overwrite: OverwritePolicy,
/// do not compress files but just show output paths /// do not compress files but just show output paths
#[structopt(short = "d", long)] #[structopt(long = "dry-run", short = "d", long)]
pub dry_run: bool, pub dry_run: bool,
/// suppress all output /// suppress all output
@ -71,6 +70,14 @@ pub struct Opt {
#[structopt(long, default_value = "1")] #[structopt(long, default_value = "1")]
pub verbose: u8, 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 /// Files to process
#[structopt(name = "FILE", parse(from_os_str))] #[structopt(name = "FILE", parse(from_os_str))]
pub files: Vec<PathBuf>, pub files: Vec<PathBuf>,