From 1b6a04ca5504955c571d1c97504fb45ea0befee4 Mon Sep 17 00:00:00 2001 From: Valentin Popov Date: Mon, 8 Jan 2024 01:21:28 +0400 Subject: Initial vendor packages Signed-off-by: Valentin Popov --- vendor/image/src/codecs/qoi.rs | 104 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 vendor/image/src/codecs/qoi.rs (limited to 'vendor/image/src/codecs/qoi.rs') diff --git a/vendor/image/src/codecs/qoi.rs b/vendor/image/src/codecs/qoi.rs new file mode 100644 index 0000000..214e99b --- /dev/null +++ b/vendor/image/src/codecs/qoi.rs @@ -0,0 +1,104 @@ +//! Decoding and encoding of QOI images + +use crate::{ + error::{DecodingError, EncodingError}, + ColorType, ImageDecoder, ImageEncoder, ImageError, ImageFormat, ImageResult, +}; +use std::io::{Cursor, Read, Write}; + +/// QOI decoder +pub struct QoiDecoder { + decoder: qoi::Decoder, +} + +impl QoiDecoder +where + R: Read, +{ + /// Creates a new decoder that decodes from the stream ```reader``` + pub fn new(reader: R) -> ImageResult { + let decoder = qoi::Decoder::from_stream(reader).map_err(decoding_error)?; + Ok(Self { decoder }) + } +} + +impl<'a, R: Read + 'a> ImageDecoder<'a> for QoiDecoder { + type Reader = Cursor>; + + fn dimensions(&self) -> (u32, u32) { + (self.decoder.header().width, self.decoder.header().height) + } + + fn color_type(&self) -> ColorType { + match self.decoder.header().channels { + qoi::Channels::Rgb => ColorType::Rgb8, + qoi::Channels::Rgba => ColorType::Rgba8, + } + } + + fn into_reader(mut self) -> ImageResult { + let buffer = self.decoder.decode_to_vec().map_err(decoding_error)?; + Ok(Cursor::new(buffer)) + } +} + +fn decoding_error(error: qoi::Error) -> ImageError { + ImageError::Decoding(DecodingError::new(ImageFormat::Qoi.into(), error)) +} + +fn encoding_error(error: qoi::Error) -> ImageError { + ImageError::Encoding(EncodingError::new(ImageFormat::Qoi.into(), error)) +} + +/// QOI encoder +pub struct QoiEncoder { + writer: W, +} + +impl QoiEncoder { + /// Creates a new encoder that writes its output to ```writer``` + pub fn new(writer: W) -> Self { + Self { writer } + } +} + +impl ImageEncoder for QoiEncoder { + fn write_image( + mut self, + buf: &[u8], + width: u32, + height: u32, + color_type: ColorType, + ) -> ImageResult<()> { + if !matches!(color_type, ColorType::Rgba8 | ColorType::Rgb8) { + return Err(ImageError::Encoding(EncodingError::new( + ImageFormat::Qoi.into(), + format!("unsupported color type {color_type:?}. Supported are Rgba8 and Rgb8."), + ))); + } + + // Encode data in QOI + let data = qoi::encode_to_vec(buf, width, height).map_err(encoding_error)?; + + // Write data to buffer + self.writer.write_all(&data[..])?; + self.writer.flush()?; + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::fs::File; + + #[test] + fn decode_test_image() { + let decoder = QoiDecoder::new(File::open("tests/images/qoi/basic-test.qoi").unwrap()) + .expect("Unable to read QOI file"); + + assert_eq!((5, 5), decoder.dimensions()); + assert_eq!(ColorType::Rgba8, decoder.color_type()); + } +} -- cgit v1.2.3