From dfe49fc1c6929759faede80f869ace24c0418cdb Mon Sep 17 00:00:00 2001 From: Varphone Wong Date: Fri, 1 Mar 2024 14:35:14 +0800 Subject: [PATCH] Apply size hint to `ImageCrateLoader::load` --- crates/egui_extras/src/image.rs | 54 +++++++++++++++++-- .../egui_extras/src/loaders/image_loader.rs | 5 +- 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/crates/egui_extras/src/image.rs b/crates/egui_extras/src/image.rs index 46d9df170..d28ce3611 100644 --- a/crates/egui_extras/src/image.rs +++ b/crates/egui_extras/src/image.rs @@ -1,9 +1,6 @@ #![allow(deprecated)] -use egui::{mutex::Mutex, TextureOptions}; - -#[cfg(feature = "svg")] -use egui::SizeHint; +use egui::{mutex::Mutex, SizeHint, TextureOptions}; /// An image to be shown in egui. /// @@ -220,6 +217,55 @@ pub fn load_image_bytes(image_bytes: &[u8]) -> Result [usize; 2] { + match hint { + SizeHint::Size(w, h) => [w as usize, h as usize], + SizeHint::Height(h) => [size[0] * h as usize / size[1], h as usize], + SizeHint::Width(w) => [w as usize, size[1] * w as usize / size[0]], + SizeHint::Scale(scale) => { + let scale = scale.into_inner(); + [ + (size[0] as f32 * scale) as usize, + (size[1] as f32 * scale) as usize, + ] + } + } +} + +/// Load a (non-svg) image and resize it to the given size hint. +/// +/// Requires the "image" feature. You must also opt-in to the image formats you need +/// with e.g. `image = { version = "0.24", features = ["jpeg", "png"] }`. +/// +/// # Errors +/// On invalid image or unsupported image format. +#[cfg(feature = "image")] +pub fn load_image_bytes_for_size( + image_bytes: &[u8], + hint: SizeHint, +) -> Result { + crate::profile_function!(); + let image = image::load_from_memory(image_bytes).map_err(|err| err.to_string())?; + let src_size = [image.width() as _, image.height() as _]; + let dst_size = calculate_size_for_hint(src_size, hint); + let (image, size) = if src_size != dst_size { + let image = image.resize_exact( + dst_size[0] as u32, + dst_size[1] as u32, + image::imageops::FilterType::Lanczos3, + ); + (image, dst_size) + } else { + (image, src_size) + }; + let image_buffer = image.to_rgba8(); + let pixels = image_buffer.as_flat_samples(); + Ok(egui::ColorImage::from_rgba_unmultiplied( + size, + pixels.as_slice(), + )) +} + /// Load an SVG and rasterize it into an egui image. /// /// Requires the "svg" feature. diff --git a/crates/egui_extras/src/loaders/image_loader.rs b/crates/egui_extras/src/loaders/image_loader.rs index a2a6fb1df..afae6dd21 100644 --- a/crates/egui_extras/src/loaders/image_loader.rs +++ b/crates/egui_extras/src/loaders/image_loader.rs @@ -53,7 +53,7 @@ impl ImageLoader for ImageCrateLoader { Self::ID } - fn load(&self, ctx: &egui::Context, uri: &str, _: SizeHint) -> ImageLoadResult { + fn load(&self, ctx: &egui::Context, uri: &str, hint: SizeHint) -> ImageLoadResult { // three stages of guessing if we support loading the image: // 1. URI extension (only done for files) // 2. Mime from `BytesPoll::Ready` @@ -95,7 +95,8 @@ impl ImageLoader for ImageCrateLoader { // (3) log::trace!("started loading {uri:?}"); - let result = crate::image::load_image_bytes(&bytes).map(Arc::new); + let result = + crate::image::load_image_bytes_for_size(&bytes, hint).map(Arc::new); log::trace!("finished loading {uri:?}"); cache.insert(uri.into(), result.clone()); result.map(|image| ImagePoll::Ready { image })