@@ -36,8 +36,7 @@ async fn blur(
3636 Raster :: new_cpu ( box_blur_algorithm ( image. into_data ( ) , radius, gamma) )
3737 } else if median {
3838 Raster :: new_cpu ( median_filter_algorithm ( image. into_data ( ) , radius as u32 , gamma) )
39- }
40- else {
39+ } else {
4140 Raster :: new_cpu ( gaussian_blur_algorithm ( image. into_data ( ) , radius, gamma) )
4241 } ;
4342
@@ -195,16 +194,26 @@ fn median_filter_algorithm(mut original_buffer: Image<Color>, radius: u32, gamma
195194 let ( width, height) = original_buffer. dimensions ( ) ;
196195 let mut output = Image :: new ( width, height, Color :: TRANSPARENT ) ;
197196
197+ // Pre-allocate and reuse buffers outside the loops to avoid repeated allocations.
198+ let window_capacity = ( ( 2 * radius + 1 ) . pow ( 2 ) ) as usize ;
199+ let mut r_vals: Vec < f32 > = Vec :: with_capacity ( window_capacity) ;
200+ let mut g_vals: Vec < f32 > = Vec :: with_capacity ( window_capacity) ;
201+ let mut b_vals: Vec < f32 > = Vec :: with_capacity ( window_capacity) ;
202+ let mut a_vals: Vec < f32 > = Vec :: with_capacity ( window_capacity) ;
203+
198204 for y in 0 ..height {
199205 for x in 0 ..width {
200- // Collect pixel neighborhood
201- let mut r_vals = Vec :: with_capacity ( ( ( 2 * radius + 1 ) . pow ( 2 ) ) as usize ) ;
202- let mut g_vals = Vec :: with_capacity ( r_vals. capacity ( ) ) ;
203- let mut b_vals = Vec :: with_capacity ( r_vals. capacity ( ) ) ;
204- let mut a_vals = Vec :: with_capacity ( r_vals. capacity ( ) ) ;
205-
206- for ny in y. saturating_sub ( radius) ..=( y + radius) . min ( height - 1 ) {
207- for nx in x. saturating_sub ( radius) ..=( x + radius) . min ( width - 1 ) {
206+ r_vals. clear ( ) ;
207+ g_vals. clear ( ) ;
208+ b_vals. clear ( ) ;
209+ a_vals. clear ( ) ;
210+
211+ // Use saturating_add to avoid potential overflow in extreme cases
212+ let y_max = y. saturating_add ( radius) . min ( height - 1 ) ;
213+ let x_max = x. saturating_add ( radius) . min ( width - 1 ) ;
214+
215+ for ny in y. saturating_sub ( radius) ..=y_max {
216+ for nx in x. saturating_sub ( radius) ..=x_max {
208217 if let Some ( px) = original_buffer. get_pixel ( nx, ny) {
209218 r_vals. push ( px. r ( ) ) ;
210219 g_vals. push ( px. g ( ) ) ;
@@ -214,7 +223,6 @@ fn median_filter_algorithm(mut original_buffer: Image<Color>, radius: u32, gamma
214223 }
215224 }
216225
217- // Use quickselect instead of sorting for efficiency
218226 let r = median_quickselect ( & mut r_vals) ;
219227 let g = median_quickselect ( & mut g_vals) ;
220228 let b = median_quickselect ( & mut b_vals) ;
0 commit comments