type Rgb = (u8, u8, u8);
pub static ACI_COLORS: [Rgb; 256] = [
(0, 0, 0),
(255, 0, 0), (255, 255, 0), (0, 255, 0), (0, 255, 255), (0, 0, 255), (255, 0, 255), (255, 255, 255), (128, 128, 128), (192, 192, 192), (255, 0, 0), (255, 127, 127), (204, 0, 0), (204, 102, 102), (153, 0, 0), (153, 76, 76), (127, 0, 0), (127, 63, 63), (76, 0, 0), (76, 38, 38), (255, 63, 0), (255, 159, 127), (204, 51, 0), (204, 127, 102), (153, 38, 0), (153, 95, 76), (127, 31, 0), (127, 79, 63), (76, 19, 0), (76, 47, 38), (255, 127, 0), (255, 191, 127), (204, 102, 0), (204, 153, 102), (153, 76, 0), (153, 114, 76), (127, 63, 0), (127, 95, 63), (76, 38, 0), (76, 57, 38), (255, 191, 0), (255, 223, 127), (204, 153, 0), (204, 178, 102), (153, 114, 0), (153, 133, 76), (127, 95, 0), (127, 111, 63), (76, 57, 0), (76, 66, 38), (255, 255, 0), (255, 255, 127), (204, 204, 0), (204, 204, 102), (153, 153, 0), (153, 153, 76), (127, 127, 0), (127, 127, 63), (76, 76, 0), (76, 76, 38), (191, 255, 0), (223, 255, 127), (153, 204, 0), (178, 204, 102), (114, 153, 0), (133, 153, 76), (95, 127, 0), (111, 127, 63), (57, 76, 0), (66, 76, 38), (127, 255, 0), (191, 255, 127), (102, 204, 0), (153, 204, 102), (76, 153, 0), (114, 153, 76), (63, 127, 0), (95, 127, 63), (38, 76, 0), (57, 76, 38), (63, 255, 0), (159, 255, 127), (51, 204, 0), (127, 204, 102), (38, 153, 0), (95, 153, 76), (31, 127, 0), (79, 127, 63), (19, 76, 0), (47, 76, 38), (0, 255, 0), (127, 255, 127), (0, 204, 0), (102, 204, 102), (0, 153, 0), (76, 153, 76), (0, 127, 0), (63, 127, 63), (0, 76, 0), (38, 76, 38), (0, 255, 63), (127, 255, 159), (0, 204, 51), (102, 204, 127), (0, 153, 38), (76, 153, 95), (0, 127, 31), (63, 127, 79), (0, 76, 19), (38, 76, 47), (0, 255, 127), (127, 255, 191), (0, 204, 102), (102, 204, 153), (0, 153, 76), (76, 153, 114), (0, 127, 63), (63, 127, 95), (0, 76, 38), (38, 76, 57), (0, 255, 191), (127, 255, 223), (0, 204, 153), (102, 204, 178), (0, 153, 114), (76, 153, 133), (0, 127, 95), (63, 127, 111), (0, 76, 57), (38, 76, 66), (0, 255, 255), (127, 255, 255), (0, 204, 204), (102, 204, 204), (0, 153, 153), (76, 153, 153), (0, 127, 127), (63, 127, 127), (0, 76, 76), (38, 76, 76), (0, 191, 255), (127, 223, 255), (0, 153, 204), (102, 178, 204), (0, 114, 153), (76, 133, 153), (0, 95, 127), (63, 111, 127), (0, 57, 76), (38, 66, 76), (0, 127, 255), (127, 191, 255), (0, 102, 204), (102, 153, 204), (0, 76, 153), (76, 114, 153), (0, 63, 127), (63, 95, 127), (0, 38, 76), (38, 57, 76), (0, 63, 255), (127, 159, 255), (0, 51, 204), (102, 127, 204), (0, 38, 153), (76, 95, 153), (0, 31, 127), (63, 79, 127), (0, 19, 76), (38, 47, 76), (0, 0, 255), (127, 127, 255), (0, 0, 204), (102, 102, 204), (0, 0, 153), (76, 76, 153), (0, 0, 127), (63, 63, 127), (0, 0, 76), (38, 38, 76), (63, 0, 255), (159, 127, 255), (51, 0, 204), (127, 102, 204), (38, 0, 153), (95, 76, 153), (31, 0, 127), (79, 63, 127), (19, 0, 76), (47, 38, 76), (127, 0, 255), (191, 127, 255), (102, 0, 204), (153, 102, 204), (76, 0, 153), (114, 76, 153), (63, 0, 127), (95, 63, 127), (38, 0, 76), (57, 38, 76), (191, 0, 255), (223, 127, 255), (153, 0, 204), (178, 102, 204), (114, 0, 153), (133, 76, 153), (95, 0, 127), (111, 63, 127), (57, 0, 76), (66, 38, 76), (255, 0, 255), (255, 127, 255), (204, 0, 204), (204, 102, 204), (153, 0, 153), (153, 76, 153), (127, 0, 127), (127, 63, 127), (76, 0, 76), (76, 38, 76), (255, 0, 191), (255, 127, 223), (204, 0, 153), (204, 102, 178), (153, 0, 114), (153, 76, 133), (127, 0, 95), (127, 63, 111), (76, 0, 57), (76, 38, 66), (255, 0, 127), (255, 127, 191), (204, 0, 102), (204, 102, 153), (153, 0, 76), (153, 76, 114), (127, 0, 63), (127, 63, 95), (76, 0, 38), (76, 38, 57), (255, 0, 63), (255, 127, 159), (204, 0, 51), (204, 102, 127), (153, 0, 38), (153, 76, 95), (127, 0, 31), (127, 63, 79), (76, 0, 19), (76, 38, 47), (51, 51, 51), (91, 91, 91), (132, 132, 132), (173, 173, 173), (214, 214, 214), (255, 255, 255), ];
#[inline]
pub fn aci_to_rgb(index: u8) -> Option<(u8, u8, u8)> {
if index == 0 {
None
} else {
Some(ACI_COLORS[index as usize])
}
}
pub fn nearest_aci(r: u8, g: u8, b: u8) -> u8 {
let mut best_idx: u8 = 7;
let mut best_dist = u32::MAX;
for i in 1u16..=255 {
let (cr, cg, cb) = ACI_COLORS[i as usize];
let dr = (r as i32) - (cr as i32);
let dg = (g as i32) - (cg as i32);
let db = (b as i32) - (cb as i32);
let dist = (dr * dr + dg * dg + db * db) as u32;
if dist < best_dist {
best_dist = dist;
best_idx = i as u8;
if dist == 0 {
break;
}
}
}
best_idx
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn aci_standard_colors() {
assert_eq!(aci_to_rgb(1), Some((255, 0, 0))); assert_eq!(aci_to_rgb(2), Some((255, 255, 0))); assert_eq!(aci_to_rgb(3), Some((0, 255, 0))); assert_eq!(aci_to_rgb(4), Some((0, 255, 255))); assert_eq!(aci_to_rgb(5), Some((0, 0, 255))); assert_eq!(aci_to_rgb(6), Some((255, 0, 255))); assert_eq!(aci_to_rgb(7), Some((255, 255, 255))); }
#[test]
fn aci_byblock_returns_none() {
assert_eq!(aci_to_rgb(0), None);
}
#[test]
fn nearest_aci_exact_match() {
assert_eq!(nearest_aci(255, 0, 0), 1); assert_eq!(nearest_aci(0, 255, 0), 3); assert_eq!(nearest_aci(0, 0, 255), 5); assert_eq!(nearest_aci(255, 255, 0), 2); }
#[test]
fn nearest_aci_approximate() {
let idx = nearest_aci(250, 5, 5);
assert_eq!(idx, 1);
}
#[test]
fn table_length() {
assert_eq!(ACI_COLORS.len(), 256);
}
#[test]
fn grays_are_correct() {
assert_eq!(aci_to_rgb(8), Some((128, 128, 128))); assert_eq!(aci_to_rgb(9), Some((192, 192, 192))); assert_eq!(aci_to_rgb(250), Some((51, 51, 51)));
assert_eq!(aci_to_rgb(255), Some((255, 255, 255)));
}
}