Files
qoicodec/tests/codec.rs
Robert Garrett e31aa5decb Move main.rs to a test, drop dep on png crate
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.
2025-10-12 21:18:32 -05:00

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
}
}
}