From 378ec6bf157f821dbc3f3eba395e7616251ddb0b Mon Sep 17 00:00:00 2001 From: ache Date: Sun, 27 Apr 2025 00:22:53 +0200 Subject: Implement serpentine scanning --- src/lib.rs | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index a479934..4bc5ab4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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 = 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; 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; -- cgit v1.3-2-g11bf