summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorache <ache@ache.one>2025-04-27 00:22:53 +0200
committerache <ache@ache.one>2025-04-27 00:22:53 +0200
commit378ec6bf157f821dbc3f3eba395e7616251ddb0b (patch)
treecaddc979991c74052806bb91175d157b277da6f9
parentWorst atomic commit ever (diff)
Implement serpentine scanning
-rw-r--r--src/lib.rs80
1 files changed, 80 insertions, 0 deletions
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<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;