imageinfo/formats/
try_jpg.rs

1use crate::{ImageFormat, ImageInfo, ImageInfoError, ImageInfoResult, ImageSize, ReadInterface};
2use std::io::{BufRead, Seek};
3
4// https://www.fileformat.info/format/jpeg/corion.htm
5pub fn try_jpg<R>(ri: &mut ReadInterface<R>, length: usize) -> ImageInfoResult<ImageInfo>
6where
7    R: BufRead + Seek,
8{
9    if length < 2 {
10        return Err(ImageInfoError::UnrecognizedFormat);
11    }
12    let buffer = ri.read(0, 2)?;
13    if !buffer.cmp(0, 2, b"\xFF\xD8") {
14        return Err(ImageInfoError::UnrecognizedFormat);
15    }
16
17    let mut ret = ImageInfo {
18        format: ImageFormat::JPEG,
19        ext: "jpg",
20        full_ext: "jpeg",
21        mimetype: "image/jpeg",
22        size: ImageSize {
23            width: 0,
24            height: 0,
25        },
26        entry_sizes: vec![],
27    };
28
29    let mut orientation = 1u16;
30    let mut offset = 2usize;
31    while offset + 9 <= length {
32        let buffer = ri.read(offset, 9)?;
33        let section_size = buffer.read_u16_be(2) as usize;
34        if !buffer.cmp(0, 1, b"\xFF") {
35            // skip garbage bytes
36            offset += 1;
37            continue;
38        }
39
40        // 0xFFE1 is application 1 (APP1)
41        if buffer.cmp(0, 2, b"\xFF\xE1") {
42            if offset + section_size + 2 > length {
43                return Err(ImageInfoError::UnrecognizedFormat);
44            }
45            let exif_buffer = ri.read(offset, section_size + 2)?;
46            if exif_buffer.cmp(4, 5, b"Exif\x00") {
47                let big_endian = !exif_buffer.cmp(10, 1, b"I");
48                let first_ifd_offset = if big_endian {
49                    exif_buffer.read_u32_be(14)
50                } else {
51                    exif_buffer.read_u32_le(14)
52                };
53                if first_ifd_offset < 8
54                    || (first_ifd_offset as u64) + 12u64 > (section_size as u64 + 2u64)
55                {
56                    return Err(ImageInfoError::UnrecognizedFormat);
57                }
58                let ifd_main_entries_count = if big_endian {
59                    exif_buffer.read_u16_be(first_ifd_offset as usize + 10)
60                } else {
61                    exif_buffer.read_u16_le(first_ifd_offset as usize + 10)
62                };
63                for i in 0..ifd_main_entries_count {
64                    let entry_offset = first_ifd_offset as usize + 12 + 12 * i as usize;
65                    if entry_offset + 12 > section_size + 2 {
66                        return Err(ImageInfoError::UnrecognizedFormat);
67                    }
68                    let tag = if big_endian {
69                        exif_buffer.read_u16_be(entry_offset)
70                    } else {
71                        exif_buffer.read_u16_le(entry_offset)
72                    };
73                    // Orientation Tag
74                    if tag == 274 {
75                        orientation = if big_endian {
76                            exif_buffer.read_u16_be(entry_offset + 8)
77                        } else {
78                            exif_buffer.read_u16_le(entry_offset + 8)
79                        };
80                    }
81                }
82            }
83            offset += section_size + 2;
84            continue;
85        }
86
87        // 0xFFC0 is baseline standard (SOF0)
88        // 0xFFC1 is baseline optimized (SOF1)
89        // 0xFFC2 is progressive (SOF2)
90        if buffer.cmp_any_of(0, 2, vec![b"\xFF\xC0", b"\xFF\xC1", b"\xFF\xC2"]) {
91            let mut size = ImageSize {
92                width: buffer.read_u16_be(7) as i64,
93                height: buffer.read_u16_be(5) as i64,
94            };
95            if orientation == 5 || orientation == 6 || orientation == 7 || orientation == 8 {
96                std::mem::swap(&mut size.width, &mut size.height);
97            }
98            ret.size = size;
99            return Ok(ret);
100        }
101        offset += section_size + 2;
102    }
103
104    Err(ImageInfoError::UnrecognizedFormat)
105}