Skip to content

Commit bf22aca

Browse files
committed
perf(colored): parallelize gradient generation
1 parent fc59845 commit bf22aca

3 files changed

Lines changed: 38 additions & 51 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ cosmic-bg-config = { path = "./config" }
1111
eyre = "0.6.12"
1212
fast_image_resize = { version = "6.0.0", features = ["image"] }
1313
image = { workspace = true, features = ["hdr", "jpeg", "png", "rayon", "webp"] }
14+
rayon = "1.11"
1415
jxl-oxide = { version = "0.12.4", features = ["image"] }
1516
notify = "8.2.0"
1617
rand = "0.9.2"

src/colored.rs

Lines changed: 36 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,12 @@
33
use colorgrad::{Color, Gradient as ColorGradient};
44
use cosmic_bg_config::Gradient;
55
use image::Rgb32FImage;
6+
use rayon::prelude::*;
67

78
/// Generate a background image from a color.
89
pub fn single(color: [f32; 3], width: u32, height: u32) -> Rgb32FImage {
9-
let mut imgbuf = Rgb32FImage::new(width, height);
10-
1110
let pixel = image::Rgb(color);
12-
13-
for x in 0..width {
14-
for y in 0..height {
15-
imgbuf.put_pixel(x, y, pixel);
16-
}
17-
}
18-
19-
imgbuf
11+
image::ImageBuffer::from_pixel(width, height, pixel)
2012
}
2113

2214
/// Generate a background image from a gradient.
@@ -26,14 +18,8 @@ pub fn gradient(
2618
height: u32,
2719
) -> Result<Rgb32FImage, colorgrad::GradientBuilderError> {
2820
let mut colors = Vec::with_capacity(gradient.colors.len());
29-
3021
for &[r, g, b] in &*gradient.colors {
31-
colors.push(colorgrad::Color::from_linear_rgba(
32-
f32::from(r),
33-
f32::from(g),
34-
f32::from(b),
35-
1.0,
36-
));
22+
colors.push(colorgrad::Color::from_linear_rgba(r, g, b, 1.0));
3723
}
3824

3925
let grad = colorgrad::GradientBuilder::new()
@@ -42,45 +28,44 @@ pub fn gradient(
4228
.build::<colorgrad::LinearGradient>()?;
4329

4430
let mut imgbuf = image::ImageBuffer::new(width, height);
45-
46-
let width = f64::from(width);
47-
let height = f64::from(height);
31+
let width = width as f32;
32+
let height = height as f32;
33+
let orientation = gradient.radius as u16;
34+
35+
let (dmin, dmax) = grad.domain();
36+
let angle = gradient.radius.to_radians();
37+
let cos = f32::cos(angle);
38+
let sin = f32::sin(angle);
39+
const SCALE: f32 = 0.015;
40+
let w_scale = width / SCALE;
41+
let h_scale = height / SCALE;
4842

4943
// Map t which is in range [a, b] to range [c, d]
50-
#[allow(clippy::items_after_statements)]
51-
fn remap(t: f64, a: f64, b: f64, c: f64, d: f64) -> f64 {
44+
fn remap(t: f32, a: f32, b: f32, c: f32, d: f32) -> f32 {
5245
(t - a) * ((d - c) / (b - a)) + c
5346
}
5447

55-
#[allow(clippy::items_after_statements)]
56-
const SCALE: f64 = 0.015;
57-
58-
let positioner: Box<dyn Fn(u32, u32) -> f64> = match gradient.radius as u16 {
59-
0 => Box::new(|_x, y| 1.0 - (y as f64 / height)),
60-
90 => Box::new(|x, _y| x as f64 / width),
61-
180 => Box::new(|_x, y| y as f64 / height),
62-
270 => Box::new(|x, _y| 1.0 - (x as f64 / width)),
63-
_ => Box::new(|x, y| {
64-
let (dmin, dmax) = grad.domain();
65-
let angle = f64::from(gradient.radius.to_radians());
66-
let (x, y) = (f64::from(x) - width / SCALE, f64::from(y) - height / SCALE);
67-
68-
remap(
69-
x * f64::cos(angle) - y * f64::sin(angle),
70-
-width / SCALE,
71-
width / SCALE,
72-
f64::from(dmin),
73-
f64::from(dmax),
74-
)
75-
}),
76-
};
77-
78-
#[allow(clippy::cast_possible_truncation)]
79-
for (x, y, pixel) in imgbuf.enumerate_pixels_mut() {
80-
let Color { r, g, b, .. } = grad.at(positioner(x, y) as f32);
81-
82-
*pixel = image::Rgb([r as f32, g as f32, b as f32]);
83-
}
48+
imgbuf.par_enumerate_pixels_mut().for_each(|(x, y, pixel)| {
49+
let x_f = x as f32;
50+
let y_f = y as f32;
51+
52+
let pos = match orientation {
53+
0 => 1.0 - (y_f / height),
54+
90 => x_f / width,
55+
180 => y_f / height,
56+
270 => 1.0 - (x_f / width),
57+
_ => remap(
58+
(x_f - w_scale) * cos - (y_f - h_scale) * sin,
59+
-w_scale,
60+
w_scale,
61+
dmin,
62+
dmax,
63+
),
64+
};
65+
66+
let Color { r, g, b, .. } = grad.at(pos);
67+
*pixel = image::Rgb([r, g, b]);
68+
});
8469

8570
Ok(imgbuf)
8671
}

0 commit comments

Comments
 (0)