Diffstat (limited to 'src/diffusion/sierra.rs')
| -rw-r--r-- | src/diffusion/sierra.rs | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/src/diffusion/sierra.rs b/src/diffusion/sierra.rs new file mode 100644 index 0000000..4177f1b --- /dev/null +++ b/src/diffusion/sierra.rs @@ -0,0 +1,111 @@ +use super::*; + +pub fn sierra<const FAC: u8>( + image: Image<&[f32], 4>, + palette: &[[f32; 4]], +) -> Image<Box<[f32]>, 4> { + let kd = map(palette); + let mut image = + Image::build(image.width(), image.height()).buf(image.buffer().to_vec().into_boxed_slice()); + let w = image.width(); + let h = image.height(); + for (x, y) in (0..h).flat_map(move |y| (0..w).map(move |x| (x, y))) { + #[rustfmt::skip] + unsafe { + let p = image.pixel(x, y); + let new = palette[kd.find_nearest(p) as usize]; + *image.pixel_mut(x, y) = new; + let error = p.asub(new); + let f = |f| { + move |x: [f32; 4]| { + x.aadd(error.amul([(f as f32 / 32.) * const { FAC as f32 * (1.0 / 255.) }; 4])) + } + }; + /* * 5 3 + 2 4 5 4 2 + 2 3 2 */ + image.replace(x + 1, y, f(5)); + image.replace(x + 2, y, f(3)); + let y = y + 1; + image.replace(x.wrapping_sub(2), y, f(2)); + image.replace(x.wrapping_sub(1), y, f(4)); + image.replace(x , y, f(5)); + image.replace(x + 1, y, f(4)); + image.replace(x + 2, y, f(2)); + let y = y + 1; + image.replace(x.wrapping_sub(1), y, f(2)); + image.replace(x , y, f(3)); + image.replace(x + 1, y, f(2)); + } + } + image +} + +pub fn sierra_two<const FAC: u8>( + image: Image<&[f32], 4>, + palette: &[[f32; 4]], +) -> Image<Box<[f32]>, 4> { + let kd = map(palette); + let mut image = + Image::build(image.width(), image.height()).buf(image.buffer().to_vec().into_boxed_slice()); + let w = image.width(); + let h = image.height(); + for (x, y) in (0..h).flat_map(move |y| (0..w).map(move |x| (x, y))) { + #[rustfmt::skip] + unsafe { + let p = image.pixel(x, y); + let new = palette[kd.find_nearest(p) as usize]; + *image.pixel_mut(x, y) = new; + let error = p.asub(new); + let f = |f| { + move |x: [f32; 4]| { + x.aadd(error.amul([(f as f32 / 16.) * const { FAC as f32 * (1.0 / 255.) }; 4])) + } + }; + /* * 4 3 + 1 2 3 2 1 */ + image.replace(x + 1, y, f(4)); + image.replace(x + 2, y, f(3)); + let y = y + 1; + image.replace(x.wrapping_sub(2), y, f(1)); + image.replace(x.wrapping_sub(1), y, f(2)); + image.replace(x , y, f(3)); + image.replace(x + 1, y, f(2)); + image.replace(x + 2, y, f(1)); + } + } + image +} + +pub fn sierra_lite<const FAC: u8>( + image: Image<&[f32], 4>, + palette: &[[f32; 4]], +) -> Image<Box<[f32]>, 4> { + let kd = map(palette); + let mut image = + Image::build(image.width(), image.height()).buf(image.buffer().to_vec().into_boxed_slice()); + let w = image.width(); + let h = image.height(); + for (x, y) in (0..h).flat_map(move |y| (0..w).map(move |x| (x, y))) { + #[rustfmt::skip] + unsafe { + let p = image.pixel(x, y); + let new = palette[kd.find_nearest(p) as usize]; + *image.pixel_mut(x, y) = new; + let error = p.asub(new); + let f = |f| { + move |x: [f32; 4]| { + x.aadd(error.amul([(f as f32 / 4.) * const { FAC as f32 * (1.0 / 255.) }; 4])) + } + }; + #[allow(warnings)] + /** 2 + 1 1 */ + image.replace(x + 1, y, f(2)); + let y = y + 1; + image.replace(x.wrapping_sub(1), y, f(1)); + image.replace(x , y, f(1)); + } + } + image +} |