image_meta/loader/
jpeg.rs1use std::io::{BufRead, Cursor, Seek, SeekFrom};
2
3use byteorder::{BigEndian, ReadBytesExt};
4
5use crate::errors::{ImageError, ImageResult};
6use crate::types::{Color, ColorMode, Dimensions, Format, ImageMeta};
7
8const MARKER: u8 = 0xff;
9const SOI: u8 = 0xd8;
10
11pub fn load<R: ?Sized + BufRead + Seek>(image: &mut R) -> ImageResult<ImageMeta> {
12 read_signature(image)?;
13 let dimensions = read_sof(image)?;
14 let color = Color {
15 alpha_channel: false,
16 mode: ColorMode::Rgb,
17 resolution: 8,
18 };
19 Ok(ImageMeta {
20 animation_frames: None,
21 color,
22 dimensions,
23 format: Format::Jpeg,
24 })
25}
26
27fn read_signature<R: ?Sized + BufRead + Seek>(image: &mut R) -> ImageResult {
28 let mut soi = [0u8; 2];
29 image.read_exact(&mut soi)?;
30 if [MARKER, SOI] != soi {
31 return Err(ImageError::InvalidSignature);
32 }
33 Ok(())
34}
35
36fn read_sof<R: ?Sized + BufRead + Seek>(image: &mut R) -> ImageResult<Dimensions> {
37 loop {
38 if let (_, Some(data)) = read_segment(image, is_sof)? {
39 let mut data = Cursor::new(data);
40 data.seek(SeekFrom::Current(1))?;
41 let height = data.read_u16::<BigEndian>().map(u32::from)?;
42 let width = data.read_u16::<BigEndian>().map(u32::from)?;
43 return Ok(Dimensions { width, height });
44 }
45 }
46}
47
48fn read_segment<R: ?Sized + BufRead + Seek, F>(
49 image: &mut R,
50 target_marker: F,
51) -> ImageResult<(u8, Option<Vec<u8>>)>
52where
53 F: Fn(u8) -> bool,
54{
55 let prefix = image.read_u8()?;
56 if prefix != MARKER {
57 return Err(ImageError::CorruptImage("Marker not found".into()));
58 }
59
60 let mut marker = image.read_u8()?;
62 while marker == MARKER {
63 marker = image.read_u8()?;
64 }
65
66 let length = image.read_u16::<BigEndian>()? - 2;
67
68 if target_marker(marker) {
69 let mut result = vec![0u8; length as usize];
70 image.read_exact(&mut result)?;
71 Ok((marker, Some(result)))
72 } else {
73 image.seek(SeekFrom::Current(i64::from(length)))?;
74 Ok((marker, None))
75 }
76}
77
78fn is_sof(marker: u8) -> bool {
79 matches!(
80 marker,
81 0xc0 | 0xc1 | 0xc2 | 0xc3 | 0xc5 | 0xc6 | 0xc7 | 0xc9 | 0xca | 0xcb | 0xcd | 0xce | 0xcf
82 )
83}