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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
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
}