From 6fa54f7f6bbb79224e75ad3606738dbd933ccc2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Fri, 24 Oct 2025 20:06:26 +0200 Subject: [PATCH] Decode on the fly in `gallery` example Use `release` mode. Image decoding is terribly slow in `debug` mode! --- examples/gallery/src/civitai.rs | 38 +++++++++++++------------- examples/gallery/src/main.rs | 47 ++++++++++++++++----------------- wgpu/src/image/cache.rs | 2 +- 3 files changed, 44 insertions(+), 43 deletions(-) diff --git a/examples/gallery/src/civitai.rs b/examples/gallery/src/civitai.rs index 97f0ad89..09fd0f91 100644 --- a/examples/gallery/src/civitai.rs +++ b/examples/gallery/src/civitai.rs @@ -1,4 +1,3 @@ -use bytes::Bytes; use serde::Deserialize; use sipper::{Straw, sipper}; use tokio::task; @@ -54,14 +53,14 @@ impl Image { rgba: Rgba { width, height, - pixels: Bytes::from(pixels), + pixels: Bytes(pixels.into()), }, }) }) .await? } - pub fn download(self, size: Size) -> impl Straw { + pub fn download(self, size: Size) -> impl Straw { sipper(async move |mut sender| { let client = reqwest::Client::new(); @@ -97,21 +96,7 @@ impl Image { .bytes() .await?; - let image = task::spawn_blocking(move || { - Ok::<_, Error>( - image::ImageReader::new(io::Cursor::new(bytes)) - .with_guessed_format()? - .decode()? - .to_rgba8(), - ) - }) - .await??; - - Ok(Rgba { - width: image.width(), - height: image.height(), - pixels: Bytes::from(image.into_raw()), - }) + Ok(Bytes(bytes)) }) } } @@ -142,6 +127,23 @@ impl fmt::Debug for Rgba { } } +#[derive(Clone)] +pub struct Bytes(bytes::Bytes); + +impl From for bytes::Bytes { + fn from(value: Bytes) -> Self { + value.0 + } +} + +impl fmt::Debug for Bytes { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Compressed") + .field("bytes", &self.0.len()) + .finish() + } +} + #[derive(Debug, Clone, Copy)] pub enum Size { Original, diff --git a/examples/gallery/src/main.rs b/examples/gallery/src/main.rs index 42e916db..03768604 100644 --- a/examples/gallery/src/main.rs +++ b/examples/gallery/src/main.rs @@ -4,7 +4,7 @@ //! some smooth animations. mod civitai; -use crate::civitai::{Error, Id, Image, Rgba, Size}; +use crate::civitai::{Bytes, Error, Id, Image, Rgba, Size}; use iced::animation; use iced::time::{Instant, milliseconds}; @@ -46,8 +46,8 @@ enum Message { ImagesListed(Result, Error>), ImagePoppedIn(Id), ImagePoppedOut(Id), - ImageDownloaded(Result), - ThumbnailDownloaded(Id, Result), + ImageDownloaded(Result), + ThumbnailDownloaded(Id, Result), ThumbnailHovered(Id, bool), BlurhashDecoded(Id, civitai::Blurhash), Open(Id), @@ -110,6 +110,13 @@ impl Gallery { let _ = self.visible.insert(id); if self.downloaded.contains(&id) { + if let Some(Preview::Ready { thumbnail, .. }) = + self.previews.get_mut(&id) + { + thumbnail.fade_in = + Animation::new(false).slow().go(true, now); + } + return Task::none(); } @@ -129,17 +136,17 @@ impl Gallery { Task::none() } - Message::ImageDownloaded(Ok(rgba)) => { - self.viewer.show(rgba, self.now); + Message::ImageDownloaded(Ok(bytes)) => { + self.viewer.show(bytes, self.now); Task::none() } - Message::ThumbnailDownloaded(id, Ok(rgba)) => { + Message::ThumbnailDownloaded(id, Ok(bytes)) => { let thumbnail = if let Some(preview) = self.previews.remove(&id) { - preview.load(rgba, self.now) + preview.load(bytes, self.now) } else { - Preview::ready(rgba, self.now) + Preview::ready(bytes, self.now) }; let _ = self.previews.insert(id, thumbnail); @@ -339,21 +346,21 @@ impl Preview { } } - fn ready(rgba: Rgba, now: Instant) -> Self { + fn ready(bytes: Bytes, now: Instant) -> Self { Self::Ready { blurhash: None, - thumbnail: Thumbnail::new(rgba, now), + thumbnail: Thumbnail::new(bytes, now), } } - fn load(self, rgba: Rgba, now: Instant) -> Self { + fn load(self, bytes: Bytes, now: Instant) -> Self { let Self::Loading { blurhash } = self else { return self; }; Self::Ready { blurhash: Some(blurhash), - thumbnail: Thumbnail::new(rgba, now), + thumbnail: Thumbnail::new(bytes, now), } } @@ -387,13 +394,9 @@ impl Preview { } impl Thumbnail { - pub fn new(rgba: Rgba, now: Instant) -> Self { + pub fn new(bytes: Bytes, now: Instant) -> Self { Self { - handle: image::Handle::from_rgba( - rgba.width, - rgba.height, - rgba.pixels, - ), + handle: image::Handle::from_bytes(bytes), fade_in: Animation::new(false).slow().go(true, now), zoom: Animation::new(false) .quick() @@ -426,12 +429,8 @@ impl Viewer { self.background_fade_in.go_mut(true, now); } - fn show(&mut self, rgba: Rgba, now: Instant) { - self.image = Some(image::Handle::from_rgba( - rgba.width, - rgba.height, - rgba.pixels, - )); + fn show(&mut self, bytes: Bytes, now: Instant) { + self.image = Some(image::Handle::from_bytes(bytes)); self.background_fade_in.go_mut(true, now); self.image_fade_in.go_mut(true, now); } diff --git a/wgpu/src/image/cache.rs b/wgpu/src/image/cache.rs index 61777318..cc0e7d69 100644 --- a/wgpu/src/image/cache.rs +++ b/wgpu/src/image/cache.rs @@ -248,7 +248,7 @@ fn load_image<'a>( } else if let core::image::Handle::Rgba { .. } = handle { // Load RGBA handles synchronously, since it's very cheap cache.insert(handle, Memory::load(handle)); - } else { + } else if !pending.contains(&handle.id()) { let _ = jobs.send(Job::Load(handle.clone())); let _ = pending.insert(handle.id()); }