Add ImageLoader and file discovery modules

ImageLoader: load image info (dimensions, format, file size) and pixels.
Discovery: find image files by extension, flat or recursive, single file or directory.
All 9 tests passing.
This commit is contained in:
2026-03-06 01:50:46 +02:00
parent 5c93dbf829
commit c445f71163
5 changed files with 253 additions and 0 deletions

View File

@@ -0,0 +1,57 @@
use std::path::{Path, PathBuf};
use walkdir::WalkDir;
const IMAGE_EXTENSIONS: &[&str] = &[
"jpg", "jpeg", "png", "webp", "avif", "gif", "tiff", "tif", "bmp", "heic", "heif", "jxl",
"svg", "ico",
];
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()) {
if 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)
}