diff --git a/Cargo.toml b/Cargo.toml index e1d31dc..3adc72d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/src/main.rs b/src/main.rs index 8abf080..baf60e7 100644 --- a/src/main.rs +++ b/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 = 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 > { + wrapped_iterator: I, + current_pixel: qoicodec::PixelRGBA, + color_element_idx: u8, +} + +impl > PixelIterExpander { + fn try_new(mut pixels: I) -> Option { + let px = pixels.next()?; + + Some(Self { + wrapped_iterator: pixels, + current_pixel: px, + color_element_idx: 0, + }) + } +} + +impl > Iterator for PixelIterExpander { + type Item = u8; + + fn next(&mut self) -> Option { + // 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"); }