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