use std::f64;
use image::{DynamicImage, GenericImage, GenericImageView, ImageError};
use ndarray::{arr2, concatenate, Array2, Axis};
use rayon::iter::{IndexedParallelIterator, IntoParallelRefMutIterator, ParallelIterator};
const R_MUT: f64 = 0.2126;
const G_MUT: f64 = 0.7152;
const B_MUT: f64 = 0.0722;
fn generate_bayer(level: u8) -> Array2<i32> {
let num = 2_u8.pow(level.into());
match num {
2 => arr2(&[[0, 2], [3, 1]]),
_ => {
concatenate![
Axis(0),
concatenate![
Axis(1),
4 * self::generate_bayer(level - 1),
4 * self::generate_bayer(level - 1),
concatenate![
Axis(1),
4 * self::generate_bayer(level - 1) + 3,
4 * self::generate_bayer(level - 1) + 1
]
]
]
}
}
}
pub fn ditherize(level: u8, image: DynamicImage) -> Result<DynamicImage, ImageError> {
let bayer = self::generate_bayer(level);
let num = 2_u8.pow(level.into());
let equalizer = 1. / (num as f32).powf(2.);
let bayer = bayer.mapv(|x| (x as f32) * equalizer);
let greyscale = image.grayscale();
let (width, height) = greyscale.dimensions();
let mut buffer = greyscale.to_rgb8();
let buffer = buffer.enumerate_pixels_mut();
let mut buffer: Vec<_> = buffer.collect();
buffer
.par_iter_mut()
.enumerate()
.for_each(|(_, (x, y, pixel))| {
let r = pixel[0] as f64 / 255.;
let g = pixel[1] as f64 / 255.;
let b = pixel[2] as f64 / 255.;
let mut br = r * R_MUT + g * G_MUT + b * B_MUT;
let bayer_len = bayer.shape()[0];
let x = x.rem_euclid(bayer_len.try_into().unwrap()) as usize;
let y = y.rem_euclid(bayer_len.try_into().unwrap()) as usize;
br = {
if br <= 0.04045 {
br / 12.92
} else {
((br + 0.055) / 1.055).powf(2.4)
}
};
if br > (1. - bayer[[y, x]] as f32).into() {
pixel[0] = 131;
pixel[1] = 176;
pixel[2] = 126;
} else {
pixel[0] = 0;
pixel[1] = 0;
pixel[2] = 0;
}
});
let mut new_image_bufffer = DynamicImage::new_rgb8(width, height).to_rgb8();
for (x, y, pixel) in buffer {
new_image_bufffer.put_pixel(x, y, *pixel);
}
Ok(DynamicImage::ImageRgb8(new_image_bufffer))
}