Move to stackblur for performance
Diff
Cargo.lock | 41 +++++++++++++++++++++++++++++++++++++++++
shalom/Cargo.toml | 1 +
shalom/src/theme.rs | 33 +++++++++++++++++++++++++++++++++
shalom/src/widgets/colour_picker.rs | 17 +++++++++++------
shalom/src/pages/room/listen.rs | 3 +--
5 files changed, 85 insertions(+), 10 deletions(-)
@@ -206,6 +206,12 @@
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"
@@ -1452,6 +1458,21 @@
version = "0.12.0"
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"
@@ -2921,6 +2942,7 @@
"serde",
"serde_json",
"serde_with",
"stackblur-iter",
"strum",
"time",
"tokio",
@@ -3077,6 +3099,19 @@
version = "1.2.0"
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"
@@ -3630,6 +3665,12 @@
version = "0.2.4"
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"
@@ -22,6 +22,7 @@
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"] }
@@ -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;
@@ -170,4 +171,34 @@
eprintln!("darkened");
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::<Vec<_>>();
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
}
@@ -15,20 +15,20 @@
use crate::widgets::forced_rounded::forced_rounded;
pub struct ColourPicker<Event> {
pub struct ColourPicker<Event, F> {
hue: f32,
saturation: f32,
brightness: f32,
on_change: fn(f32, f32, f32) -> Event,
on_change: F,
on_mouse_up: Event,
}
impl<Event> ColourPicker<Event> {
impl<Event, F> ColourPicker<Event, F> {
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<Event: Clone> Component<Event, Renderer> for ColourPicker<Event> {
impl<Event: Clone, F: Fn(f32, f32, f32) -> Event> Component<Event, Renderer>
for ColourPicker<Event, F>
{
type State = ();
type Event = Message;
@@ -88,11 +90,12 @@
}
}
impl<'a, M> From<ColourPicker<M>> for Element<'a, M, Renderer>
impl<'a, M, F> From<ColourPicker<M, F>> for Element<'a, M, Renderer>
where
M: 'a + Clone,
F: Fn(f32, f32, f32) -> M + 'a,
{
fn from(card: ColourPicker<M>) -> Self {
fn from(card: ColourPicker<M, F>) -> Self {
component(card)
}
}
@@ -6,7 +6,6 @@
widget::{container, image::Handle, Column},
Element, Renderer, Subscription,
};
use image::imageops::blur;
use url::Url;
use crate::{
@@ -202,7 +201,7 @@
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 {