1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10pub enum ImageFormat {
11 Png,
13 Jpeg,
15 Bmp,
17 Tiff,
19 Jb2,
21 Unknown,
23}
24
25impl ImageFormat {
26 #[must_use]
28 pub fn from_extension(ext: &str) -> Self {
29 match ext.to_lowercase().as_str() {
30 "png" => Self::Png,
31 "jpg" | "jpeg" => Self::Jpeg,
32 "bmp" => Self::Bmp,
33 "tiff" | "tif" => Self::Tiff,
34 "jb2" | "gbig2" => Self::Jb2,
35 _ => Self::Unknown,
36 }
37 }
38
39 #[must_use]
41 pub fn from_path(path: &str) -> Self {
42 let ext = path.rsplit('.').next().unwrap_or("");
43 Self::from_extension(ext)
44 }
45
46 #[must_use]
48 pub fn mime_type(&self) -> &'static str {
49 match self {
50 Self::Png => "image/png",
51 Self::Jpeg => "image/jpeg",
52 Self::Bmp => "image/bmp",
53 Self::Tiff => "image/tiff",
54 Self::Jb2 => "image/x-jbig2",
55 Self::Unknown => "application/octet-stream",
56 }
57 }
58
59 #[must_use]
61 pub fn extension(&self) -> &'static str {
62 match self {
63 Self::Png => "png",
64 Self::Jpeg => "jpeg",
65 Self::Bmp => "bmp",
66 Self::Tiff => "tiff",
67 Self::Jb2 => "jb2",
68 Self::Unknown => "bin",
69 }
70 }
71}
72
73#[must_use]
77pub fn detect_format(data: &[u8]) -> ImageFormat {
78 if data.len() < 4 {
79 return ImageFormat::Unknown;
80 }
81 if data.starts_with(&[0x89, 0x50, 0x4E, 0x47]) {
83 return ImageFormat::Png;
84 }
85 if data.starts_with(&[0xFF, 0xD8, 0xFF]) {
87 return ImageFormat::Jpeg;
88 }
89 if data.starts_with(&[0x42, 0x4D]) {
91 return ImageFormat::Bmp;
92 }
93 if data.starts_with(&[0x49, 0x49, 0x2A, 0x00]) || data.starts_with(&[0x4D, 0x4D, 0x00, 0x2A]) {
95 return ImageFormat::Tiff;
96 }
97 if data.starts_with(&[0x97, 0x4A, 0x42, 0x32]) {
99 return ImageFormat::Jb2;
100 }
101 ImageFormat::Unknown
102}
103
104#[must_use]
108pub fn gray(r: u32, g: u32, b: u32) -> u32 {
109 (r * 19_595 + g * 38_469 + b * 7_472) >> 16
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115
116 #[test]
117 fn test_image_format_from_extension() {
118 assert_eq!(ImageFormat::from_extension("png"), ImageFormat::Png);
119 assert_eq!(ImageFormat::from_extension("JPEG"), ImageFormat::Jpeg);
120 assert_eq!(ImageFormat::from_extension("jpg"), ImageFormat::Jpeg);
121 assert_eq!(ImageFormat::from_extension("bmp"), ImageFormat::Bmp);
122 assert_eq!(ImageFormat::from_extension("tiff"), ImageFormat::Tiff);
123 assert_eq!(ImageFormat::from_extension("tif"), ImageFormat::Tiff);
124 assert_eq!(ImageFormat::from_extension("jb2"), ImageFormat::Jb2);
125 assert_eq!(ImageFormat::from_extension("xyz"), ImageFormat::Unknown);
126 }
127
128 #[test]
129 fn test_image_format_from_path() {
130 assert_eq!(
131 ImageFormat::from_path("/doc/res/photo.jpg"),
132 ImageFormat::Jpeg
133 );
134 assert_eq!(ImageFormat::from_path("image.PNG"), ImageFormat::Png);
135 }
136
137 #[test]
138 fn test_image_format_mime_type() {
139 assert_eq!(ImageFormat::Png.mime_type(), "image/png");
140 assert_eq!(ImageFormat::Jpeg.mime_type(), "image/jpeg");
141 }
142
143 #[test]
144 fn test_image_format_extension() {
145 assert_eq!(ImageFormat::Png.extension(), "png");
146 assert_eq!(ImageFormat::Jpeg.extension(), "jpeg");
147 }
148
149 #[test]
150 fn test_detect_format_png() {
151 let data = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A];
152 assert_eq!(detect_format(&data), ImageFormat::Png);
153 }
154
155 #[test]
156 fn test_detect_format_jpeg() {
157 let data = [0xFF, 0xD8, 0xFF, 0xE0];
158 assert_eq!(detect_format(&data), ImageFormat::Jpeg);
159 }
160
161 #[test]
162 fn test_detect_format_bmp() {
163 let data = [0x42, 0x4D, 0x00, 0x00];
164 assert_eq!(detect_format(&data), ImageFormat::Bmp);
165 }
166
167 #[test]
168 fn test_detect_format_tiff_le() {
169 let data = [0x49, 0x49, 0x2A, 0x00];
170 assert_eq!(detect_format(&data), ImageFormat::Tiff);
171 }
172
173 #[test]
174 fn test_detect_format_tiff_be() {
175 let data = [0x4D, 0x4D, 0x00, 0x2A];
176 assert_eq!(detect_format(&data), ImageFormat::Tiff);
177 }
178
179 #[test]
180 fn test_detect_format_jb2() {
181 let data = [0x97, 0x4A, 0x42, 0x32];
182 assert_eq!(detect_format(&data), ImageFormat::Jb2);
183 }
184
185 #[test]
186 fn test_detect_format_unknown() {
187 let data = [0x00, 0x01, 0x02, 0x03];
188 assert_eq!(detect_format(&data), ImageFormat::Unknown);
189 }
190
191 #[test]
192 fn test_detect_format_short_data() {
193 assert_eq!(detect_format(&[0x89]), ImageFormat::Unknown);
194 assert_eq!(detect_format(&[]), ImageFormat::Unknown);
195 }
196
197 #[test]
198 fn test_gray() {
199 let white = gray(255, 255, 255);
201 assert_eq!(white, 255);
202 let black = gray(0, 0, 0);
204 assert_eq!(black, 0);
205 }
206}