imageinfo/formats/
try_jpg.rs1use crate::{ImageFormat, ImageInfo, ImageInfoError, ImageInfoResult, ImageSize, ReadInterface};
2use std::io::{BufRead, Seek};
3
4pub 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 offset += 1;
37 continue;
38 }
39
40 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 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 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}