Critical: undo toast now trashes only batch output files (not entire dir), JPEG scanline write errors propagated, selective metadata write result returned. High: zero-dimension guards in ResizeConfig/fit_within, negative aspect ratio rejection, FM integration toggle infinite recursion guard, saturating counter arithmetic in executor. Medium: PNG compression level passed to oxipng, pct mode updates job_config, external file loading updates step indicator, CLI undo removes history entries, watch config write failures reported, fast-copy path reads image dimensions for rename templates, discovery excludes unprocessable formats (heic/svg/ico/jxl), CLI warns on invalid algorithm/overwrite values, resolve_collision trailing dot fix, generation guards on all preview threads to cancel stale results, default DPI aligned to 0, watermark text width uses char count not byte length. Low: binary path escaped in Nautilus extension, file dialog filter aligned with discovery, reset_wizard clears preset_mode and output_dir.
57 lines
1.4 KiB
Rust
57 lines
1.4 KiB
Rust
use std::path::{Path, PathBuf};
|
|
|
|
use walkdir::WalkDir;
|
|
|
|
const IMAGE_EXTENSIONS: &[&str] = &[
|
|
"jpg", "jpeg", "png", "webp", "avif", "gif", "tiff", "tif", "bmp",
|
|
];
|
|
|
|
fn is_image_extension(ext: &str) -> bool {
|
|
IMAGE_EXTENSIONS.contains(&ext.to_lowercase().as_str())
|
|
}
|
|
|
|
pub fn discover_images(path: &Path, recursive: bool) -> Vec<PathBuf> {
|
|
if path.is_file() {
|
|
if let Some(ext) = path.extension().and_then(|e| e.to_str())
|
|
&& is_image_extension(ext)
|
|
{
|
|
return vec![path.to_path_buf()];
|
|
}
|
|
return Vec::new();
|
|
}
|
|
|
|
if !path.is_dir() {
|
|
return Vec::new();
|
|
}
|
|
|
|
let max_depth = if recursive { usize::MAX } else { 1 };
|
|
|
|
WalkDir::new(path)
|
|
.max_depth(max_depth)
|
|
.into_iter()
|
|
.filter_map(|entry| entry.ok())
|
|
.filter(|entry| entry.file_type().is_file())
|
|
.filter(|entry| {
|
|
entry
|
|
.path()
|
|
.extension()
|
|
.and_then(|ext| ext.to_str())
|
|
.is_some_and(is_image_extension)
|
|
})
|
|
.map(|entry| entry.into_path())
|
|
.collect()
|
|
}
|
|
|
|
pub fn has_subdirectories(path: &Path) -> bool {
|
|
if !path.is_dir() {
|
|
return false;
|
|
}
|
|
std::fs::read_dir(path)
|
|
.map(|entries| {
|
|
entries
|
|
.filter_map(|e| e.ok())
|
|
.any(|e| e.file_type().is_ok_and(|ft| ft.is_dir()))
|
|
})
|
|
.unwrap_or(false)
|
|
}
|