diff --git a/src/app/mod.rs b/src/app/mod.rs index d42be8e..8ef9843 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -69,14 +69,11 @@ impl State { let entry = self.images.entry(path.clone()).or_default(); if matches!(entry, MaybeImage::Unloaded) { - let columns = self.columns; + let size = 1000 / self.columns as u32; let (task, handle) = Task::perform( async move { - utils::load_image(&path) - .map(|img| { - let size = 1000 / columns as u32; - (path, handle_from_image(img.thumbnail(size, size))) - }) + utils::load_thumbnail(&path, size) + .map(|img| (path, handle_from_image(img))) .map_err(Arc::new) }, Message::ImageLoaded, diff --git a/src/utils.rs b/src/utils.rs index 9baabee..3eb1795 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,9 +1,27 @@ -use std::path::Path; +use std::{ffi::OsStr, path::Path}; -use image::{DynamicImage, ImageReader, ImageResult}; +use image::{DynamicImage, ImageDecoder, ImageReader, ImageResult}; -pub fn load_image(path: impl AsRef) -> ImageResult { - Ok(DynamicImage::from_decoder( - ImageReader::open(path)?.into_decoder()?, - )?) +pub fn load_thumbnail(path: impl AsRef, max_size: u32) -> ImageResult { + let mut decoder = ImageReader::open(&path)? + .with_guessed_format()? + .into_decoder()?; + + let oreintation = decoder.orientation()?; + + let mut decoded_image = DynamicImage::from_decoder(decoder)?.thumbnail(max_size, max_size); + + // the condition is a workaround to not rotate JXL images twice; + // since they are already rotated by the decoder + // (while jpegs for instance aren't) + if !path + .as_ref() + .extension() + .map(OsStr::to_string_lossy) + .is_some_and(|s| s == "jxl") + { + decoded_image.apply_orientation(oreintation); + } + + Ok(decoded_image) }