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
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
png = "0.17.14"
|
||||||
|
|||||||
81
src/main.rs
81
src/main.rs
@@ -1,9 +1,13 @@
|
|||||||
|
|
||||||
use qoicodec::DecodeError;
|
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};
|
use std::{fs::File, io::Read};
|
||||||
|
|
||||||
fn main() {
|
fn main() -> Result<(), DecodeError> {
|
||||||
let file = File::open("qoi_test_images/dice.qoi").unwrap();
|
let file = File::open("qoi_test_images/dice.qoi").unwrap();
|
||||||
let mut bytes = file.bytes()
|
let mut bytes = file.bytes()
|
||||||
.map(|maybe_bytes|
|
.map(|maybe_bytes|
|
||||||
@@ -13,13 +17,74 @@ fn main() {
|
|||||||
Err(oops) => panic!("Oops, the file failed to load: {}", oops)
|
Err(oops) => panic!("Oops, the file failed to load: {}", oops)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if let Err(e) = try_read_magic(&mut bytes) {
|
let decoder = Decoder::try_new(bytes)?;
|
||||||
match e {
|
|
||||||
DecodeError::Magic => panic!("QOI Magic bytes are bad!"),
|
let test_out_path = Path::new("test_output.png");
|
||||||
DecodeError::EarlyIteratorExhaustion => panic!("File iterator exhausted earlier than expected."),
|
let file = File::create(test_out_path).unwrap();
|
||||||
_ => panic!("Unhandled error reading magic: {:?}", e),
|
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()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
todo!("The rest of the main function");
|
// 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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user