diff options
| author | ache <ache@ache.one> | 2025-04-27 00:22:53 +0200 |
|---|---|---|
| committer | ache <ache@ache.one> | 2025-04-27 00:22:53 +0200 |
| commit | 378ec6bf157f821dbc3f3eba395e7616251ddb0b (patch) | |
| tree | caddc979991c74052806bb91175d157b277da6f9 | |
| parent | Worst atomic commit ever (diff) | |
Implement serpentine scanning
| -rw-r--r-- | src/lib.rs | 80 |
1 files changed, 80 insertions, 0 deletions
@@ -444,6 +444,86 @@ pub fn dither(image: &mut RgbImage, kernel: kernel::Kernel) { *pixel_ = image::Rgb([pixel, pixel, pixel]); } } +pub fn dither_serpentine_1b(image: &mut RgbImage, kernel: kernel::Kernel) { + let (width, height) = image.dimensions(); + let (width, height): (usize, usize) = (width as usize, height as usize); + let error_buffer_size = kernel + .iter() + .map(|k| k.dx + k.dy * width as i32) + .max() + .unwrap() as usize; + assert!(error_buffer_size > 0); + let mut error: Vec<f32> = vec![0.; error_buffer_size]; + + for y in 0..(height as u32) { + let serpentine_coef: i32 = if y % 2 == 0 { 1 } else { 1 }; + for x in 0..(width as u32) { + let x = if y % 2 == 0 { x } else { width as u32 - 1 - x }; + + let Rgb([r, g, b]) = image.get_pixel(x, y); + let pixel = (*r as f32 + *g as f32 + *b as f32) as f32 / 3.; + let err_pos: u32 = (y * width as u32 + x) % (error_buffer_size as u32); + + // let (pixel, err) = dither_float_chose_color(error[err_pos as usize], pixel); + let (pixel, err) = dither_atkinson_chose_color(error[err_pos as usize], pixel); + + for e in &kernel { + error[(err_pos as i32 + e.dx * serpentine_coef + width as i32 * e.dy) + .rem_euclid(error_buffer_size as i32) as usize] += err * e.weight; + } + error[err_pos as usize] = 0.; + + image.put_pixel(x, y, image::Rgb([pixel, pixel, pixel])); + } + } +} +pub fn dither_serpentine_3b(image: &mut RgbImage, kernel: kernel::Kernel) { + let (width, height) = image.dimensions(); + let (width, height): (usize, usize) = (width as usize, height as usize); + let error_buffer_size = kernel + .iter() + .map(|k| k.dx + k.dy * width as i32) + .max() + .unwrap() as usize; + assert!(error_buffer_size > 0); + let mut error: [Vec<f32>; 3] = [ + vec![0.; error_buffer_size], + vec![0.; error_buffer_size], + vec![0.; error_buffer_size], + ]; + + for y in 0..(height as u32) { + let serpentine_coef: i32 = if y % 2 == 0 { 1 } else { 1 }; + for x in 0..(width as u32) { + let x = if y % 2 == 0 { x } else { width as u32 - 1 - x }; + + let pixel = image.get_pixel(x, y); + let err_pos: u32 = (y * width as u32 + x) % (error_buffer_size as u32); + + // let (pixel, err) = dither_float_chose_color(error[err_pos as usize], pixel); + let (new_pixel, err) = dither_float_chose_3b( + error[0][err_pos as usize], + error[1][err_pos as usize], + error[2][err_pos as usize], + *pixel, + ); + + for i in 0..3 { + error[i][err_pos as usize] = 0.; + } + + for e in &kernel { + for i in 0..3 { + error[i][(err_pos as i32 + e.dx * serpentine_coef + width as i32 * e.dy) + .rem_euclid(error_buffer_size as i32) + as usize] += err[i] * e.weight; + } + } + + image.put_pixel(x, y, new_pixel); + } + } +} pub fn dither_float(image: &mut RgbImage, kernel: kernel::Kernel) { let (width, _height) = image.dimensions(); let width = width as usize; |