The codec library doesn't use any external dependencies. The PNG crate is only to load some source material for testing the codec. Turning the test driver into a real test lets me turn the PNG dependency into a dev-dependency.
92 lines
2.8 KiB
Rust
92 lines
2.8 KiB
Rust
|
|
use qoicodec::DecodeError;
|
|
use qoicodec::Decoder;
|
|
use qoicodec::PixelRGBA;
|
|
|
|
use std::io::BufWriter;
|
|
use std::path::Path;
|
|
use std::{fs::File, io::Read};
|
|
|
|
#[test]
|
|
fn main() -> Result<(), DecodeError> {
|
|
let file = File::open("qoi_test_images/dice.qoi").unwrap();
|
|
let mut bytes = file.bytes()
|
|
.map(|maybe_bytes|
|
|
{
|
|
match maybe_bytes {
|
|
Ok(byte) => byte,
|
|
Err(oops) => panic!("Oops, the file failed to load: {}", oops)
|
|
}
|
|
});
|
|
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);
|
|
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
|
|
}
|
|
}
|
|
}
|