1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
use std::io::{Read, Seek, SeekFrom};
use byteorder::{BigEndian, ReadBytesExt};
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum Format {
Png,
Jpeg,
Gif,
Webp,
Tiff,
Bmp,
Ico,
Hdr,
Tga,
Xyz,
}
pub fn guess<R: Read + Seek>(mut input: R) -> Option<Format> {
const MAGIC: &'static [(&'static [u8], Format)] = &[
(b"\x89PNG\r\n\x1a\n", Format::Png),
(&[0xff, 0xd8, 0xff], Format::Jpeg),
(b"GIF89a", Format::Gif),
(b"GIF87a", Format::Gif),
(b"WEBP", Format::Webp),
(b"MM.*", Format::Tiff),
(b"II*.", Format::Tiff),
(b"BM", Format::Bmp),
(b"XYZ1", Format::Xyz),
(&[0x00, 0x00, 0x01, 0x00], Format::Ico),
(b"#?RADIANCE", Format::Hdr),
];
macro_rules! try {
(return $body:expr) => (
if let Ok(value) = $body {
value
}
else {
return None;
}
);
(continue $body:expr) => (
if let Ok(value) = $body {
value
}
else {
continue;
}
);
}
let mut result = None;
for &(magic, format) in MAGIC.iter() {
try!(continue input.seek(SeekFrom::Start(0)));
let mut buffer = vec![0; magic.len()];
try!(continue input.read_exact(&mut buffer));
if buffer == &magic[..] {
result = Some(format);
break;
}
}
if result.is_none() {
try!(return input.seek(SeekFrom::Start(1)));
let byte = try!(return input.read_u32::<BigEndian>()) & 0xfff7ffff;
if byte == 0x01010000 || byte == 0x00020000 || byte == 0x00030000 {
result = Some(Format::Tga);
}
}
try!(return input.seek(SeekFrom::Start(0)));
result
}