Cargo Format

This commit is contained in:
2024-05-06 14:37:59 -05:00
parent 1ca0394d4a
commit aa18ba5992

View File

@@ -11,10 +11,10 @@ struct PixelRGBA {
} }
impl PixelRGBA { impl PixelRGBA {
fn new(r: u8, g: u8, b: u8, a: u8 ) -> Self { fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
Self {r, g, b, a } Self { r, g, b, a }
} }
fn zero() -> Self { fn zero() -> Self {
Self::new(0, 0, 0, 0) Self::new(0, 0, 0, 0)
} }
@@ -27,7 +27,7 @@ const QOI_OP_DIFF: u8 = 0b0100_0000;
const QOI_OP_LUMA: u8 = 0b1000_0000; const QOI_OP_LUMA: u8 = 0b1000_0000;
const QOI_OP_RUN: u8 = 0b1100_0000; const QOI_OP_RUN: u8 = 0b1100_0000;
struct Decoder<I: Iterator<Item=u8>> { struct Decoder<I: Iterator<Item = u8>> {
// QOI codec state information // QOI codec state information
back_buffer: [PixelRGBA; 64], back_buffer: [PixelRGBA; 64],
prev_pixel: PixelRGBA, prev_pixel: PixelRGBA,
@@ -36,7 +36,10 @@ struct Decoder<I: Iterator<Item=u8>> {
run_len: u8, run_len: u8,
} }
impl <I> Decoder <I> where I: Iterator<Item=u8> { impl<I> Decoder<I>
where
I: Iterator<Item = u8>,
{
fn new(bytes: I) -> Self { fn new(bytes: I) -> Self {
Self { Self {
back_buffer: [PixelRGBA::zero(); 64], back_buffer: [PixelRGBA::zero(); 64],
@@ -60,7 +63,10 @@ impl <I> Decoder <I> where I: Iterator<Item=u8> {
Self { Self {
back_buffer, back_buffer,
prev_pixel: PixelRGBA { prev_pixel: PixelRGBA {
r: 0, g: 0, b: 0, a: 255, r: 0,
g: 0,
b: 0,
a: 255,
}, },
bytes, bytes,
run_len: 0, run_len: 0,
@@ -91,7 +97,10 @@ mod codec_utils {
} }
} }
impl<'input, I> Iterator for Decoder<I> where I: Iterator<Item=u8> { impl<'input, I> Iterator for Decoder<I>
where
I: Iterator<Item = u8>,
{
type Item = PixelRGBA; type Item = PixelRGBA;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
@@ -99,65 +108,67 @@ impl<'input, I> Iterator for Decoder<I> where I: Iterator<Item=u8> {
self.run_len -= 1; self.run_len -= 1;
return Some(self.prev_pixel); return Some(self.prev_pixel);
} else { } else {
let byte = self.bytes.next()?; let byte = self.bytes.next()?;
match byte { match byte {
QOI_OP_RGB => { QOI_OP_RGB => {
return Some(PixelRGBA { return Some(PixelRGBA {
r: self.bytes.next()?, r: self.bytes.next()?,
g: self.bytes.next()?, g: self.bytes.next()?,
b: self.bytes.next()?, b: self.bytes.next()?,
a: self.prev_pixel.a, a: self.prev_pixel.a,
}); });
}, }
QOI_OP_RGBA => { QOI_OP_RGBA => {
return Some(PixelRGBA { return Some(PixelRGBA {
r: self.bytes.next()?, r: self.bytes.next()?,
g: self.bytes.next()?, g: self.bytes.next()?,
b: self.bytes.next()?, b: self.bytes.next()?,
a: self.bytes.next()?, a: self.bytes.next()?,
}); });
}, }
QOI_OP_INDEX => { QOI_OP_INDEX => {
let idx = (byte | 0b0011_1111) as usize; let idx = (byte | 0b0011_1111) as usize;
return Some(self.back_buffer[idx]); return Some(self.back_buffer[idx]);
}, }
QOI_OP_DIFF => { QOI_OP_DIFF => {
let dr = ((byte | 0b0011_0000) >> 4) - 2; let dr = ((byte | 0b0011_0000) >> 4) - 2;
let dg = ((byte | 0b0000_1100) >> 2) - 2; let dg = ((byte | 0b0000_1100) >> 2) - 2;
let db = (byte | 0b0000_0011) - 2; let db = (byte | 0b0000_0011) - 2;
return Some(PixelRGBA { return Some(PixelRGBA {
r: self.prev_pixel.r + dr, r: self.prev_pixel.r + dr,
g: self.prev_pixel.g + dg, g: self.prev_pixel.g + dg,
b: self.prev_pixel.b + db, b: self.prev_pixel.b + db,
a: self.prev_pixel.a a: self.prev_pixel.a,
}); });
}, }
QOI_OP_LUMA => { QOI_OP_LUMA => {
let dg = (byte | 0b0011_1111) - 32; let dg = (byte | 0b0011_1111) - 32;
let packed = self.bytes.next()?; let packed = self.bytes.next()?;
let drdg = ((packed | 0b1111_0000) >> 4) - 8; let drdg = ((packed | 0b1111_0000) >> 4) - 8;
let dbdg = (packed | 0b0000_1111) - 8; let dbdg = (packed | 0b0000_1111) - 8;
let dr = drdg + dg; let dr = drdg + dg;
let db = dbdg + dg; let db = dbdg + dg;
return Some(PixelRGBA { return Some(PixelRGBA {
r: self.prev_pixel.r + dr, r: self.prev_pixel.r + dr,
g: self.prev_pixel.g + dg, g: self.prev_pixel.g + dg,
b: self.prev_pixel.b + db, b: self.prev_pixel.b + db,
a: self.prev_pixel.a a: self.prev_pixel.a,
}); });
}, }
QOI_OP_RUN => { QOI_OP_RUN => {
self.run_len = byte | 0b0011_1111; self.run_len = byte | 0b0011_1111;
// storage bias of -1, so a +1 should be on the end here. // storage bias of -1, so a +1 should be on the end here.
// However, I'm immediately popping off the first occurrence // However, I'm immediately popping off the first occurrence
// and returning a PixelRGBA, so the count is also immediatly // and returning a PixelRGBA, so the count is also immediatly
// dropped by 1 // dropped by 1
return Some(self.prev_pixel); return Some(self.prev_pixel);
}, }
_ => {panic!("bad op code")} _ => {
panic!("bad op code")
}
}
} }
} }
}
} }
#[cfg(test)] #[cfg(test)]
@@ -181,15 +192,29 @@ mod test {
// compressed RGB values should be expanded back out to RGBA // compressed RGB values should be expanded back out to RGBA
// with an assumed alpha of 0xFF. // with an assumed alpha of 0xFF.
let compressed = [ let compressed = [
QOI_OP_RGB, 0xFF, 0xFF, 0xFF, QOI_OP_RGB, 0xFF, 0xFF, 0xFF, QOI_OP_RGB, 0x7F, 0x00, 0xAD, QOI_OP_RGB, 0x00, 0x00,
QOI_OP_RGB, 0x7F, 0x00, 0xAD, 0x00,
QOI_OP_RGB, 0x00, 0x00, 0x00
]; ];
let expected = [ let expected = [
PixelRGBA{ r: 0xFF, g: 0xFF, b: 0xFF, a: 0xFF}, PixelRGBA {
PixelRGBA{ r: 0x7F, g: 0x00, b: 0xAD, a: 0xFF}, r: 0xFF,
PixelRGBA{ r: 0x00, g: 0x00, b: 0x00, a: 0xFF} g: 0xFF,
b: 0xFF,
a: 0xFF,
},
PixelRGBA {
r: 0x7F,
g: 0x00,
b: 0xAD,
a: 0xFF,
},
PixelRGBA {
r: 0x00,
g: 0x00,
b: 0x00,
a: 0xFF,
},
]; ];
let decoder = Decoder::new(compressed.into_iter()); let decoder = Decoder::new(compressed.into_iter());
@@ -200,15 +225,42 @@ mod test {
#[test] #[test]
fn decoder_unpack_rgba() { fn decoder_unpack_rgba() {
let compressed = [ let compressed = [
QOI_OP_RGBA, 0xFF, 0xFF, 0xFF, 0xFF, QOI_OP_RGBA,
QOI_OP_RGBA, 0x7F, 0x7F, 0x7F, 0xFF, 0xFF,
QOI_OP_RGBA, 0x10, 0x20, 0x30, 0x40, 0xFF,
0xFF,
0xFF,
QOI_OP_RGBA,
0x7F,
0x7F,
0x7F,
0xFF,
QOI_OP_RGBA,
0x10,
0x20,
0x30,
0x40,
]; ];
let expected = [ let expected = [
PixelRGBA{ r: 0xFF, g: 0xFF, b: 0xFF, a: 0xFF }, PixelRGBA {
PixelRGBA{ r: 0x7f, g: 0x7f, b: 0x7f, a: 0xFF }, r: 0xFF,
PixelRGBA{ r: 0x10, g: 0x20, b: 0x30, a: 0x40 }, g: 0xFF,
b: 0xFF,
a: 0xFF,
},
PixelRGBA {
r: 0x7f,
g: 0x7f,
b: 0x7f,
a: 0xFF,
},
PixelRGBA {
r: 0x10,
g: 0x20,
b: 0x30,
a: 0x40,
},
]; ];
let decoder = Decoder::new(compressed.into_iter()); let decoder = Decoder::new(compressed.into_iter());
@@ -225,7 +277,7 @@ mod test {
backbuffer[3] = PixelRGBA::new(0, 0, 0, 0); backbuffer[3] = PixelRGBA::new(0, 0, 0, 0);
backbuffer[10] = PixelRGBA::new(10, 10, 10, 0); backbuffer[10] = PixelRGBA::new(10, 10, 10, 0);
backbuffer[11] = PixelRGBA::new(0xF0, 0x2C, 0xAF, 0xFF); backbuffer[11] = PixelRGBA::new(0xF0, 0x2C, 0xAF, 0xFF);
let compressed = [ let compressed = [
(QOI_OP_INDEX | 0), (QOI_OP_INDEX | 0),
(QOI_OP_INDEX | 11), (QOI_OP_INDEX | 11),
@@ -233,7 +285,7 @@ mod test {
(QOI_OP_INDEX | 2), (QOI_OP_INDEX | 2),
(QOI_OP_INDEX | 3), (QOI_OP_INDEX | 3),
(QOI_OP_INDEX | 10), (QOI_OP_INDEX | 10),
(QOI_OP_INDEX | 42) (QOI_OP_INDEX | 42),
]; ];
let expected = [ let expected = [
@@ -264,7 +316,7 @@ mod test {
(QOI_OP_DIFF | 0b0001_1001), // (-1, 0, -1) (QOI_OP_DIFF | 0b0001_1001), // (-1, 0, -1)
(QOI_OP_DIFF | 0b0000_0000), // (-2, -2, -2) (QOI_OP_DIFF | 0b0000_0000), // (-2, -2, -2)
]; ];
// the codec begins with a pixel at (0, 0, 0, 255), so these results // the codec begins with a pixel at (0, 0, 0, 255), so these results
// are diffs from that. // are diffs from that.
let expected = [ let expected = [
@@ -284,15 +336,18 @@ mod test {
#[test] #[test]
fn decoder_unpack_luma() { fn decoder_unpack_luma() {
// red and blue diffs are relative to the green channel as (dr - dg) and (db - dg) // red and blue diffs are relative to the green channel as (dr - dg) and (db - dg)
// Their finished diffs need to invert this operation. // Their finished diffs need to invert this operation.
// Diff(dg, dr-dg, db-dg) and Pix (dr, dg, db) // Diff(dg, dr-dg, db-dg) and Pix (dr, dg, db)
let compressed = [ let compressed = [
(QOI_OP_LUMA | 0b0011_1111), (0b1111_1111), // Diff( 31, 7, 7) -> Pix (38, 31, 38) (QOI_OP_LUMA | 0b0011_1111),
(QOI_OP_LUMA | 0b0011_0000), (0b1000_1000), // Diff( 0, 0, 0) -> Pix (0, 0, 0) (0b1111_1111), // Diff( 31, 7, 7) -> Pix (38, 31, 38)
(QOI_OP_LUMA | 0b0010_0001), (0b1111_1111), // Diff( 1, 7, 7) -> Pix (8, 1, 8) (QOI_OP_LUMA | 0b0011_0000),
(QOI_OP_LUMA | 0b0001_0011), (0b1100_0011), // Diff(-13, 4, -5) -> Pix (-9, -13, -18) (0b1000_1000), // Diff( 0, 0, 0) -> Pix (0, 0, 0)
(QOI_OP_LUMA | 0b0010_0001),
(0b1111_1111), // Diff( 1, 7, 7) -> Pix (8, 1, 8)
(QOI_OP_LUMA | 0b0001_0011),
(0b1100_0011), // Diff(-13, 4, -5) -> Pix (-9, -13, -18)
]; ];
let expected = [ let expected = [
@@ -313,14 +368,14 @@ mod test {
(QOI_OP_RUN | 0b0000_0000), // 1 -- bias of -1, so all zeros is a run of 1 pixel (QOI_OP_RUN | 0b0000_0000), // 1 -- bias of -1, so all zeros is a run of 1 pixel
(QOI_OP_RUN | 0b0000_1111), // 13 (QOI_OP_RUN | 0b0000_1111), // 13
]; ];
let init_pixel = PixelRGBA::new(50, 100, 150, 200); let init_pixel = PixelRGBA::new(50, 100, 150, 200);
let expected = [init_pixel; 14]; let expected = [init_pixel; 14];
// the run instructions should really have been collapsed into just one, but // the run instructions should really have been collapsed into just one, but
// lets pretend an encoder did this for some reason. The decoder can still // lets pretend an encoder did this for some reason. The decoder can still
// unpack this correctly, it's just a sub-optimal compression is all. // unpack this correctly, it's just a sub-optimal compression is all.
let decoder = Decoder::new_with_previous_pixel(compressed.into_iter(), init_pixel); let decoder = Decoder::new_with_previous_pixel(compressed.into_iter(), init_pixel);
let result: Vec<PixelRGBA> = decoder.collect(); let result: Vec<PixelRGBA> = decoder.collect();
assert_eq!(result, expected); assert_eq!(result, expected);