1use crate::error::CodecError;
7use crate::options::ImageInfo;
8use crate::pixel::ImagePixel;
9use edgefirst_tensor::{Tensor, TensorDyn};
10use std::io::Read;
11
12pub struct ImageDecoder {
41 pub(crate) jpeg_state: crate::jpeg::JpegDecoderState,
43 pub(crate) scratch: Vec<u8>,
45 pub(crate) input_buffer: Vec<u8>,
47}
48
49impl ImageDecoder {
50 pub fn new() -> Self {
52 Self {
53 jpeg_state: crate::jpeg::JpegDecoderState::new(),
54 scratch: Vec::new(),
55 input_buffer: Vec::new(),
56 }
57 }
58
59 pub fn decode_into<T: ImagePixel>(
72 &mut self,
73 data: &[u8],
74 dst: &mut Tensor<T>,
75 ) -> crate::Result<ImageInfo> {
76 if is_jpeg(data) {
77 crate::jpeg::decode_jpeg_into(data, dst, &mut self.jpeg_state)
78 } else if is_png(data) {
79 crate::png::decode_png_into(data, dst, &mut self.scratch)
80 } else {
81 Err(CodecError::InvalidData(
82 "unrecognized image format (expected JPEG or PNG magic bytes)".into(),
83 ))
84 }
85 }
86
87 pub fn decode_into_dyn(
89 &mut self,
90 data: &[u8],
91 dst: &mut TensorDyn,
92 ) -> crate::Result<ImageInfo> {
93 match dst {
94 TensorDyn::U8(t) => self.decode_into(data, t),
95 TensorDyn::I8(t) => self.decode_into(data, t),
96 TensorDyn::U16(t) => self.decode_into(data, t),
97 TensorDyn::I16(t) => self.decode_into(data, t),
98 TensorDyn::F32(t) => self.decode_into(data, t),
99 other => Err(CodecError::UnsupportedDtype(other.dtype())),
100 }
101 }
102
103 pub fn decode_from_reader<T: ImagePixel, R: Read>(
106 &mut self,
107 mut reader: R,
108 dst: &mut Tensor<T>,
109 ) -> crate::Result<ImageInfo> {
110 self.input_buffer.clear();
111 reader.read_to_end(&mut self.input_buffer)?;
112 decode_into_inner(
113 &mut self.jpeg_state,
114 &mut self.scratch,
115 &self.input_buffer,
116 dst,
117 )
118 }
119
120 pub fn decode_from_reader_dyn<R: Read>(
123 &mut self,
124 mut reader: R,
125 dst: &mut TensorDyn,
126 ) -> crate::Result<ImageInfo> {
127 self.input_buffer.clear();
128 reader.read_to_end(&mut self.input_buffer)?;
129 decode_into_inner_dyn(
130 &mut self.jpeg_state,
131 &mut self.scratch,
132 &self.input_buffer,
133 dst,
134 )
135 }
136}
137
138pub(crate) fn decode_into_inner<T: ImagePixel>(
142 jpeg_state: &mut crate::jpeg::JpegDecoderState,
143 scratch: &mut Vec<u8>,
144 data: &[u8],
145 dst: &mut Tensor<T>,
146) -> crate::Result<ImageInfo> {
147 if is_jpeg(data) {
148 crate::jpeg::decode_jpeg_into(data, dst, jpeg_state)
149 } else if is_png(data) {
150 crate::png::decode_png_into(data, dst, scratch)
151 } else {
152 Err(CodecError::InvalidData(
153 "unrecognized image format (expected JPEG or PNG magic bytes)".into(),
154 ))
155 }
156}
157
158pub(crate) fn decode_into_inner_dyn(
159 jpeg_state: &mut crate::jpeg::JpegDecoderState,
160 scratch: &mut Vec<u8>,
161 data: &[u8],
162 dst: &mut TensorDyn,
163) -> crate::Result<ImageInfo> {
164 match dst {
165 TensorDyn::U8(t) => decode_into_inner(jpeg_state, scratch, data, t),
166 TensorDyn::I8(t) => decode_into_inner(jpeg_state, scratch, data, t),
167 TensorDyn::U16(t) => decode_into_inner(jpeg_state, scratch, data, t),
168 TensorDyn::I16(t) => decode_into_inner(jpeg_state, scratch, data, t),
169 TensorDyn::F32(t) => decode_into_inner(jpeg_state, scratch, data, t),
170 other => Err(CodecError::UnsupportedDtype(other.dtype())),
171 }
172}
173
174impl Default for ImageDecoder {
175 fn default() -> Self {
176 Self::new()
177 }
178}
179
180pub fn peek_info(data: &[u8]) -> crate::Result<ImageInfo> {
197 if is_jpeg(data) {
198 crate::jpeg::peek_jpeg_info(data)
199 } else if is_png(data) {
200 crate::png::peek_png_info(data)
201 } else {
202 Err(CodecError::InvalidData(
203 "unrecognized image format (expected JPEG or PNG magic bytes)".into(),
204 ))
205 }
206}
207
208fn is_jpeg(data: &[u8]) -> bool {
210 data.len() >= 3 && data[0] == 0xFF && data[1] == 0xD8 && data[2] == 0xFF
211}
212
213fn is_png(data: &[u8]) -> bool {
215 data.len() >= 4 && data[0] == 0x89 && data[1] == 0x50 && data[2] == 0x4E && data[3] == 0x47
216}
217
218#[cfg(test)]
219mod tests {
220 use super::*;
221
222 #[test]
223 fn magic_bytes_jpeg() {
224 assert!(is_jpeg(&[0xFF, 0xD8, 0xFF, 0xE0]));
225 assert!(!is_jpeg(&[0x89, 0x50, 0x4E, 0x47]));
226 assert!(!is_jpeg(&[]));
227 assert!(!is_jpeg(&[0xFF]));
228 }
229
230 #[test]
231 fn magic_bytes_png() {
232 assert!(is_png(&[0x89, 0x50, 0x4E, 0x47]));
233 assert!(!is_png(&[0xFF, 0xD8, 0xFF, 0xE0]));
234 assert!(!is_png(&[]));
235 }
236
237 #[test]
238 fn invalid_data() {
239 let mut decoder = ImageDecoder::new();
240 let mut tensor = Tensor::<u8>::image(
241 100,
242 100,
243 edgefirst_tensor::PixelFormat::Nv12,
244 Some(edgefirst_tensor::TensorMemory::Mem),
245 )
246 .unwrap();
247 let result = decoder.decode_into(b"not an image", &mut tensor);
248 assert!(matches!(result, Err(CodecError::InvalidData(_))));
249 }
250}