dithr 0.3.0

Buffer-first rust dithering and halftoning library.
Documentation
pub const OSTROMOUKHOV_COEFFS: [(i16, i16, i16, i16); 256] = [
    (13, 0, 5, 18),
    (13, 0, 5, 18),
    (21, 0, 10, 31),
    (7, 0, 4, 11),
    (8, 0, 5, 13),
    (47, 3, 28, 78),
    (23, 3, 13, 39),
    (15, 3, 8, 26),
    (22, 6, 11, 39),
    (43, 15, 20, 78),
    (7, 3, 3, 13),
    (501, 224, 211, 936),
    (249, 116, 103, 468),
    (165, 80, 67, 312),
    (123, 62, 49, 234),
    (489, 256, 191, 936),
    (81, 44, 31, 156),
    (483, 272, 181, 936),
    (60, 35, 22, 117),
    (53, 32, 19, 104),
    (237, 148, 83, 468),
    (471, 304, 161, 936),
    (3, 2, 1, 6),
    (481, 314, 185, 980),
    (354, 226, 155, 735),
    (1389, 866, 685, 2940),
    (227, 138, 125, 490),
    (267, 158, 163, 588),
    (327, 188, 220, 735),
    (61, 34, 45, 140),
    (627, 338, 505, 1470),
    (1227, 638, 1075, 2940),
    (20, 10, 19, 49),
    (1937, 1000, 1767, 4704),
    (977, 520, 855, 2352),
    (657, 360, 551, 1568),
    (71, 40, 57, 168),
    (2005, 1160, 1539, 4704),
    (337, 200, 247, 784),
    (2039, 1240, 1425, 4704),
    (257, 160, 171, 588),
    (691, 440, 437, 1568),
    (1045, 680, 627, 2352),
    (301, 200, 171, 672),
    (177, 120, 95, 392),
    (2141, 1480, 1083, 4704),
    (1079, 760, 513, 2352),
    (725, 520, 323, 1568),
    (137, 100, 57, 294),
    (2209, 1640, 855, 4704),
    (53, 40, 19, 112),
    (2243, 1720, 741, 4704),
    (565, 440, 171, 1176),
    (759, 600, 209, 1568),
    (1147, 920, 285, 2352),
    (2311, 1880, 513, 4704),
    (97, 80, 19, 196),
    (335, 280, 57, 672),
    (1181, 1000, 171, 2352),
    (793, 680, 95, 1568),
    (599, 520, 57, 1176),
    (2413, 2120, 171, 4704),
    (405, 360, 19, 784),
    (2447, 2200, 57, 4704),
    (11, 10, 0, 21),
    (158, 151, 3, 312),
    (178, 179, 7, 364),
    (1030, 1091, 63, 2184),
    (248, 277, 21, 546),
    (318, 375, 35, 728),
    (458, 571, 63, 1092),
    (878, 1159, 147, 2184),
    (5, 7, 1, 13),
    (172, 181, 37, 390),
    (97, 76, 22, 195),
    (72, 41, 17, 130),
    (119, 47, 29, 195),
    (4, 1, 1, 6),
    (4, 1, 1, 6),
    (4, 1, 1, 6),
    (4, 1, 1, 6),
    (4, 1, 1, 6),
    (4, 1, 1, 6),
    (4, 1, 1, 6),
    (4, 1, 1, 6),
    (4, 1, 1, 6),
    (65, 18, 17, 100),
    (95, 29, 26, 150),
    (185, 62, 53, 300),
    (30, 11, 9, 50),
    (35, 14, 11, 60),
    (85, 37, 28, 150),
    (55, 26, 19, 100),
    (80, 41, 29, 150),
    (155, 86, 59, 300),
    (5, 3, 2, 10),
    (5, 3, 2, 10),
    (5, 3, 2, 10),
    (5, 3, 2, 10),
    (5, 3, 2, 10),
    (5, 3, 2, 10),
    (5, 3, 2, 10),
    (5, 3, 2, 10),
    (5, 3, 2, 10),
    (5, 3, 2, 10),
    (5, 3, 2, 10),
    (5, 3, 2, 10),
    (5, 3, 2, 10),
    (305, 176, 119, 600),
    (155, 86, 59, 300),
    (105, 56, 39, 200),
    (80, 41, 29, 150),
    (65, 32, 23, 120),
    (55, 26, 19, 100),
    (335, 152, 113, 600),
    (85, 37, 28, 150),
    (115, 48, 37, 200),
    (35, 14, 11, 60),
    (355, 136, 109, 600),
    (30, 11, 9, 50),
    (365, 128, 107, 600),
    (185, 62, 53, 300),
    (25, 8, 7, 40),
    (95, 29, 26, 150),
    (385, 112, 103, 600),
    (65, 18, 17, 100),
    (395, 104, 101, 600),
    (4, 1, 1, 6),
    (4, 1, 1, 6),
    (395, 104, 101, 600),
    (65, 18, 17, 100),
    (385, 112, 103, 600),
    (95, 29, 26, 150),
    (25, 8, 7, 40),
    (185, 62, 53, 300),
    (365, 128, 107, 600),
    (30, 11, 9, 50),
    (355, 136, 109, 600),
    (35, 14, 11, 60),
    (115, 48, 37, 200),
    (85, 37, 28, 150),
    (335, 152, 113, 600),
    (55, 26, 19, 100),
    (65, 32, 23, 120),
    (80, 41, 29, 150),
    (105, 56, 39, 200),
    (155, 86, 59, 300),
    (305, 176, 119, 600),
    (5, 3, 2, 10),
    (5, 3, 2, 10),
    (5, 3, 2, 10),
    (5, 3, 2, 10),
    (5, 3, 2, 10),
    (5, 3, 2, 10),
    (5, 3, 2, 10),
    (5, 3, 2, 10),
    (5, 3, 2, 10),
    (5, 3, 2, 10),
    (5, 3, 2, 10),
    (5, 3, 2, 10),
    (5, 3, 2, 10),
    (155, 86, 59, 300),
    (80, 41, 29, 150),
    (55, 26, 19, 100),
    (85, 37, 28, 150),
    (35, 14, 11, 60),
    (30, 11, 9, 50),
    (185, 62, 53, 300),
    (95, 29, 26, 150),
    (65, 18, 17, 100),
    (4, 1, 1, 6),
    (4, 1, 1, 6),
    (4, 1, 1, 6),
    (4, 1, 1, 6),
    (4, 1, 1, 6),
    (4, 1, 1, 6),
    (4, 1, 1, 6),
    (4, 1, 1, 6),
    (4, 1, 1, 6),
    (119, 47, 29, 195),
    (72, 41, 17, 130),
    (97, 76, 22, 195),
    (172, 181, 37, 390),
    (5, 7, 1, 13),
    (878, 1159, 147, 2184),
    (458, 571, 63, 1092),
    (318, 375, 35, 728),
    (248, 277, 21, 546),
    (1030, 1091, 63, 2184),
    (178, 179, 7, 364),
    (158, 151, 3, 312),
    (11, 10, 0, 21),
    (2447, 2200, 57, 4704),
    (405, 360, 19, 784),
    (2413, 2120, 171, 4704),
    (599, 520, 57, 1176),
    (793, 680, 95, 1568),
    (1181, 1000, 171, 2352),
    (335, 280, 57, 672),
    (97, 80, 19, 196),
    (2311, 1880, 513, 4704),
    (1147, 920, 285, 2352),
    (759, 600, 209, 1568),
    (565, 440, 171, 1176),
    (2243, 1720, 741, 4704),
    (53, 40, 19, 112),
    (2209, 1640, 855, 4704),
    (137, 100, 57, 294),
    (725, 520, 323, 1568),
    (1079, 760, 513, 2352),
    (2141, 1480, 1083, 4704),
    (177, 120, 95, 392),
    (301, 200, 171, 672),
    (1045, 680, 627, 2352),
    (691, 440, 437, 1568),
    (257, 160, 171, 588),
    (2039, 1240, 1425, 4704),
    (337, 200, 247, 784),
    (2005, 1160, 1539, 4704),
    (71, 40, 57, 168),
    (657, 360, 551, 1568),
    (977, 520, 855, 2352),
    (1937, 1000, 1767, 4704),
    (20, 10, 19, 49),
    (1227, 638, 1075, 2940),
    (627, 338, 505, 1470),
    (61, 34, 45, 140),
    (327, 188, 220, 735),
    (267, 158, 163, 588),
    (227, 138, 125, 490),
    (1389, 866, 685, 2940),
    (354, 226, 155, 735),
    (481, 314, 185, 980),
    (3, 2, 1, 6),
    (471, 304, 161, 936),
    (237, 148, 83, 468),
    (53, 32, 19, 104),
    (60, 35, 22, 117),
    (483, 272, 181, 936),
    (81, 44, 31, 156),
    (489, 256, 191, 936),
    (123, 62, 49, 234),
    (165, 80, 67, 312),
    (249, 116, 103, 468),
    (501, 224, 211, 936),
    (7, 3, 3, 13),
    (43, 15, 20, 78),
    (22, 6, 11, 39),
    (15, 3, 8, 26),
    (23, 3, 13, 39),
    (47, 3, 28, 78),
    (8, 0, 5, 13),
    (7, 0, 4, 11),
    (21, 0, 10, 31),
    (13, 0, 5, 18),
    (13, 0, 5, 18),
];

const ZHOU_FANG_KEY_LEVELS: [u8; 10] = [0, 32, 64, 96, 112, 128, 144, 160, 192, 255];
const ZHOU_FANG_KEY_AMPLITUDES: [u8; 10] = [0, 87, 133, 163, 184, 199, 184, 163, 133, 87];

const fn zhou_fang_interp_u8(x: u16, x0: u16, y0: u16, x1: u16, y1: u16) -> u8 {
    if x1 <= x0 {
        return y0 as u8;
    }

    let dx = x1 - x0;
    let tx = x - x0;
    let dy = y1 as i32 - y0 as i32;
    let num = dy * tx as i32;
    let den = dx as i32;
    let delta = if num >= 0 {
        (num + den / 2) / den
    } else {
        (num - den / 2) / den
    };

    let value = y0 as i32 + delta;
    if value < 0 {
        0
    } else if value > 255 {
        255
    } else {
        value as u8
    }
}

const fn generate_zhou_fang_modulation() -> [u8; 256] {
    let mut out = [0_u8; 256];
    let mut i = 0_usize;

    while i < 256 {
        let x = i as u16;
        let mut seg = 0_usize;
        while seg + 1 < ZHOU_FANG_KEY_LEVELS.len() {
            let x0 = ZHOU_FANG_KEY_LEVELS[seg] as u16;
            let x1 = ZHOU_FANG_KEY_LEVELS[seg + 1] as u16;
            if x >= x0 && x <= x1 {
                let y0 = ZHOU_FANG_KEY_AMPLITUDES[seg] as u16;
                let y1 = ZHOU_FANG_KEY_AMPLITUDES[seg + 1] as u16;
                out[i] = zhou_fang_interp_u8(x, x0, y0, x1, y1);
                break;
            }
            seg += 1;
        }

        if seg + 1 == ZHOU_FANG_KEY_LEVELS.len() {
            out[i] = ZHOU_FANG_KEY_AMPLITUDES[ZHOU_FANG_KEY_AMPLITUDES.len() - 1];
        }

        i += 1;
    }

    out
}

pub const ZHOU_FANG_MODULATION: [u8; 256] = generate_zhou_fang_modulation();