use byteorder::{BigEndian, ByteOrder};
use hkdf::Hkdf;
use sha2::{Sha256};
const COLOURS: [[u8; 3]; 16] = [
[0, 0, 0], [194, 54, 33], [37, 188, 36], [173, 173, 39], [73, 46, 225], [211, 56, 211], [51, 187, 200], [203, 204, 205], [129, 131, 131], [252, 57, 31], [49, 231, 34], [234, 236, 35], [88, 51, 255], [249, 53, 248], [20, 240, 240], [233, 235, 235], ];
pub struct Mozaic {
data: [u8; 32],
}
impl Mozaic {
pub fn new(data: &[u8]) -> Self {
let mut moz = Mozaic { data: [0u8; 32] };
let hk = Hkdf::<Sha256>::new(None, &data);
hk.expand(&[0u8; 0], &mut moz.data)
.expect("hkdf to provide 32 bytes");
return moz;
}
pub fn ansi(&self) -> String {
let rows = 8;
let mut output = "".to_string();
let mut u16buf = [0u8; 2];
for i in 0..32 {
if i % rows == 0 && i != 0 {
output += "\r\n"
} else if i % 2 == 1 && i != 0 {
let (l, r) = split_byte(&mut u16buf, self.data[i]);
output += &(ansi_rgb(l) + " " + &(ansi_rgb(r) + &" \x1b[0m "));
continue;
}
let (l, r) = split_byte(&mut u16buf, self.data[i]);
output += &(ansi_rgb(l) + " " + &(ansi_rgb(r)) + " \x1b[0m");
}
return output + "\x1b[0m";
}
}
fn split_byte(u16buf: &mut [u8; 2], b: u8) -> ([u8; 3], [u8; 3]) {
let l = b >> 4;
let r = b << 4 >> 4;
u16buf[1] = l;
let li = (BigEndian::read_u16(u16buf)) as usize;
u16buf[1] = r;
let ri = (BigEndian::read_u16(u16buf)) as usize;
return (COLOURS[li], COLOURS[ri]);
}
fn ansi_rgb(rgb: [u8; 3]) -> String {
return format!(
"\x1b[38;2;{};{};{};48;2;{};{};{}m",
rgb[0], rgb[1], rgb[2], rgb[0], rgb[1], rgb[2]
);
}