resvg/filter/
iir_blur.rs
1use super::ImageRefMut;
30use rgb::ComponentSlice;
31
32struct BlurData {
33 width: usize,
34 height: usize,
35 sigma_x: f64,
36 sigma_y: f64,
37 steps: usize,
38}
39
40pub fn apply(sigma_x: f64, sigma_y: f64, src: ImageRefMut) {
50 let buf_size = (src.width * src.height) as usize;
51 let mut buf = vec![0.0; buf_size];
52 let buf = &mut buf;
53
54 let d = BlurData {
55 width: src.width as usize,
56 height: src.height as usize,
57 sigma_x,
58 sigma_y,
59 steps: 4,
60 };
61
62 let data = src.data.as_mut_slice();
63 gaussian_channel(data, &d, 0, buf);
64 gaussian_channel(data, &d, 1, buf);
65 gaussian_channel(data, &d, 2, buf);
66 gaussian_channel(data, &d, 3, buf);
67}
68
69fn gaussian_channel(data: &mut [u8], d: &BlurData, channel: usize, buf: &mut Vec<f64>) {
70 for i in 0..data.len() / 4 {
71 buf[i] = data[i * 4 + channel] as f64 / 255.0;
72 }
73
74 gaussianiir2d(d, buf);
75
76 for i in 0..data.len() / 4 {
77 data[i * 4 + channel] = (buf[i] * 255.0) as u8;
78 }
79}
80
81fn gaussianiir2d(d: &BlurData, buf: &mut Vec<f64>) {
82 let (lambda_x, dnu_x) = if d.sigma_x > 0.0 {
84 let (lambda, dnu) = gen_coefficients(d.sigma_x, d.steps);
85
86 for y in 0..d.height {
87 for _ in 0..d.steps {
88 let idx = d.width * y;
89
90 for x in 1..d.width {
92 buf[idx + x] += dnu * buf[idx + x - 1];
93 }
94
95 let mut x = d.width - 1;
96
97 while x > 0 {
99 buf[idx + x - 1] += dnu * buf[idx + x];
100 x -= 1;
101 }
102 }
103 }
104
105 (lambda, dnu)
106 } else {
107 (1.0, 1.0)
108 };
109
110 let (lambda_y, dnu_y) = if d.sigma_y > 0.0 {
112 let (lambda, dnu) = gen_coefficients(d.sigma_y, d.steps);
113 for x in 0..d.width {
114 for _ in 0..d.steps {
115 let idx = x;
116
117 let mut y = d.width;
119 while y < buf.len() {
120 buf[idx + y] += dnu * buf[idx + y - d.width];
121 y += d.width;
122 }
123
124 y = buf.len() - d.width;
125
126 while y > 0 {
128 buf[idx + y - d.width] += dnu * buf[idx + y];
129 y -= d.width;
130 }
131 }
132 }
133
134 (lambda, dnu)
135 } else {
136 (1.0, 1.0)
137 };
138
139 let post_scale =
140 ((dnu_x * dnu_y).sqrt() / (lambda_x * lambda_y).sqrt()).powi(2 * d.steps as i32);
141 buf.iter_mut().for_each(|v| *v *= post_scale);
142}
143
144fn gen_coefficients(sigma: f64, steps: usize) -> (f64, f64) {
145 let lambda = (sigma * sigma) / (2.0 * steps as f64);
146 let dnu = (1.0 + 2.0 * lambda - (1.0 + 4.0 * lambda).sqrt()) / (2.0 * lambda);
147 (lambda, dnu)
148}