feat: parallel loading

This commit is contained in:
electria 2026-08-09 15:10:16 -07:00
commit e179b824c8
Signed by: electria
SSH key fingerprint: SHA256:8LlB3ucPbBHqozqkhsNbaV5oG3SlzzqUj8FZDL6IPQs
3 changed files with 45 additions and 3 deletions

View file

@ -4,6 +4,7 @@ use std::{
env, env,
path::{Path, PathBuf}, path::{Path, PathBuf},
process, process,
sync::Arc,
}; };
use iced::{ use iced::{
@ -11,16 +12,23 @@ use iced::{
keyboard, theme, widget, window, keyboard, theme, widget, window,
}; };
use ignore::{WalkBuilder, types::TypesBuilder}; use ignore::{WalkBuilder, types::TypesBuilder};
use image::ImageError;
use rayon::iter::{ParallelBridge, ParallelIterator}; use rayon::iter::{ParallelBridge, ParallelIterator};
use rfd::AsyncFileDialog; use rfd::AsyncFileDialog;
use crate::{SUPPORTED_TYPES, app::maybe_image::MaybeImage}; use crate::{
SUPPORTED_TYPES,
app::maybe_image::{MaybeImage, handle_from_image},
utils,
};
mod maybe_image; mod maybe_image;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
enum Message { enum Message {
LoadImage(PathBuf), LoadImage(PathBuf),
ImageLoaded(Result<(PathBuf, widget::image::Handle), Arc<ImageError>>),
UnloadImage(PathBuf), UnloadImage(PathBuf),
OpenImage(PathBuf), OpenImage(PathBuf),
@ -58,10 +66,34 @@ impl State {
fn update(&mut self, message: Message) -> Task<Message> { fn update(&mut self, message: Message) -> Task<Message> {
match message { match message {
Message::LoadImage(path) => { Message::LoadImage(path) => {
self.images.entry(path.clone()).and_modify(|e| { let path_clone = path.clone();
*e = MaybeImage::Loaded(widget::image::Handle::from_path(path))
let (task, handle) = Task::perform(
async {
utils::load_image(&path)
.map(|img| (path, handle_from_image(img)))
.map_err(Arc::new)
},
Message::ImageLoaded,
)
.abortable();
self.images.entry(path_clone).and_modify(|e| {
*e = MaybeImage::Loading(handle);
}); });
return task;
} }
Message::ImageLoaded(result) => {
self.error = result.as_ref().err().map(|e| e.to_string());
if let Ok((path, handle)) = result {
self.images
.entry(path)
.and_modify(|e| *e = MaybeImage::Loaded(handle));
}
}
Message::UnloadImage(path) => { Message::UnloadImage(path) => {
self.images.entry(path).and_modify(MaybeImage::unload); self.images.entry(path).and_modify(MaybeImage::unload);
} }

View file

@ -1,4 +1,5 @@
mod app; mod app;
mod utils;
const SUPPORTED_TYPES: &[&str; 20] = &[ const SUPPORTED_TYPES: &[&str; 20] = &[
"*.png", "*.PNG", "*.jpg", "*.JPG", "*.jpeg", "*.JPEG", "*.avif", "*.jxl", "*.bmp", "*.exr", "*.png", "*.PNG", "*.jpg", "*.JPG", "*.jpeg", "*.JPEG", "*.avif", "*.jxl", "*.bmp", "*.exr",

9
src/utils.rs Normal file
View file

@ -0,0 +1,9 @@
use std::path::Path;
use image::{DynamicImage, ImageReader, ImageResult};
pub fn load_image(path: impl AsRef<Path>) -> ImageResult<DynamicImage> {
Ok(DynamicImage::from_decoder(
ImageReader::open(path)?.into_decoder()?,
)?)
}