1use alloc::{boxed::Box, format};
20use no_std_io::io::{self, Read, Seek, SeekFrom, Write};
21
22use crate::color::ExtendedColorType;
23use crate::error::{
24 DecodingError, ImageError, ImageResult, UnsupportedError, UnsupportedErrorKind,
25};
26use crate::io::free_functions::load_rect;
27use crate::{ColorType, ImageDecoder, ImageDecoderRect, ImageEncoder, ImageFormat};
28
29pub struct FarbfeldReader<R: Read> {
31 width: u32,
32 height: u32,
33 inner: R,
34 current_offset: u64,
36 cached_byte: Option<u8>,
37}
38
39impl<R: Read> FarbfeldReader<R> {
40 fn new(mut buffered_read: R) -> ImageResult<FarbfeldReader<R>> {
41 fn read_dimm<R: Read>(from: &mut R) -> ImageResult<u32> {
42 let mut buf = [0u8; 4];
43 from.read_exact(&mut buf).map_err(ImageError::IoError)?;
44 Ok(u32::from_be_bytes(buf))
45 }
46
47 let mut magic = [0u8; 8];
48 buffered_read
49 .read_exact(&mut magic)
50 .map_err(ImageError::IoError)?;
51 if &magic != b"farbfeld" {
52 return Err(ImageError::Decoding(DecodingError::new(
53 ImageFormat::Farbfeld.into(),
54 format!("Invalid magic: {magic:02x?}"),
55 )));
56 }
57
58 let reader = FarbfeldReader {
59 width: read_dimm(&mut buffered_read)?,
60 height: read_dimm(&mut buffered_read)?,
61 inner: buffered_read,
62 current_offset: 0,
63 cached_byte: None,
64 };
65
66 if crate::utils::check_dimension_overflow(
67 reader.width,
68 reader.height,
69 8,
71 ) {
72 return Err(ImageError::Unsupported(
73 UnsupportedError::from_format_and_kind(
74 ImageFormat::Farbfeld.into(),
75 UnsupportedErrorKind::GenericFeature(format!(
76 "Image dimensions ({}x{}) are too large",
77 reader.width, reader.height
78 )),
79 ),
80 ));
81 }
82
83 Ok(reader)
84 }
85}
86
87impl<R: Read> Read for FarbfeldReader<R> {
88 fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {
89 let mut bytes_written = 0;
90 if let Some(byte) = self.cached_byte.take() {
91 buf[0] = byte;
92 buf = &mut buf[1..];
93 bytes_written = 1;
94 self.current_offset += 1;
95 }
96
97 if buf.len() == 1 {
98 buf[0] = cache_byte(&mut self.inner, &mut self.cached_byte)?;
99 bytes_written += 1;
100 self.current_offset += 1;
101 } else {
102 for channel_out in buf.as_chunks_mut::<2>().0 {
103 consume_channel(&mut self.inner, channel_out)?;
104 bytes_written += 2;
105 self.current_offset += 2;
106 }
107 }
108
109 Ok(bytes_written)
110 }
111}
112
113impl<R: Read + Seek> Seek for FarbfeldReader<R> {
114 fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
115 fn parse_offset(original_offset: u64, end_offset: u64, pos: SeekFrom) -> Option<i64> {
116 match pos {
117 SeekFrom::Start(off) => i64::try_from(off)
118 .ok()?
119 .checked_sub(i64::try_from(original_offset).ok()?),
120 SeekFrom::End(off) => {
121 if off < i64::try_from(end_offset).unwrap_or(i64::MAX) {
122 None
123 } else {
124 Some(i64::try_from(end_offset.checked_sub(original_offset)?).ok()? + off)
125 }
126 }
127 SeekFrom::Current(off) => {
128 if off < i64::try_from(original_offset).unwrap_or(i64::MAX) {
129 None
130 } else {
131 Some(off)
132 }
133 }
134 }
135 }
136
137 let original_offset = self.current_offset;
138 let end_offset = u64::from(self.width) * u64::from(self.height) * 2;
139 let offset_from_current =
140 parse_offset(original_offset, end_offset, pos).ok_or_else(|| {
141 io::Error::new(
142 io::ErrorKind::InvalidInput,
143 "invalid seek to a negative or overflowing position",
144 )
145 })?;
146
147 self.inner.seek(SeekFrom::Current(offset_from_current))?;
149 self.current_offset = if offset_from_current < 0 {
150 original_offset.checked_sub(offset_from_current.wrapping_neg() as u64)
151 } else {
152 original_offset.checked_add(offset_from_current as u64)
153 }
154 .expect("This should've been checked above");
155
156 if self.current_offset < end_offset && self.current_offset % 2 == 1 {
157 let curr = self.inner.seek(SeekFrom::Current(-1))?;
158 cache_byte(&mut self.inner, &mut self.cached_byte)?;
159 self.inner.seek(SeekFrom::Start(curr))?;
160 } else {
161 self.cached_byte = None;
162 }
163
164 Ok(original_offset)
165 }
166}
167
168fn consume_channel<R: Read>(from: &mut R, to: &mut [u8; 2]) -> io::Result<()> {
169 let mut ibuf = [0u8; 2];
170 from.read_exact(&mut ibuf)?;
171 to.copy_from_slice(&u16::from_be_bytes(ibuf).to_ne_bytes());
172
173 Ok(())
174}
175
176fn cache_byte<R: Read>(from: &mut R, cached_byte: &mut Option<u8>) -> io::Result<u8> {
177 let mut obuf = [0u8; 2];
178 consume_channel(from, &mut obuf)?;
179 *cached_byte = Some(obuf[1]);
180 Ok(obuf[0])
181}
182
183pub struct FarbfeldDecoder<R: Read> {
185 reader: FarbfeldReader<R>,
186}
187
188impl<R: Read> FarbfeldDecoder<R> {
189 pub fn new(buffered_read: R) -> ImageResult<FarbfeldDecoder<R>> {
191 Ok(FarbfeldDecoder {
192 reader: FarbfeldReader::new(buffered_read)?,
193 })
194 }
195}
196
197impl<R: Read> ImageDecoder for FarbfeldDecoder<R> {
198 fn dimensions(&self) -> (u32, u32) {
199 (self.reader.width, self.reader.height)
200 }
201
202 fn color_type(&self) -> ColorType {
203 ColorType::Rgba16
204 }
205
206 fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> {
207 assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));
208 self.reader.read_exact(buf)?;
209 Ok(())
210 }
211
212 fn read_image_boxed(self: Box<Self>, buf: &mut [u8]) -> ImageResult<()> {
213 (*self).read_image(buf)
214 }
215}
216
217impl<R: Read + Seek> ImageDecoderRect for FarbfeldDecoder<R> {
218 fn read_rect(
219 &mut self,
220 x: u32,
221 y: u32,
222 width: u32,
223 height: u32,
224 buf: &mut [u8],
225 row_pitch: usize,
226 ) -> ImageResult<()> {
227 #[allow(clippy::seek_from_current)]
231 let start = self.reader.seek(SeekFrom::Current(0))?;
232 load_rect(
233 x,
234 y,
235 width,
236 height,
237 buf,
238 row_pitch,
239 self,
240 2,
241 |s, scanline| s.reader.seek(SeekFrom::Start(scanline * 2)).map(|_| ()),
242 |s, buf| s.reader.read_exact(buf),
243 )?;
244 self.reader.seek(SeekFrom::Start(start))?;
245 Ok(())
246 }
247}
248
249pub struct FarbfeldEncoder<W: Write> {
251 w: W,
252}
253
254impl<W: Write> FarbfeldEncoder<W> {
255 pub fn new(buffered_writer: W) -> FarbfeldEncoder<W> {
257 FarbfeldEncoder { w: buffered_writer }
258 }
259
260 #[track_caller]
266 pub fn encode(self, data: &[u8], width: u32, height: u32) -> ImageResult<()> {
267 let expected_buffer_len = (u64::from(width) * u64::from(height)).saturating_mul(8);
268 assert_eq!(
269 expected_buffer_len,
270 data.len() as u64,
271 "Invalid buffer length: expected {expected_buffer_len} got {} for {width}x{height} image",
272 data.len(),
273 );
274 self.encode_impl(data, width, height)?;
275 Ok(())
276 }
277
278 fn encode_impl(mut self, data: &[u8], width: u32, height: u32) -> io::Result<()> {
279 self.w.write_all(b"farbfeld")?;
280
281 self.w.write_all(&width.to_be_bytes())?;
282 self.w.write_all(&height.to_be_bytes())?;
283
284 for &channel in data.as_chunks::<2>().0 {
285 self.w
286 .write_all(&u16::from_ne_bytes(channel).to_be_bytes())?;
287 }
288
289 Ok(())
290 }
291}
292
293impl<W: Write> ImageEncoder for FarbfeldEncoder<W> {
294 #[track_caller]
295 fn write_image(
296 self,
297 buf: &[u8],
298 width: u32,
299 height: u32,
300 color_type: ExtendedColorType,
301 ) -> ImageResult<()> {
302 if color_type != ExtendedColorType::Rgba16 {
303 return Err(ImageError::Unsupported(
304 UnsupportedError::from_format_and_kind(
305 ImageFormat::Farbfeld.into(),
306 UnsupportedErrorKind::Color(color_type),
307 ),
308 ));
309 }
310
311 self.encode(buf, width, height)
312 }
313}
314
315#[cfg(test)]
316mod tests {
317 use crate::codecs::farbfeld::FarbfeldDecoder;
318 use crate::ImageDecoderRect;
319 use byteorder_lite::{ByteOrder, NativeEndian};
320 use no_std_io::io::{Cursor, Seek, SeekFrom};
321
322 static RECTANGLE_IN: &[u8] = b"farbfeld\
323 \x00\x00\x00\x02\x00\x00\x00\x03\
324 \xFF\x01\xFE\x02\xFD\x03\xFC\x04\xFB\x05\xFA\x06\xF9\x07\xF8\x08\
325 \xF7\x09\xF6\x0A\xF5\x0B\xF4\x0C\xF3\x0D\xF2\x0E\xF1\x0F\xF0\x10\
326 \xEF\x11\xEE\x12\xED\x13\xEC\x14\xEB\x15\xEA\x16\xE9\x17\xE8\x18";
327
328 #[test]
329 fn read_rect_1x2() {
330 static RECTANGLE_OUT: &[u16] = &[
331 0xF30D, 0xF20E, 0xF10F, 0xF010, 0xEB15, 0xEA16, 0xE917, 0xE818,
332 ];
333
334 read_rect(1, 1, 1, 2, RECTANGLE_OUT);
335 }
336
337 #[test]
338 fn read_rect_2x2() {
339 static RECTANGLE_OUT: &[u16] = &[
340 0xFF01, 0xFE02, 0xFD03, 0xFC04, 0xFB05, 0xFA06, 0xF907, 0xF808, 0xF709, 0xF60A, 0xF50B,
341 0xF40C, 0xF30D, 0xF20E, 0xF10F, 0xF010,
342 ];
343
344 read_rect(0, 0, 2, 2, RECTANGLE_OUT);
345 }
346
347 #[test]
348 fn read_rect_2x1() {
349 static RECTANGLE_OUT: &[u16] = &[
350 0xEF11, 0xEE12, 0xED13, 0xEC14, 0xEB15, 0xEA16, 0xE917, 0xE818,
351 ];
352
353 read_rect(0, 2, 2, 1, RECTANGLE_OUT);
354 }
355
356 #[test]
357 fn read_rect_2x3() {
358 static RECTANGLE_OUT: &[u16] = &[
359 0xFF01, 0xFE02, 0xFD03, 0xFC04, 0xFB05, 0xFA06, 0xF907, 0xF808, 0xF709, 0xF60A, 0xF50B,
360 0xF40C, 0xF30D, 0xF20E, 0xF10F, 0xF010, 0xEF11, 0xEE12, 0xED13, 0xEC14, 0xEB15, 0xEA16,
361 0xE917, 0xE818,
362 ];
363
364 read_rect(0, 0, 2, 3, RECTANGLE_OUT);
365 }
366
367 #[test]
368 fn read_rect_in_stream() {
369 static RECTANGLE_OUT: &[u16] = &[0xEF11, 0xEE12, 0xED13, 0xEC14];
370
371 let mut input = vec![];
372 input.extend_from_slice(b"This is a 31-byte-long prologue");
373 input.extend_from_slice(RECTANGLE_IN);
374 let mut input_cur = Cursor::new(input);
375 input_cur.seek(SeekFrom::Start(31)).unwrap();
376
377 let mut out_buf = [0u8; 64];
378 FarbfeldDecoder::new(input_cur)
379 .unwrap()
380 .read_rect(0, 2, 1, 1, &mut out_buf, 8)
381 .unwrap();
382 let exp = degenerate_pixels(RECTANGLE_OUT);
383 assert_eq!(&out_buf[..exp.len()], &exp[..]);
384 }
385
386 #[test]
387 fn dimension_overflow() {
388 let header = b"farbfeld\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF";
389
390 assert!(FarbfeldDecoder::new(Cursor::new(header)).is_err());
391 }
392
393 fn read_rect(x: u32, y: u32, width: u32, height: u32, exp_wide: &[u16]) {
394 let mut out_buf = [0u8; 64];
395 FarbfeldDecoder::new(Cursor::new(RECTANGLE_IN))
396 .unwrap()
397 .read_rect(x, y, width, height, &mut out_buf, width as usize * 8)
398 .unwrap();
399 let exp = degenerate_pixels(exp_wide);
400 assert_eq!(&out_buf[..exp.len()], &exp[..]);
401 }
402
403 fn degenerate_pixels(exp_wide: &[u16]) -> Vec<u8> {
404 let mut exp = vec![0u8; exp_wide.len() * 2];
405 NativeEndian::write_u16_into(exp_wide, &mut exp);
406 exp
407 }
408}