1#![doc = include_str!("../README.md")]
2
3use cairo::{Format, ImageSurface};
4
5pub fn blur_image_surface(surface: &mut ImageSurface, radius: i32) {
7 let mut width = surface.width();
8 let height = surface.height();
9 let temp =
10 ImageSurface::create(Format::ARgb32, width, height).expect("Couldn’t create surface");
11 let mut kernel = [0u8; 17];
12 let size = kernel.len() as i32;
13 let half = size / 2;
14
15 match surface.format() {
16 Format::A1 => return,
17
18 Format::A8 => width /= 4,
19 _ => (),
20 }
21
22 let src_stride = surface.stride();
23 let dst_stride = temp.stride();
24 surface
25 .with_data(move |src| {
26 temp.with_data(move |dst| {
27 let src =
28 unsafe { std::slice::from_raw_parts_mut(src.as_ptr() as *mut u8, src.len()) };
29 let dst =
30 unsafe { std::slice::from_raw_parts_mut(dst.as_ptr() as *mut u8, dst.len()) };
31 let mut x: u32;
32 let mut y: u32;
33 let mut z: u32;
34 let mut w: u32;
35 let mut p: u32;
36
37 let mut a: u32 = 0;
38 for i in 0..size {
39 let f = i - half;
40 let f = f as f64;
41 kernel[i as usize] = ((-f * f / 30.0).exp() * 80.0) as u8;
42 a += kernel[i as usize] as u32;
43 }
44
45 for i in 0..height {
47 let s: &[u32] = unsafe { src[(i * src_stride) as usize..].align_to::<u32>().1 };
48 let d: &mut [u32] =
49 unsafe { dst[(i * dst_stride) as usize..].align_to_mut::<u32>().1 };
50 for j in 0..width {
51 if radius < j && j < width - radius {
52 let j = j as usize;
53 d[j] = s[j];
54 continue;
55 }
56
57 x = 0;
58 y = 0;
59 z = 0;
60 w = 0;
61 for k in 0..size {
62 if j - half + k < 0 || j - half + k >= width {
63 continue;
64 }
65
66 p = s[(j - half + k) as usize];
67 let k = k as usize;
68
69 x += ((p >> 24) & 0xff) * kernel[k] as u32;
70 y += ((p >> 16) & 0xff) * kernel[k] as u32;
71 z += ((p >> 8) & 0xff) * kernel[k] as u32;
72 w += (p & 0xff) * kernel[k] as u32;
73 }
74 d[j as usize] = (x / a) << 24 | (y / a) << 16 | (z / a) << 8 | (w / a);
75 }
76 }
77
78 for i in 0..height {
80 let mut s: &mut [u32] =
81 unsafe { dst[(i * dst_stride) as usize..].align_to_mut::<u32>().1 };
82 let d: &mut [u32] =
83 unsafe { src[(i * src_stride) as usize..].align_to_mut::<u32>().1 };
84 for j in 0..width {
85 if radius < i && i < height - radius {
86 let j = j as usize;
87 d[j] = s[j];
88 continue;
89 }
90
91 x = 0;
92 y = 0;
93 z = 0;
94 w = 0;
95 for k in 0..size {
96 if i - half + k < 0 || i - half + k >= height {
97 continue;
98 }
99
100 s = unsafe {
101 dst[((i - half + k) * dst_stride) as usize..]
102 .align_to_mut::<u32>()
103 .1
104 };
105 p = s[j as usize];
106 let k = k as usize;
107 x += ((p >> 24) & 0xff) * kernel[k] as u32;
108 y += ((p >> 16) & 0xff) * kernel[k] as u32;
109 z += ((p >> 8) & 0xff) * kernel[k] as u32;
110 w += (p & 0xff) * kernel[k] as u32;
111 }
112 d[j as usize] = (x / a) << 24 | (y / a) << 16 | (z / a) << 8 | (w / a);
113 }
114 }
115 })
116 .unwrap();
117 })
118 .unwrap();
119
120 surface.mark_dirty();
121}