use crate::shared::*;
pub fn decode_qoi<'a>(data: &'a [u8]) -> Option<(Header, Vec<u8>, &'a [u8])> {
let (head, mut data) = read_header(data)?;
let decoded_size = (head.height * head.width * 4) as usize;
let mut pxlbuffer = Vec::with_capacity(decoded_size);
let mut colorhashes = [(0u8, 0u8, 0u8, 0u8); 64];
let mut last_pxl = (0u8, 0u8, 0u8, 255u8);
while pxlbuffer.len() < decoded_size {
let (rest, part) = Part::decode(&data)?;
data = rest;
match part {
Part::RGBA(r,g,b,a) => {
pxlbuffer.push(r);
pxlbuffer.push(g);
pxlbuffer.push(b);
pxlbuffer.push(a);
add_hash_and_last(r, g, b, a, &mut colorhashes, &mut last_pxl);
}
Part::RGB(r,g,b) => {
pxlbuffer.push(r);
pxlbuffer.push(g);
pxlbuffer.push(b);
pxlbuffer.push(last_pxl.3);
add_hash_and_last(r, g, b, last_pxl.3, &mut colorhashes, &mut last_pxl);
}
Part::Run(runlen) => {
add_hash_and_last(last_pxl.0, last_pxl.1, last_pxl.2, last_pxl.3, &mut colorhashes, &mut last_pxl);
for _ in 0..runlen {
pxlbuffer.push(last_pxl.0);
pxlbuffer.push(last_pxl.1);
pxlbuffer.push(last_pxl.2);
pxlbuffer.push(last_pxl.3);
}
}
Part::LumaDiff(drdg, dg, dbdg) => {
let dr = drdg + dg;
let db = dbdg + dg;
let r = (last_pxl.0 as i8).wrapping_add(dr) as u8;
let g = (last_pxl.1 as i8).wrapping_add(dg) as u8;
let b = (last_pxl.2 as i8).wrapping_add(db) as u8;
pxlbuffer.push(r);
pxlbuffer.push(g);
pxlbuffer.push(b);
pxlbuffer.push(last_pxl.3);
add_hash_and_last(r, g, b, last_pxl.3, &mut colorhashes, &mut last_pxl);
}
Part::SmallDiff(dr, dg, db) => {
let r = (last_pxl.0 as i8).wrapping_add(dr) as u8;
let g = (last_pxl.1 as i8).wrapping_add(dg) as u8;
let b = (last_pxl.2 as i8).wrapping_add(db) as u8;
pxlbuffer.push(r);
pxlbuffer.push(g);
pxlbuffer.push(b);
pxlbuffer.push(last_pxl.3);
add_hash_and_last(r, g, b, last_pxl.3, &mut colorhashes, &mut last_pxl);
}
Part::Idx(index) => {
let pxl = colorhashes[index as usize];
pxlbuffer.push(pxl.0);
pxlbuffer.push(pxl.1);
pxlbuffer.push(pxl.2);
pxlbuffer.push(pxl.3);
add_hash_and_last(pxl.0, pxl.1, pxl.2, pxl.3, &mut colorhashes, &mut last_pxl);
}
}
}
Some((head, pxlbuffer, data))
}