1#[cfg(feature = "png")]
2use png::BitDepth;
3use crate::structs::*;
4use crate::magic;
5
6pub fn read(buf: &[u8]) -> Result<ImageInfo, ()> {
7 let file_type = magic::detect_file_type_with_magic_number(&buf).unwrap();
8
9 match file_type {
10 "png" => {
11 #[cfg(feature="png")]
12 return Ok(read_png(&buf));
13 #[cfg(not(feature="png"))]
14 return Err(());
15 }
16 "webp" => {
17 #[cfg(feature="webp")]
18 return Ok(read_webp(&buf));
19 #[cfg(not(feature="webp"))]
20 return Err(());
21 }
22 "jxl" => {
23 #[cfg(feature="jpegxl")]
24 return Ok(read_jpeg_xl(&buf));
25 #[cfg(not(feature="jpegxl"))]
26 return Err(());
27 }
28 _ => Err(()),
29 }
30}
31
32#[cfg(feature="webp")]
33pub fn read_webp(buf: &[u8]) -> ImageInfo {
34 let decoder = webp::Decoder::new(&buf);
35
36 let webp_info = decoder.decode().unwrap();
37
38 let bit_per_pixel = match webp_info.is_alpha() {
39 true => 4, false => 3, };
42
43 let pixels_num = webp_info.width() as usize * webp_info.height() as usize;
44 let dots_num = pixels_num * bit_per_pixel;
45
46 let image = webp_info.to_image();
47
48 let mut pixels: Vec<u8> = vec![0; dots_num];
49
50 if webp_info.is_alpha() {
51 let image = image.as_rgba8().unwrap();
52
53 for x in 0..webp_info.width() {
54 for y in 0..webp_info.height() {
55 let pixel = image.get_pixel(x, y);
56 let i: usize = (y * webp_info.width() + x) as usize;
57 pixels[i * 4 + 0] = pixel[0];
58 pixels[i * 4 + 1] = pixel[1];
59 pixels[i * 4 + 2] = pixel[2];
60 pixels[i * 4 + 3] = pixel[3];
61 }
62 }
63 } else {
64 let image = image.as_rgb8().unwrap();
65
66 for x in 0..webp_info.width() {
67 for y in 0..webp_info.height() {
68 let pixel = image.get_pixel(x, y);
69 let i: usize = (y * webp_info.width() + x) as usize;
70 pixels[i * 3 + 0] = pixel[0];
71 pixels[i * 3 + 1] = pixel[1];
72 pixels[i * 3 + 2] = pixel[2];
73 }
74 }
75 }
76
77 let im_info = ImageInfo {
78 width: webp_info.width(),
79 height: webp_info.height(),
80 bit_depth: 8,
81 color_type: match webp_info.is_alpha() {
82 true => 6, false => 2, },
85 pixels: ImagePixels::U8(pixels),
86 };
87
88 im_info
89}
90
91#[cfg(feature="png")]
92pub fn read_png(buf: &[u8]) -> ImageInfo {
93 let decoder = png::Decoder::new(buf);
94 let mut reader = decoder.read_info().unwrap();
95 let info = reader.info().to_owned();
96
97 let mut dot_per_pixel = match info.color_type {
100 png::ColorType::Grayscale => 1,
101 png::ColorType::Rgb => 3,
102 png::ColorType::Indexed => 1,
103 png::ColorType::GrayscaleAlpha => 2,
104 png::ColorType::Rgba => 4,
105 };
106
107 if info.bit_depth == BitDepth::Sixteen {
108 dot_per_pixel *= 2;
109 }
110
111 let mut pxls = vec![0; info.width as usize * info.height as usize * dot_per_pixel];
112
113 reader.next_frame(&mut pxls).unwrap();
114
115 let pixels: ImagePixels;
116
117 if info.bit_depth == BitDepth::Sixteen {
118 let mut pixels16 = vec![0; info.width as usize * info.height as usize * dot_per_pixel / 2];
119
120 for i in 0..pixels16.len() {
121 pixels16[i] = (pxls[i * 2] as u16) << 8 | pxls[i * 2 + 1] as u16;
122 }
123
124 pixels = ImagePixels::U16(pixels16);
125 } else {
126 let mut pixels8 = vec![0; info.width as usize * info.height as usize * dot_per_pixel];
127
128 for i in 0..pixels8.len() {
129 pixels8[i] = pxls[i];
130 }
131
132 pixels = ImagePixels::U8(pixels8);
133 }
134
135 let im_info = ImageInfo {
136 width: info.width,
137 height: info.height,
138 bit_depth: match info.bit_depth {
139 BitDepth::One => 1,
140 BitDepth::Two => 2,
141 BitDepth::Four => 4,
142 BitDepth::Eight => 8,
143 BitDepth::Sixteen => 16,
144 },
145 color_type: match info.color_type {
146 png::ColorType::Grayscale => 0,
147 png::ColorType::Rgb => 2,
148 png::ColorType::Indexed => 3,
149 png::ColorType::GrayscaleAlpha => 4,
150 png::ColorType::Rgba => 6,
151 },
152 pixels,
153 };
154
155 im_info
156}
157
158#[cfg(feature="jpegxl")]
159pub fn read_jpeg_xl(buf: &[u8]) -> ImageInfo {
160 let mut decoder_builder = jpegxl_rs::decode::decoder_builder();
161 let mut decoder = decoder_builder.build().unwrap();
162 let data = decoder.decode(buf).unwrap();
163
164 let metadata = data.0;
165 let pixels = data.1;
166
167 let bit_depth = match pixels {
168 jpegxl_rs::decode::Pixels::Uint8(_) => 8,
169 jpegxl_rs::decode::Pixels::Uint16(_) => 16,
170 jpegxl_rs::decode::Pixels::Float16(_) => 16,
171 jpegxl_rs::decode::Pixels::Float(_) => 32,
172 };
173
174 let pixels = match pixels {
175 jpegxl_rs::decode::Pixels::Uint8(pixels) => {
176 ImagePixels::U8(pixels)
177 },
178 jpegxl_rs::decode::Pixels::Uint16(pixels) => {
179 ImagePixels::U16(pixels)
180 },
181 jpegxl_rs::decode::Pixels::Float16(pixels) => {
182 ImagePixels::F16(pixels)
183 },
184 jpegxl_rs::decode::Pixels::Float(pixels) => {
185 ImagePixels::F32(pixels)
186 },
187 };
188
189 let mut im_info = ImageInfo {
190 width: metadata.width,
191 height: metadata.height,
192 bit_depth,
193 color_type: (metadata.num_color_channels + (if metadata.has_alpha_channel { 1 } else { 0 })) as u8,
194 pixels,
195 };
196
197 im_info
198}