From 18f5cc459df09145600ebee7f591ad9e7550e6b8 Mon Sep 17 00:00:00 2001 From: Jordan Doyle Date: Wed, 3 Jan 2024 19:22:57 +0000 Subject: [PATCH] Move to stackblur for performance --- Cargo.lock | 41 +++++++++++++++++++++++++++++++++++++++++ shalom/Cargo.toml | 1 + shalom/src/pages/room/listen.rs | 3 +-- shalom/src/theme.rs | 33 ++++++++++++++++++++++++++++++++- shalom/src/widgets/colour_picker.rs | 17 ++++++++++------- 5 files changed, 85 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1738165..df3aa62 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -206,6 +206,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] +name = "blend-srgb" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a187f5213b0a15f4344b1850bf1bd1f5cbe98eaf61d9914406723a9a2e6426" + +[[package]] name = "block" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1454,6 +1460,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "029d73f573d8e8d63e6d5020011d3255b28c3ba85d6cf870a07184ed23de9284" [[package]] +name = "imgref" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90d944e334f00f4449c9640b440a171f816be0152305c12ef90424fc35fd035c" + +[[package]] +name = "imgref-iter" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58112733c0ee178b66dceba49e0445d0b293268719de579d2c7dd4c2290976aa" +dependencies = [ + "imgref", +] + +[[package]] name = "indexmap" version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2921,6 +2942,7 @@ dependencies = [ "serde", "serde_json", "serde_with", + "stackblur-iter", "strum", "time", "tokio", @@ -3079,6 +3101,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] +name = "stackblur-iter" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712b7bee292d3d0ac59c5110f826d3d8aaafd8f39e455319acebe06c0eae3e7f" +dependencies = [ + "blend-srgb", + "imgref", + "imgref-iter", + "rayon", + "unique", +] + +[[package]] name = "static_assertions" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3632,6 +3667,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] +name = "unique" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d360722e1f3884f5b14d332185f02ff111f771f0c76a313268fe6af1409aba96" + +[[package]] name = "untrusted" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/shalom/Cargo.toml b/shalom/Cargo.toml index 21b9f54..82f5de1 100644 --- a/shalom/Cargo.toml +++ b/shalom/Cargo.toml @@ -22,6 +22,7 @@ reqwest = { version = "0.11.22", default-features = false, features = ["rustls-t serde = { version = "1.0", features = ["derive"] } serde_with = { version = "3.4", features = ["macros"] } serde_json = { version = "1.0", features = ["raw_value"] } +stackblur-iter = { version = "0.2.0", features = ["blend-srgb", "rayon"] } strum = { version = "0.25", features = ["derive"] } tokio = { version = "1.33", features = ["net", "sync", "rt", "macros", "time", "fs"] } tokio-stream = { version = "0.1", features = ["sync"] } diff --git a/shalom/src/pages/room/listen.rs b/shalom/src/pages/room/listen.rs index 0186a9b..7f30573 100644 --- a/shalom/src/pages/room/listen.rs +++ b/shalom/src/pages/room/listen.rs @@ -6,7 +6,6 @@ use iced::{ widget::{container, image::Handle, Column}, Element, Renderer, Subscription, }; -use image::imageops::blur; use url::Url; use crate::{ @@ -202,7 +201,7 @@ impl Listen { if let Some(MaybePendingImage::Loading(url)) = &self.background { download_image( url.clone(), - |image| blur(&darken_image(image, 0.3), 5.0), + |image| crate::theme::blur(&darken_image(image, 0.3), 15), Message::BackgroundDownloaded, ) } else { diff --git a/shalom/src/theme.rs b/shalom/src/theme.rs index 06640be..12a6910 100644 --- a/shalom/src/theme.rs +++ b/shalom/src/theme.rs @@ -1,9 +1,10 @@ -use ::image::{GenericImageView, Pixel, RgbaImage}; +use ::image::{GenericImageView, Pixel, Rgba, RgbaImage}; use iced::{ advanced::svg::Handle, widget::{image, svg}, }; use once_cell::sync::Lazy; +use stackblur_iter::imgref::Img; pub mod colours { use iced::Color; @@ -171,3 +172,33 @@ pub fn darken_image(mut img: RgbaImage, factor: f32) -> RgbaImage { img } + +#[allow(clippy::many_single_char_names)] +pub fn blur(img: &RgbaImage, radius: usize) -> RgbaImage { + let width = img.width(); + let height = img.height(); + + let mut raw = img + .pixels() + .map(|p| u32::from_be_bytes([p.0[3], p.0[0], p.0[1], p.0[2]])) + .collect::>(); + + stackblur_iter::par_blur_srgb( + &mut Img::new( + &mut raw, + width.try_into().unwrap(), + height.try_into().unwrap(), + ), + radius, + ); + + let mut image = RgbaImage::new(width, height); + for (i, &pixel) in raw.iter().enumerate() { + let x = u32::try_from(i).unwrap_or(u32::MAX) % width; + let y = u32::try_from(i).unwrap_or(u32::MAX) / width; + let [a, r, g, b] = pixel.to_be_bytes(); + image.put_pixel(x, y, Rgba([r, g, b, a])); + } + + image +} diff --git a/shalom/src/widgets/colour_picker.rs b/shalom/src/widgets/colour_picker.rs index 39e99d9..1e10b8e 100644 --- a/shalom/src/widgets/colour_picker.rs +++ b/shalom/src/widgets/colour_picker.rs @@ -15,20 +15,20 @@ use palette::IntoColor; use crate::widgets::forced_rounded::forced_rounded; -pub struct ColourPicker { +pub struct ColourPicker { hue: f32, saturation: f32, brightness: f32, - on_change: fn(f32, f32, f32) -> Event, + on_change: F, on_mouse_up: Event, } -impl ColourPicker { +impl ColourPicker { pub fn new( hue: f32, saturation: f32, brightness: f32, - on_change: fn(f32, f32, f32) -> Event, + on_change: F, on_mouse_up: Event, ) -> Self { Self { @@ -41,7 +41,9 @@ impl ColourPicker { } } -impl Component for ColourPicker { +impl Event> Component + for ColourPicker +{ type State = (); type Event = Message; @@ -88,11 +90,12 @@ impl Component for ColourPicker { } } -impl<'a, M> From> for Element<'a, M, Renderer> +impl<'a, M, F> From> for Element<'a, M, Renderer> where M: 'a + Clone, + F: Fn(f32, f32, f32) -> M + 'a, { - fn from(card: ColourPicker) -> Self { + fn from(card: ColourPicker) -> Self { component(card) } } -- libgit2 1.7.2