Add PNG write-out machinery
I've pulled in the PNG crate to write the images back out as regular PNG images. Now I can compare the results of my decoder against the reference images. I also made a weird utility iterator thing to wrap the Decoder's pixel iterator because the PNG crate wants a &[u8], not a bunch of u32's or custom pixels structs. I should learn how to impl the right traits so that I can just `.to_components()` on an Iterator<Item=PixelRGBA> instead of the wrapper constructor thing I have now.
This commit is contained in:
@@ -6,3 +6,4 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
png = "0.17.14"
|
||||
|
||||
83
src/main.rs
83
src/main.rs
@@ -1,9 +1,13 @@
|
||||
|
||||
use qoicodec::DecodeError;
|
||||
use qoicodec::try_read_magic;
|
||||
use qoicodec::Decoder;
|
||||
use qoicodec::PixelRGBA;
|
||||
|
||||
use std::io::BufWriter;
|
||||
use std::path::Path;
|
||||
use std::{fs::File, io::Read};
|
||||
|
||||
fn main() {
|
||||
fn main() -> Result<(), DecodeError> {
|
||||
let file = File::open("qoi_test_images/dice.qoi").unwrap();
|
||||
let mut bytes = file.bytes()
|
||||
.map(|maybe_bytes|
|
||||
@@ -13,13 +17,74 @@ fn main() {
|
||||
Err(oops) => panic!("Oops, the file failed to load: {}", oops)
|
||||
}
|
||||
});
|
||||
if let Err(e) = try_read_magic(&mut bytes) {
|
||||
match e {
|
||||
DecodeError::Magic => panic!("QOI Magic bytes are bad!"),
|
||||
DecodeError::EarlyIteratorExhaustion => panic!("File iterator exhausted earlier than expected."),
|
||||
_ => panic!("Unhandled error reading magic: {:?}", e),
|
||||
let decoder = Decoder::try_new(bytes)?;
|
||||
|
||||
let test_out_path = Path::new("test_output.png");
|
||||
let file = File::create(test_out_path).unwrap();
|
||||
let ref mut w = BufWriter::new(file);
|
||||
|
||||
let mut encoder = png::Encoder::new(w, decoder.width, decoder.height);
|
||||
encoder.set_color(match decoder.channels {
|
||||
3 => png::ColorType::Rgb,
|
||||
4 => png::ColorType::Rgba,
|
||||
_ => panic!("Bad colorspace in qoicodec::Decoder!")
|
||||
});
|
||||
encoder.set_depth(png::BitDepth::Eight);
|
||||
encoder.set_source_gamma(png::ScaledFloat::from_scaled(45455));
|
||||
encoder.set_source_gamma(png::ScaledFloat::new(1.0 / 2.2));
|
||||
let source_chromaticities = png::SourceChromaticities::new(
|
||||
(0.31270, 0.32900),
|
||||
(0.64000, 0.33000),
|
||||
(0.30000, 0.60000),
|
||||
(0.15000, 0.06000),
|
||||
);
|
||||
encoder.set_source_chromaticities(source_chromaticities);
|
||||
let mut writer = encoder.write_header().unwrap();
|
||||
|
||||
let data: Vec<u8> = PixelIterExpander::try_new(decoder).unwrap().collect();
|
||||
let result = writer.write_image_data(&data[0..(data.len()-32)]);
|
||||
if let Err(res) = result {
|
||||
eprintln!("{}", res);
|
||||
}
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
struct PixelIterExpander <I: Iterator<Item = qoicodec::PixelRGBA>> {
|
||||
wrapped_iterator: I,
|
||||
current_pixel: qoicodec::PixelRGBA,
|
||||
color_element_idx: u8,
|
||||
}
|
||||
|
||||
impl <I: std::iter::Iterator<Item = PixelRGBA>> PixelIterExpander <I> {
|
||||
fn try_new(mut pixels: I) -> Option<Self> {
|
||||
let px = pixels.next()?;
|
||||
|
||||
Some(Self {
|
||||
wrapped_iterator: pixels,
|
||||
current_pixel: px,
|
||||
color_element_idx: 0,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl <I: Iterator<Item=PixelRGBA>> Iterator for PixelIterExpander<I> {
|
||||
type Item = u8;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
// at index 4, reset counter and get next pixel
|
||||
if self.color_element_idx == 4 {
|
||||
self.color_element_idx = 0;
|
||||
self.current_pixel = self.wrapped_iterator.next()?;
|
||||
}
|
||||
|
||||
// increment pixel value, match over index and return that byte
|
||||
self.color_element_idx += 1;
|
||||
match self.color_element_idx {
|
||||
1 => Some(self.current_pixel.r),
|
||||
2 => Some(self.current_pixel.g),
|
||||
3 => Some(self.current_pixel.b),
|
||||
4 => Some(self.current_pixel.a),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
todo!("The rest of the main function");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user