infer/matchers/
image.rs
1use std::convert::TryInto;
2
3pub fn is_jpeg(buf: &[u8]) -> bool {
5 buf.len() > 2 && buf[0] == 0xFF && buf[1] == 0xD8 && buf[2] == 0xFF
6}
7
8pub fn is_jpeg2000(buf: &[u8]) -> bool {
10 buf.len() > 12
11 && buf[0] == 0x0
12 && buf[1] == 0x0
13 && buf[2] == 0x0
14 && buf[3] == 0xC
15 && buf[4] == 0x6A
16 && buf[5] == 0x50
17 && buf[6] == 0x20
18 && buf[7] == 0x20
19 && buf[8] == 0xD
20 && buf[9] == 0xA
21 && buf[10] == 0x87
22 && buf[11] == 0xA
23 && buf[12] == 0x0
24}
25
26pub fn is_png(buf: &[u8]) -> bool {
28 buf.len() > 3 && buf[0] == 0x89 && buf[1] == 0x50 && buf[2] == 0x4E && buf[3] == 0x47
29}
30
31pub fn is_gif(buf: &[u8]) -> bool {
33 buf.len() > 2 && buf[0] == 0x47 && buf[1] == 0x49 && buf[2] == 0x46
34}
35
36pub fn is_webp(buf: &[u8]) -> bool {
38 buf.len() > 11 && buf[8] == 0x57 && buf[9] == 0x45 && buf[10] == 0x42 && buf[11] == 0x50
39}
40
41pub fn is_cr2(buf: &[u8]) -> bool {
43 buf.len() > 9
44 && ((buf[0] == 0x49 && buf[1] == 0x49 && buf[2] == 0x2A && buf[3] == 0x0)
45 || (buf[0] == 0x4D && buf[1] == 0x4D && buf[2] == 0x0 && buf[3] == 0x2A))
46 && buf[8] == 0x43
47 && buf[9] == 0x52
48 && buf[10] == 0x02 }
50
51pub fn is_tiff(buf: &[u8]) -> bool {
53 buf.len() > 9
54 && ((buf[0] == 0x49 && buf[1] == 0x49 && buf[2] == 0x2A && buf[3] == 0x0)
55 || (buf[0] == 0x4D && buf[1] == 0x4D && buf[2] == 0x0 && buf[3] == 0x2A))
56 && buf[8] != 0x43
57 && buf[9] != 0x52
58 && !is_cr2(buf) }
60
61pub fn is_bmp(buf: &[u8]) -> bool {
63 buf.len() > 1 && buf[0] == 0x42 && buf[1] == 0x4D
64}
65
66pub fn is_jxr(buf: &[u8]) -> bool {
68 buf.len() > 2 && buf[0] == 0x49 && buf[1] == 0x49 && buf[2] == 0xBC
69}
70
71pub fn is_psd(buf: &[u8]) -> bool {
73 buf.len() > 3 && buf[0] == 0x38 && buf[1] == 0x42 && buf[2] == 0x50 && buf[3] == 0x53
74}
75
76pub fn is_ico(buf: &[u8]) -> bool {
78 buf.len() > 3 && buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x01 && buf[3] == 0x00
79}
80
81pub fn is_heif(buf: &[u8]) -> bool {
83 if buf.is_empty() {
84 return false;
85 }
86
87 if !is_isobmff(buf) {
88 return false;
89 }
90
91 if let Some((major, _minor, compatible)) = get_ftyp(buf) {
92 if major == b"heic" {
93 return true;
94 }
95
96 if major == b"mif1" || major == b"msf1" {
97 for b in compatible {
98 if b == b"heic" {
99 return true;
100 }
101 }
102 }
103 }
104
105 false
106}
107
108pub fn is_avif(buf: &[u8]) -> bool {
110 if buf.is_empty() {
111 return false;
112 }
113
114 if !is_isobmff(buf) {
115 return false;
116 }
117
118 if let Some((major, _minor, compatible)) = get_ftyp(buf) {
119 if major == b"avif" || major == b"avis" {
120 return true;
121 }
122
123 for b in compatible {
124 if b == b"avif" || b == b"avis" {
125 return true;
126 }
127 }
128 }
129
130 false
131}
132
133fn is_isobmff(buf: &[u8]) -> bool {
135 if buf.len() < 16 {
136 return false;
137 }
138
139 if &buf[4..8] != b"ftyp" {
140 return false;
141 }
142
143 let ftyp_length = u32::from_be_bytes(buf[0..4].try_into().unwrap()) as usize;
144 buf.len() >= ftyp_length
145}
146
147fn get_ftyp(buf: &[u8]) -> Option<(&[u8], &[u8], impl Iterator<Item = &[u8]>)> {
149 if buf.len() < 16 {
150 return None;
151 }
152
153 let ftyp_length = u32::from_be_bytes(buf[0..4].try_into().unwrap()) as usize;
154
155 let major = &buf[8..12];
156 let minor = &buf[12..16];
157 let compatible = (16..ftyp_length).step_by(4).map(move |i| &buf[i..i + 4]);
158
159 Some((major, minor, compatible))
160}