1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
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))
}