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}
126