Skip to main content

imagesize/formats/
mod.rs

1#[cfg(feature = "aesprite")]
2pub mod aesprite;
3#[cfg(feature = "astc")]
4pub mod astc;
5#[cfg(feature = "bmp")]
6pub mod bmp;
7#[cfg(feature = "exr")]
8pub mod exr;
9#[cfg(feature = "farbfeld")]
10pub mod farbfeld;
11#[cfg(feature = "gif")]
12pub mod gif;
13#[cfg(feature = "hdr")]
14pub mod hdr;
15#[cfg(feature = "ico")]
16pub mod ico;
17#[cfg(feature = "ilbm")]
18pub mod ilbm;
19#[cfg(feature = "jpeg")]
20pub mod jpeg;
21#[cfg(feature = "jxl")]
22pub mod jxl;
23#[cfg(feature = "ktx2")]
24pub mod ktx2;
25#[cfg(feature = "png")]
26pub mod png;
27#[cfg(feature = "pnm")]
28pub mod pnm;
29#[cfg(feature = "psd")]
30pub mod psd;
31#[cfg(feature = "qoi")]
32pub mod qoi;
33#[cfg(feature = "tga")]
34pub mod tga;
35#[cfg(feature = "tiff")]
36pub mod tiff;
37#[cfg(feature = "vtf")]
38pub mod vtf;
39#[cfg(feature = "webp")]
40pub mod webp;
41
42use crate::{container, ImageError, ImageResult, ImageType};
43use std::io::{BufRead, Seek};
44
45pub fn image_type<R: BufRead + Seek>(reader: &mut R) -> ImageResult<ImageType> {
46    let mut header = [0; 12];
47    reader.read_exact(&mut header)?;
48
49    // Currently there are no formats where 1 byte is enough to determine format
50    if header.len() < 2 {
51        return Err(
52            std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "Not enough data").into(),
53        );
54    }
55
56    // This is vaguely organized in what I assume are the most commonly used formats.
57    // I don't know how much this matters for actual execution time.
58    #[cfg(feature = "jpeg")]
59    if jpeg::matches(&header) {
60        return Ok(ImageType::Jpeg);
61    }
62
63    #[cfg(feature = "png")]
64    if png::matches(&header) {
65        return Ok(ImageType::Png);
66    }
67
68    #[cfg(feature = "gif")]
69    if gif::matches(&header) {
70        return Ok(ImageType::Gif);
71    }
72
73    #[cfg(feature = "tiff")]
74    if tiff::matches(&header) {
75        return Ok(ImageType::Tiff);
76    }
77
78    #[cfg(feature = "webp")]
79    if webp::matches(&header) {
80        return Ok(ImageType::Webp);
81    }
82
83    #[cfg(feature = "heif")]
84    if let Some(c) = container::heif::matches(&header, reader) {
85        return Ok(ImageType::Heif(c));
86    }
87
88    #[cfg(feature = "jxl")]
89    if jxl::matches(&header) {
90        return Ok(ImageType::Jxl);
91    }
92
93    #[cfg(feature = "bmp")]
94    if bmp::matches(&header) {
95        return Ok(ImageType::Bmp);
96    }
97
98    #[cfg(feature = "psd")]
99    if psd::matches(&header) {
100        return Ok(ImageType::Psd);
101    }
102
103    #[cfg(feature = "ico")]
104    if ico::matches(&header) {
105        return Ok(ImageType::Ico);
106    }
107
108    #[cfg(feature = "aesprite")]
109    if aesprite::matches(&header) {
110        return Ok(ImageType::Aseprite);
111    }
112
113    #[cfg(feature = "astc")]
114    if astc::matches(&header) {
115        return Ok(ImageType::Astc);
116    }
117
118    #[cfg(feature = "atc")]
119    if container::atc::matches(&header) {
120        use crate::container::atc::AtcCompression;
121
122        let compression =
123            container::atc::detect_compression(reader).unwrap_or(AtcCompression::Unknown);
124        return Ok(ImageType::Atc(compression));
125    }
126
127    #[cfg(feature = "pvrtc")]
128    if container::pvrtc::matches(&header) {
129        use crate::container::pvrtc::PvrtcCompression;
130
131        let compression =
132            container::pvrtc::detect_compression(reader).unwrap_or(PvrtcCompression::Unknown);
133        return Ok(ImageType::Pvrtc(compression));
134    }
135
136    // Check EAC before ETC2 since EAC is more specific
137    #[cfg(feature = "eac")]
138    if container::pkm::matches_eac(&header) {
139        use crate::container::pkm::PkmCompression;
140
141        let compression =
142            container::pkm::detect_compression(reader).unwrap_or(PkmCompression::Unknown);
143        return Ok(ImageType::Eac(compression));
144    }
145
146    #[cfg(feature = "etc2")]
147    if container::pkm::matches(&header) {
148        use crate::container::pkm::PkmCompression;
149
150        let compression =
151            container::pkm::detect_compression(reader).unwrap_or(PkmCompression::Unknown);
152        return Ok(ImageType::Etc2(compression));
153    }
154
155    #[cfg(feature = "exr")]
156    if exr::matches(&header) {
157        return Ok(ImageType::Exr);
158    }
159
160    #[cfg(feature = "hdr")]
161    if hdr::matches(&header) {
162        return Ok(ImageType::Hdr);
163    }
164
165    #[cfg(feature = "dds")]
166    if container::dds::matches(&header) {
167        use crate::container::dds::DdsCompression;
168
169        let compression =
170            container::dds::detect_compression(reader).unwrap_or(DdsCompression::Unknown);
171        return Ok(ImageType::Dds(compression));
172    }
173
174    #[cfg(feature = "ktx2")]
175    if ktx2::matches(&header) {
176        return Ok(ImageType::Ktx2);
177    }
178
179    #[cfg(feature = "qoi")]
180    if qoi::matches(&header) {
181        return Ok(ImageType::Qoi);
182    }
183
184    #[cfg(feature = "farbfeld")]
185    if farbfeld::matches(&header) {
186        return Ok(ImageType::Farbfeld);
187    }
188
189    #[cfg(feature = "pnm")]
190    if pnm::matches(&header) {
191        return Ok(ImageType::Pnm);
192    }
193
194    #[cfg(feature = "vtf")]
195    if vtf::matches(&header) {
196        return Ok(ImageType::Vtf);
197    }
198
199    #[cfg(feature = "ilbm")]
200    if ilbm::matches(&header) {
201        return Ok(ImageType::Ilbm);
202    }
203
204    // Keep TGA last because it has the highest probability of false positives
205    #[cfg(feature = "tga")]
206    if tga::matches(&header, reader) {
207        return Ok(ImageType::Tga);
208    }
209
210    Err(ImageError::NotSupported)
211}