1pub mod avif;
2pub mod jpeg;
3pub mod jxl;
4pub mod png;
5pub mod qoi;
6pub mod webp;
7
8use crate::error::Result;
9use crate::format::Format;
10
11#[derive(Debug, Clone)]
13pub struct ImageData {
14 pub width: u32,
15 pub height: u32,
16 pub data: Vec<u8>,
17}
18
19impl ImageData {
20 pub fn new(width: u32, height: u32, data: Vec<u8>) -> Self {
25 debug_assert_eq!(
26 data.len(),
27 (width as usize) * (height as usize) * 4,
28 "ImageData: expected {} bytes ({}x{}x4), got {}",
29 (width as usize) * (height as usize) * 4,
30 width,
31 height,
32 data.len(),
33 );
34 Self {
35 width,
36 height,
37 data,
38 }
39 }
40
41 pub fn to_rgb(&self) -> Vec<u8> {
43 self.data
44 .chunks_exact(4)
45 .flat_map(|px| &px[..3])
46 .copied()
47 .collect()
48 }
49}
50
51#[derive(Debug, Clone, Copy)]
53pub struct EncodeOptions {
54 pub quality: u8,
56}
57
58impl Default for EncodeOptions {
59 fn default() -> Self {
60 Self { quality: 80 }
61 }
62}
63
64pub trait Codec {
66 fn format(&self) -> Format;
68
69 fn decode(&self, data: &[u8]) -> Result<ImageData>;
71
72 fn encode(&self, image: &ImageData, options: &EncodeOptions) -> Result<Vec<u8>>;
74}
75
76pub fn get_codec(format: Format) -> Box<dyn Codec> {
78 match format {
79 Format::Jpeg => Box::new(jpeg::JpegCodec),
80 Format::Png => Box::new(png::PngCodec),
81 Format::WebP => Box::new(webp::WebPCodec),
82 Format::Avif => Box::new(avif::AvifCodec),
83 Format::Jxl => Box::new(jxl::JxlCodec),
84 Format::Qoi => Box::new(qoi::QoiCodec),
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91
92 #[test]
93 fn image_data_to_rgb() {
94 let data = vec![255, 0, 0, 255, 0, 255, 0, 128];
96 let img = ImageData::new(2, 1, data);
97
98 let rgb = img.to_rgb();
99 assert_eq!(rgb, vec![255, 0, 0, 0, 255, 0]);
100 }
101
102 #[test]
103 fn encode_options_default() {
104 let opts = EncodeOptions::default();
105 assert_eq!(opts.quality, 80);
106 }
107
108 #[test]
109 fn image_data_dimensions() {
110 let data = vec![0u8; 4 * 3 * 2]; let img = ImageData::new(3, 2, data);
112 assert_eq!(img.width, 3);
113 assert_eq!(img.height, 2);
114 assert_eq!(img.data.len(), 24);
115 }
116
117 #[test]
118 #[cfg(debug_assertions)]
119 #[should_panic(expected = "ImageData: expected")]
120 fn image_data_wrong_size_panics_in_debug() {
121 let data = vec![0u8; 10]; let _ = ImageData::new(2, 2, data);
123 }
124}