imagesize/formats/
mod.rs

1pub mod aesprite;
2pub mod avif;
3pub mod bmp;
4pub mod dds;
5pub mod exr;
6pub mod farbfeld;
7pub mod gif;
8pub mod hdr;
9pub mod heif;
10pub mod ico;
11pub mod jpeg;
12pub mod jxl;
13pub mod ktx2;
14pub mod png;
15pub mod pnm;
16pub mod psd;
17pub mod qoi;
18pub mod tga;
19pub mod tiff;
20pub mod vtf;
21pub mod webp;
22
23use crate::{ImageError, ImageResult, ImageType};
24use std::io::{BufRead, Seek};
25
26pub fn image_type<R: BufRead + Seek>(reader: &mut R) -> ImageResult<ImageType> {
27    let mut header = [0; 12];
28    reader.read_exact(&mut header)?;
29
30    // Currently there are no formats where 1 byte is enough to determine format
31    if header.len() < 2 {
32        return Err(
33            std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "Not enough data").into(),
34        );
35    }
36
37    // This is vaguely organized in what I assume are the most commonly used formats.
38    // I don't know how much this matters for actual execution time.
39    if jpeg::matches(&header) {
40        return Ok(ImageType::Jpeg);
41    }
42
43    if png::matches(&header) {
44        return Ok(ImageType::Png);
45    }
46
47    if gif::matches(&header) {
48        return Ok(ImageType::Gif);
49    }
50
51    if tiff::matches(&header) {
52        return Ok(ImageType::Tiff);
53    }
54
55    if webp::matches(&header) {
56        return Ok(ImageType::Webp);
57    }
58
59    if heif::matches(&header) {
60        return Ok(ImageType::Heif);
61    }
62
63    if avif::matches(&header) {
64        return Ok(ImageType::Avif);
65    }
66
67    if jxl::matches(&header) {
68        return Ok(ImageType::Jxl);
69    }
70
71    if bmp::matches(&header) {
72        return Ok(ImageType::Bmp);
73    }
74
75    if psd::matches(&header) {
76        return Ok(ImageType::Psd);
77    }
78
79    if ico::matches(&header) {
80        return Ok(ImageType::Ico);
81    }
82
83    if aesprite::matches(&header) {
84        return Ok(ImageType::Aseprite);
85    }
86
87    if exr::matches(&header) {
88        return Ok(ImageType::Exr);
89    }
90
91    if hdr::matches(&header) {
92        return Ok(ImageType::Hdr);
93    }
94
95    if dds::matches(&header) {
96        return Ok(ImageType::Dds);
97    }
98
99    if ktx2::matches(&header) {
100        return Ok(ImageType::Ktx2);
101    }
102
103    if qoi::matches(&header) {
104        return Ok(ImageType::Qoi);
105    }
106
107    if farbfeld::matches(&header) {
108        return Ok(ImageType::Farbfeld);
109    }
110
111    if pnm::matches(&header) {
112        return Ok(ImageType::Pnm);
113    }
114
115    if vtf::matches(&header) {
116        return Ok(ImageType::Vtf);
117    }
118
119    // Keep TGA last because it has the highest probability of false positives
120    if tga::matches(&header, reader) {
121        return Ok(ImageType::Tga);
122    }
123
124    Err(ImageError::NotSupported)
125}