imagesize/lib.rs
1#![allow(dead_code)]
2
3use std::error::Error;
4use std::fmt;
5use std::fs::File;
6use std::io::{BufRead, BufReader, Cursor, Seek};
7use std::path::Path;
8
9mod container;
10mod formats;
11mod util;
12
13pub use container::heif::Compression;
14use {
15 container::heif::{self},
16 formats::*,
17};
18
19/// An Error type used in failure cases.
20#[derive(Debug)]
21pub enum ImageError {
22 /// Used when the given data is not a supported format.
23 NotSupported,
24 /// Used when the image has an invalid format.
25 CorruptedImage,
26 /// Used when an IoError occurs when trying to read the given data.
27 IoError(std::io::Error),
28}
29
30impl Error for ImageError {}
31
32impl fmt::Display for ImageError {
33 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
34 use self::ImageError::*;
35 match self {
36 NotSupported => f.write_str("Could not decode image"),
37 CorruptedImage => f.write_str("Hit end of file before finding size"),
38 IoError(error) => error.fmt(f),
39 }
40 }
41}
42
43impl From<std::io::Error> for ImageError {
44 fn from(err: std::io::Error) -> ImageError {
45 ImageError::IoError(err)
46 }
47}
48
49pub type ImageResult<T> = Result<T, ImageError>;
50
51/// Types of image formats that this crate can identify.
52#[non_exhaustive]
53#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
54pub enum ImageType {
55 /// Animated sprite image format
56 /// <https://github.com/aseprite/aseprite>
57 #[cfg(feature = "aesprite")]
58 Aseprite,
59 /// Standard Bitmap
60 #[cfg(feature = "bmp")]
61 Bmp,
62 /// DirectDraw Surface
63 #[cfg(feature = "dds")]
64 Dds,
65 /// OpenEXR
66 #[cfg(feature = "exr")]
67 Exr,
68 /// Farbfeld
69 /// <https://tools.suckless.org/farbfeld/>
70 #[cfg(feature = "farbfeld")]
71 Farbfeld,
72 /// Standard GIF
73 #[cfg(feature = "gif")]
74 Gif,
75 /// Radiance HDR
76 #[cfg(feature = "hdr")]
77 Hdr,
78 /// Image Container Format
79 #[cfg(feature = "heif")]
80 Heif(Compression),
81 /// Icon file
82 #[cfg(feature = "ico")]
83 Ico,
84 /// Interleaved Bitmap
85 #[cfg(feature = "ilbm")]
86 Ilbm,
87 /// Standard JPEG
88 #[cfg(feature = "jpeg")]
89 Jpeg,
90 /// JPEG XL
91 #[cfg(feature = "jxl")]
92 Jxl,
93 /// Khronos Texture Container
94 #[cfg(feature = "ktx2")]
95 Ktx2,
96 /// Standard PNG
97 #[cfg(feature = "png")]
98 Png,
99 /// Portable Any Map
100 #[cfg(feature = "pnm")]
101 Pnm,
102 /// Photoshop Document
103 #[cfg(feature = "psd")]
104 Psd,
105 /// Quite OK Image Format
106 /// <https://qoiformat.org/>
107 #[cfg(feature = "qoi")]
108 Qoi,
109 /// Truevision Graphics Adapter
110 #[cfg(feature = "tga")]
111 Tga,
112 /// Standard TIFF
113 #[cfg(feature = "tiff")]
114 Tiff,
115 /// Valve Texture Format
116 #[cfg(feature = "vtf")]
117 Vtf,
118 /// Standard Webp
119 #[cfg(feature = "webp")]
120 Webp,
121}
122
123impl ImageType {
124 /// Calls the correct image size method based on the image type
125 ///
126 /// # Arguments
127 /// * `reader` - A reader for the data
128 pub fn reader_size<R: BufRead + Seek>(&self, reader: &mut R) -> ImageResult<ImageSize> {
129 match self {
130 #[cfg(feature = "aesprite")]
131 ImageType::Aseprite => aesprite::size(reader),
132 #[cfg(feature = "bmp")]
133 ImageType::Bmp => bmp::size(reader),
134 #[cfg(feature = "dds")]
135 ImageType::Dds => dds::size(reader),
136 #[cfg(feature = "exr")]
137 ImageType::Exr => exr::size(reader),
138 #[cfg(feature = "farbfeld")]
139 ImageType::Farbfeld => farbfeld::size(reader),
140 #[cfg(feature = "gif")]
141 ImageType::Gif => gif::size(reader),
142 #[cfg(feature = "hdr")]
143 ImageType::Hdr => hdr::size(reader),
144 #[cfg(feature = "ico")]
145 ImageType::Ico => ico::size(reader),
146 #[cfg(feature = "ilbm")]
147 ImageType::Ilbm => ilbm::size(reader),
148 #[cfg(feature = "jpeg")]
149 ImageType::Jpeg => jpeg::size(reader),
150 #[cfg(feature = "jxl")]
151 ImageType::Jxl => jxl::size(reader),
152 #[cfg(feature = "ktx2")]
153 ImageType::Ktx2 => ktx2::size(reader),
154 #[cfg(feature = "png")]
155 ImageType::Png => png::size(reader),
156 #[cfg(feature = "pnm")]
157 ImageType::Pnm => pnm::size(reader),
158 #[cfg(feature = "psd")]
159 ImageType::Psd => psd::size(reader),
160 #[cfg(feature = "qoi")]
161 ImageType::Qoi => qoi::size(reader),
162 #[cfg(feature = "tga")]
163 ImageType::Tga => tga::size(reader),
164 #[cfg(feature = "tiff")]
165 ImageType::Tiff => tiff::size(reader),
166 #[cfg(feature = "vtf")]
167 ImageType::Vtf => vtf::size(reader),
168 #[cfg(feature = "webp")]
169 ImageType::Webp => webp::size(reader),
170
171 #[cfg(feature = "heif")]
172 ImageType::Heif(..) => heif::size(reader),
173 }
174 }
175}
176
177/// Holds the size information of an image.
178#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
179pub struct ImageSize {
180 /// Width of an image in pixels.
181 pub width: usize,
182 /// Height of an image in pixels.
183 pub height: usize,
184}
185
186impl Ord for ImageSize {
187 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
188 (self.width * self.height).cmp(&(other.width * other.height))
189 }
190}
191
192impl PartialOrd for ImageSize {
193 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
194 Some(self.cmp(other))
195 }
196}
197
198/// Get the image type from a header
199///
200/// # Arguments
201/// * `header` - The header of the file.
202///
203/// # Remarks
204///
205/// This will check the header to determine what image type the data is.
206pub fn image_type(header: &[u8]) -> ImageResult<ImageType> {
207 formats::image_type(&mut Cursor::new(header))
208}
209
210/// Get the image size from a local file
211///
212/// # Arguments
213/// * `path` - A local path to the file to parse.
214///
215/// # Remarks
216///
217/// Will try to read as little of the file as possible in order to get the
218/// proper size information.
219///
220/// # Error
221///
222/// This method will return an [`ImageError`] under the following conditions:
223///
224/// * The header isn't recognized as a supported image format
225/// * The data isn't long enough to find the size for the given format
226///
227/// The minimum data required is 12 bytes. Anything shorter will return [`ImageError::IoError`].
228///
229/// # Examples
230///
231/// ```
232/// use imagesize::size;
233///
234/// match size("test/test.webp") {
235/// Ok(dim) => {
236/// assert_eq!(dim.width, 716);
237/// assert_eq!(dim.height, 716);
238/// }
239/// Err(why) => println!("Error getting size: {:?}", why)
240/// }
241/// ```
242///
243/// [`ImageError`]: enum.ImageError.html
244pub fn size<P: AsRef<Path>>(path: P) -> ImageResult<ImageSize> {
245 let file = File::open(path)?;
246 let reader = BufReader::new(file);
247 reader_size(reader)
248}
249
250/// Get the image size from a block of raw data.
251///
252/// # Arguments
253/// * `data` - A Vec containing the data to parse for image size.
254///
255/// # Error
256///
257/// This method will return an [`ImageError`] under the following conditions:
258///
259/// * The header isn't recognized as a supported image format
260/// * The data isn't long enough to find the size for the given format
261///
262/// The minimum data required is 12 bytes. Anything shorter will return [`ImageError::IoError`].
263///
264/// # Examples
265///
266/// ```
267/// use imagesize::blob_size;
268///
269/// // First few bytes of arbitrary data.
270/// let data = vec![0x89, 0x89, 0x89, 0x89, 0x0D, 0x0A, 0x1A, 0x0A,
271/// 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52,
272/// 0x00, 0x00, 0x00, 0x7B, 0x01, 0x00, 0x01, 0x41,
273/// 0x08, 0x06, 0x00, 0x00, 0x00, 0x9A, 0x38, 0xC4];
274///
275/// assert_eq!(blob_size(&data).is_err(), true);
276/// ```
277///
278/// [`ImageError`]: enum.ImageError.html
279pub fn blob_size(data: &[u8]) -> ImageResult<ImageSize> {
280 let reader = Cursor::new(data);
281 reader_size(reader)
282}
283
284/// Get the image size from a reader
285///
286/// # Arguments
287/// * `reader` - A reader for the data
288///
289/// # Error
290///
291/// This method will return an [`ImageError`] under the following conditions:
292///
293/// * The header isn't recognized as a supported image format
294/// * The data isn't long enough to find the size for the given format
295///
296/// The minimum data required is 12 bytes. Anything shorter will return [`ImageError::IoError`].
297///
298/// # Examples
299///
300/// ```
301/// use std::io::Cursor;
302/// use imagesize::reader_size;
303///
304/// // PNG Header with size 123x321
305/// let reader = Cursor::new([
306/// 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
307/// 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52,
308/// 0x00, 0x00, 0x00, 0x7B, 0x00, 0x00, 0x01, 0x41,
309/// 0x08, 0x06, 0x00, 0x00, 0x00, 0x9A, 0x38, 0xC4
310/// ]);
311///
312/// match reader_size(reader) {
313/// Ok(dim) => {
314/// assert_eq!(dim.width, 123);
315/// assert_eq!(dim.height, 321);
316/// }
317/// Err(why) => println!("Error getting reader size: {:?}", why)
318/// }
319/// ```
320///
321/// [`ImageError`]: enum.ImageError.html
322pub fn reader_size<R: BufRead + Seek>(mut reader: R) -> ImageResult<ImageSize> {
323 reader_type(&mut reader)?.reader_size(&mut reader)
324}
325
326/// Get the image type from a reader
327///
328/// # Arguments
329/// * `reader` - A reader for the data
330///
331/// # Remarks
332///
333/// This will check the header to determine what image type the data is.
334pub fn reader_type<R: BufRead + Seek>(mut reader: R) -> ImageResult<ImageType> {
335 formats::image_type(&mut reader)
336}