Cargo Format
This commit is contained in:
217
src/main.rs
217
src/main.rs
@@ -11,8 +11,8 @@ struct PixelRGBA {
|
||||
}
|
||||
|
||||
impl PixelRGBA {
|
||||
fn new(r: u8, g: u8, b: u8, a: u8 ) -> Self {
|
||||
Self {r, g, b, a }
|
||||
fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
|
||||
Self { r, g, b, a }
|
||||
}
|
||||
|
||||
fn zero() -> Self {
|
||||
@@ -27,7 +27,7 @@ const QOI_OP_DIFF: u8 = 0b0100_0000;
|
||||
const QOI_OP_LUMA: u8 = 0b1000_0000;
|
||||
const QOI_OP_RUN: u8 = 0b1100_0000;
|
||||
|
||||
struct Decoder<I: Iterator<Item=u8>> {
|
||||
struct Decoder<I: Iterator<Item = u8>> {
|
||||
// QOI codec state information
|
||||
back_buffer: [PixelRGBA; 64],
|
||||
prev_pixel: PixelRGBA,
|
||||
@@ -36,7 +36,10 @@ struct Decoder<I: Iterator<Item=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 {
|
||||
Self {
|
||||
back_buffer: [PixelRGBA::zero(); 64],
|
||||
@@ -60,7 +63,10 @@ impl <I> Decoder <I> where I: Iterator<Item=u8> {
|
||||
Self {
|
||||
back_buffer,
|
||||
prev_pixel: PixelRGBA {
|
||||
r: 0, g: 0, b: 0, a: 255,
|
||||
r: 0,
|
||||
g: 0,
|
||||
b: 0,
|
||||
a: 255,
|
||||
},
|
||||
bytes,
|
||||
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;
|
||||
|
||||
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;
|
||||
return Some(self.prev_pixel);
|
||||
} else {
|
||||
let byte = self.bytes.next()?;
|
||||
match byte {
|
||||
QOI_OP_RGB => {
|
||||
return Some(PixelRGBA {
|
||||
r: self.bytes.next()?,
|
||||
g: self.bytes.next()?,
|
||||
b: self.bytes.next()?,
|
||||
a: self.prev_pixel.a,
|
||||
});
|
||||
},
|
||||
QOI_OP_RGBA => {
|
||||
return Some(PixelRGBA {
|
||||
r: self.bytes.next()?,
|
||||
g: self.bytes.next()?,
|
||||
b: self.bytes.next()?,
|
||||
a: self.bytes.next()?,
|
||||
});
|
||||
},
|
||||
QOI_OP_INDEX => {
|
||||
let idx = (byte | 0b0011_1111) as usize;
|
||||
return Some(self.back_buffer[idx]);
|
||||
},
|
||||
QOI_OP_DIFF => {
|
||||
let dr = ((byte | 0b0011_0000) >> 4) - 2;
|
||||
let dg = ((byte | 0b0000_1100) >> 2) - 2;
|
||||
let db = (byte | 0b0000_0011) - 2;
|
||||
return Some(PixelRGBA {
|
||||
r: self.prev_pixel.r + dr,
|
||||
g: self.prev_pixel.g + dg,
|
||||
b: self.prev_pixel.b + db,
|
||||
a: self.prev_pixel.a
|
||||
});
|
||||
},
|
||||
QOI_OP_LUMA => {
|
||||
let dg = (byte | 0b0011_1111) - 32;
|
||||
let packed = self.bytes.next()?;
|
||||
let drdg = ((packed | 0b1111_0000) >> 4) - 8;
|
||||
let dbdg = (packed | 0b0000_1111) - 8;
|
||||
let dr = drdg + dg;
|
||||
let db = dbdg + dg;
|
||||
return Some(PixelRGBA {
|
||||
r: self.prev_pixel.r + dr,
|
||||
g: self.prev_pixel.g + dg,
|
||||
b: self.prev_pixel.b + db,
|
||||
a: self.prev_pixel.a
|
||||
});
|
||||
},
|
||||
QOI_OP_RUN => {
|
||||
self.run_len = byte | 0b0011_1111;
|
||||
// storage bias of -1, so a +1 should be on the end here.
|
||||
// However, I'm immediately popping off the first occurrence
|
||||
// and returning a PixelRGBA, so the count is also immediatly
|
||||
// dropped by 1
|
||||
return Some(self.prev_pixel);
|
||||
},
|
||||
_ => {panic!("bad op code")}
|
||||
let byte = self.bytes.next()?;
|
||||
match byte {
|
||||
QOI_OP_RGB => {
|
||||
return Some(PixelRGBA {
|
||||
r: self.bytes.next()?,
|
||||
g: self.bytes.next()?,
|
||||
b: self.bytes.next()?,
|
||||
a: self.prev_pixel.a,
|
||||
});
|
||||
}
|
||||
QOI_OP_RGBA => {
|
||||
return Some(PixelRGBA {
|
||||
r: self.bytes.next()?,
|
||||
g: self.bytes.next()?,
|
||||
b: self.bytes.next()?,
|
||||
a: self.bytes.next()?,
|
||||
});
|
||||
}
|
||||
QOI_OP_INDEX => {
|
||||
let idx = (byte | 0b0011_1111) as usize;
|
||||
return Some(self.back_buffer[idx]);
|
||||
}
|
||||
QOI_OP_DIFF => {
|
||||
let dr = ((byte | 0b0011_0000) >> 4) - 2;
|
||||
let dg = ((byte | 0b0000_1100) >> 2) - 2;
|
||||
let db = (byte | 0b0000_0011) - 2;
|
||||
return Some(PixelRGBA {
|
||||
r: self.prev_pixel.r + dr,
|
||||
g: self.prev_pixel.g + dg,
|
||||
b: self.prev_pixel.b + db,
|
||||
a: self.prev_pixel.a,
|
||||
});
|
||||
}
|
||||
QOI_OP_LUMA => {
|
||||
let dg = (byte | 0b0011_1111) - 32;
|
||||
let packed = self.bytes.next()?;
|
||||
let drdg = ((packed | 0b1111_0000) >> 4) - 8;
|
||||
let dbdg = (packed | 0b0000_1111) - 8;
|
||||
let dr = drdg + dg;
|
||||
let db = dbdg + dg;
|
||||
return Some(PixelRGBA {
|
||||
r: self.prev_pixel.r + dr,
|
||||
g: self.prev_pixel.g + dg,
|
||||
b: self.prev_pixel.b + db,
|
||||
a: self.prev_pixel.a,
|
||||
});
|
||||
}
|
||||
QOI_OP_RUN => {
|
||||
self.run_len = byte | 0b0011_1111;
|
||||
// storage bias of -1, so a +1 should be on the end here.
|
||||
// However, I'm immediately popping off the first occurrence
|
||||
// and returning a PixelRGBA, so the count is also immediatly
|
||||
// dropped by 1
|
||||
return Some(self.prev_pixel);
|
||||
}
|
||||
_ => {
|
||||
panic!("bad op code")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -181,15 +192,29 @@ mod test {
|
||||
// compressed RGB values should be expanded back out to RGBA
|
||||
// with an assumed alpha of 0xFF.
|
||||
let compressed = [
|
||||
QOI_OP_RGB, 0xFF, 0xFF, 0xFF,
|
||||
QOI_OP_RGB, 0x7F, 0x00, 0xAD,
|
||||
QOI_OP_RGB, 0x00, 0x00, 0x00
|
||||
QOI_OP_RGB, 0xFF, 0xFF, 0xFF, QOI_OP_RGB, 0x7F, 0x00, 0xAD, QOI_OP_RGB, 0x00, 0x00,
|
||||
0x00,
|
||||
];
|
||||
|
||||
let expected = [
|
||||
PixelRGBA{ r: 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}
|
||||
PixelRGBA {
|
||||
r: 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());
|
||||
@@ -200,15 +225,42 @@ mod test {
|
||||
#[test]
|
||||
fn decoder_unpack_rgba() {
|
||||
let compressed = [
|
||||
QOI_OP_RGBA, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
QOI_OP_RGBA, 0x7F, 0x7F, 0x7F, 0xFF,
|
||||
QOI_OP_RGBA, 0x10, 0x20, 0x30, 0x40,
|
||||
QOI_OP_RGBA,
|
||||
0xFF,
|
||||
0xFF,
|
||||
0xFF,
|
||||
0xFF,
|
||||
QOI_OP_RGBA,
|
||||
0x7F,
|
||||
0x7F,
|
||||
0x7F,
|
||||
0xFF,
|
||||
QOI_OP_RGBA,
|
||||
0x10,
|
||||
0x20,
|
||||
0x30,
|
||||
0x40,
|
||||
];
|
||||
|
||||
let expected = [
|
||||
PixelRGBA{ r: 0xFF, g: 0xFF, b: 0xFF, a: 0xFF },
|
||||
PixelRGBA{ r: 0x7f, g: 0x7f, b: 0x7f, a: 0xFF },
|
||||
PixelRGBA{ r: 0x10, g: 0x20, b: 0x30, a: 0x40 },
|
||||
PixelRGBA {
|
||||
r: 0xFF,
|
||||
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());
|
||||
@@ -233,7 +285,7 @@ mod test {
|
||||
(QOI_OP_INDEX | 2),
|
||||
(QOI_OP_INDEX | 3),
|
||||
(QOI_OP_INDEX | 10),
|
||||
(QOI_OP_INDEX | 42)
|
||||
(QOI_OP_INDEX | 42),
|
||||
];
|
||||
|
||||
let expected = [
|
||||
@@ -284,15 +336,18 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn decoder_unpack_luma() {
|
||||
|
||||
// red and blue diffs are relative to the green channel as (dr - dg) and (db - dg)
|
||||
// Their finished diffs need to invert this operation.
|
||||
// Diff(dg, dr-dg, db-dg) and Pix (dr, dg, db)
|
||||
let compressed = [
|
||||
(QOI_OP_LUMA | 0b0011_1111), (0b1111_1111), // Diff( 31, 7, 7) -> Pix (38, 31, 38)
|
||||
(QOI_OP_LUMA | 0b0011_0000), (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)
|
||||
(QOI_OP_LUMA | 0b0011_1111),
|
||||
(0b1111_1111), // Diff( 31, 7, 7) -> Pix (38, 31, 38)
|
||||
(QOI_OP_LUMA | 0b0011_0000),
|
||||
(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 = [
|
||||
|
||||
Reference in New Issue
Block a user