ai_imagesize/lib.rs
1#![no_std]
2#![allow(dead_code)]
3
4extern crate alloc;
5
6use core::fmt;
7use no_std_io::io::{BufRead, Cursor, Seek};
8
9#[cfg(feature = "std")]
10extern crate std;
11#[cfg(feature = "std")]
12use std::fs::File;
13#[cfg(feature = "std")]
14use std::path::Path;
15
16mod container;
17mod formats;
18mod util;
19
20pub use container::{
21 atc::AtcCompression, dds::DdsCompression, heif::Compression, pkm::PkmCompression,
22 pvrtc::PvrtcCompression,
23};
24
25/// Groups related compression algorithms regardless of their container format
26#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
27pub enum CompressionFamily {
28 /// Block Compression family (BC1-7, also known as DXT1-5, ATI1-2)
29 BlockCompression,
30 /// Ericsson Texture Compression family (ETC1, ETC2 variants)
31 Etc,
32 /// Ericsson Alpha Compression (EAC R11, RG11)
33 Eac,
34 /// PowerVR Texture Compression
35 Pvrtc,
36 /// Adaptive Scalable Texture Compression
37 Astc,
38 /// Adaptive Texture Compression (Qualcomm Adreno)
39 Atc,
40 /// Uncompressed formats
41 Uncompressed,
42}
43
44#[allow(unused_imports)]
45use {
46 container::heif::{self},
47 formats::*,
48};
49
50/// An Error type used in failure cases.
51#[derive(Debug)]
52pub enum ImageError {
53 /// Used when the given data is not a supported format.
54 NotSupported,
55 /// Used when the image has an invalid format.
56 CorruptedImage,
57 /// Used when an IoError occurs when trying to read the given data.
58 IoError(no_std_io::io::Error),
59}
60
61impl core::error::Error for ImageError {}
62
63impl fmt::Display for ImageError {
64 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
65 use self::ImageError::*;
66 match self {
67 NotSupported => f.write_str("Could not decode image"),
68 CorruptedImage => f.write_str("Hit end of file before finding size"),
69 IoError(error) => error.fmt(f),
70 }
71 }
72}
73
74impl From<no_std_io::io::Error> for ImageError {
75 fn from(err: no_std_io::io::Error) -> ImageError {
76 ImageError::IoError(err)
77 }
78}
79
80pub type ImageResult<T> = Result<T, ImageError>;
81
82/// Types of image formats that this crate can identify.
83///
84/// Many container formats support multiple inner compression formats. For these formats,
85/// the enum contains the inner compression type to provide more detailed information:
86///
87/// - `Dds(DdsCompression)` - DirectDraw Surface with various BC compression formats
88/// - `Etc2(PkmCompression)` - ETC/PKM container with ETC1, ETC2, EAC variants
89/// - `Eac(PkmCompression)` - EAC formats (unified with ETC2 detection)
90/// - `Atc(AtcCompression)` - Adaptive Texture Compression variants
91/// - `Pvrtc(PvrtcCompression)` - PowerVR texture compression with 2bpp/4bpp variants
92///
93/// # Helper Methods
94///
95/// The `ImageType` provides several helper methods to query compression information
96/// across different container formats:
97///
98/// - [`compression_family()`](ImageType::compression_family) - Groups related compression algorithms
99/// - [`is_block_compressed()`](ImageType::is_block_compressed) - Checks for BC/DXT compression
100/// - [`container_format()`](ImageType::container_format) - Returns container format name
101/// - [`is_multi_compression_container()`](ImageType::is_multi_compression_container) - Checks if container supports multiple compression types
102///
103/// # Examples
104///
105/// ## Basic Format Detection
106///
107/// ```rust
108/// use ai_imagesize::{image_type, ImageType, PkmCompression};
109///
110/// // Create a PKM header for ETC2 format
111/// let mut header = vec![b'P', b'K', b'M', b' ', b'2', b'0'];
112/// header.extend_from_slice(&0x0001u16.to_be_bytes()); // ETC2 RGB
113/// header.extend_from_slice(&[0x00, 0x40, 0x00, 0x40]); // Extended dimensions
114/// header.extend_from_slice(&[0x00, 0x40, 0x00, 0x40]); // Original dimensions
115///
116/// match image_type(&header).unwrap() {
117/// ImageType::Etc2(PkmCompression::Etc2) => println!("This is ETC2 RGB format"),
118/// ImageType::Etc2(compression) => println!("This is ETC2 format: {:?}", compression),
119/// other => println!("Other format: {:?}", other),
120/// }
121/// ```
122///
123/// ## Using Helper Methods for Cross-Container Queries
124///
125/// ```rust
126/// use ai_imagesize::{ImageType, CompressionFamily, DdsCompression, PvrtcCompression};
127///
128/// // Query compression families across different containers
129/// let dds_bc1 = ImageType::Dds(DdsCompression::Bc1);
130/// let pvr_etc2 = ImageType::Pvrtc(PvrtcCompression::Etc2Rgb);
131/// let png = ImageType::Png;
132///
133/// // Group related compression algorithms
134/// assert_eq!(dds_bc1.compression_family(), Some(CompressionFamily::BlockCompression));
135/// assert_eq!(pvr_etc2.compression_family(), Some(CompressionFamily::Etc));
136/// assert_eq!(png.compression_family(), None); // Simple formats don't have compression
137///
138/// // Check for specific compression types
139/// assert!(dds_bc1.is_block_compressed());
140/// assert!(!pvr_etc2.is_block_compressed());
141///
142/// // Identify container formats
143/// assert_eq!(dds_bc1.container_format(), Some("DDS"));
144/// assert_eq!(pvr_etc2.container_format(), Some("PowerVR"));
145/// assert_eq!(png.container_format(), None);
146///
147/// // Check multi-compression support
148/// assert!(dds_bc1.is_multi_compression_container()); // DDS supports BC1-7, RGBA, etc.
149/// assert!(pvr_etc2.is_multi_compression_container()); // PowerVR supports PVRTC, ETC2, EAC
150/// ```
151#[non_exhaustive]
152#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
153pub enum ImageType {
154 /// Animated sprite image format
155 /// <https://github.com/aseprite/aseprite>
156 #[cfg(feature = "aesprite")]
157 Aseprite,
158 /// Adaptive Scalable Texture Compression
159 #[cfg(feature = "astc")]
160 Astc,
161 /// Adaptive Texture Compression
162 #[cfg(feature = "atc")]
163 Atc(AtcCompression),
164 /// Standard Bitmap
165 #[cfg(feature = "bmp")]
166 Bmp,
167 /// DirectDraw Surface
168 #[cfg(feature = "dds")]
169 Dds(DdsCompression),
170 /// Ericsson Texture Compression - Alpha Channel (now unified with ETC2)
171 #[cfg(feature = "eac")]
172 Eac(PkmCompression),
173 /// Ericsson Texture Compression 2 (includes ETC1, ETC2 variants)
174 #[cfg(feature = "etc2")]
175 Etc2(PkmCompression),
176 /// OpenEXR
177 #[cfg(feature = "exr")]
178 Exr,
179 /// Farbfeld
180 /// <https://tools.suckless.org/farbfeld/>
181 #[cfg(feature = "farbfeld")]
182 Farbfeld,
183 /// Standard GIF
184 #[cfg(feature = "gif")]
185 Gif,
186 /// Radiance HDR
187 #[cfg(feature = "hdr")]
188 Hdr,
189 /// Image Container Format
190 #[cfg(feature = "heif")]
191 Heif(Compression),
192 /// Icon file
193 #[cfg(feature = "ico")]
194 Ico,
195 /// Interleaved Bitmap
196 #[cfg(feature = "ilbm")]
197 Ilbm,
198 /// Standard JPEG
199 #[cfg(feature = "jpeg")]
200 Jpeg,
201 /// JPEG XL
202 #[cfg(feature = "jxl")]
203 Jxl,
204 /// Khronos Texture Container
205 #[cfg(feature = "ktx2")]
206 Ktx2,
207 /// Standard PNG
208 #[cfg(feature = "png")]
209 Png,
210 /// Portable Any Map
211 #[cfg(feature = "pnm")]
212 Pnm,
213 /// PowerVR Texture Compression
214 #[cfg(feature = "pvrtc")]
215 Pvrtc(PvrtcCompression),
216 /// Photoshop Document
217 #[cfg(feature = "psd")]
218 Psd,
219 /// Quite OK Image Format
220 /// <https://qoiformat.org/>
221 #[cfg(feature = "qoi")]
222 Qoi,
223 /// Truevision Graphics Adapter
224 #[cfg(feature = "tga")]
225 Tga,
226 /// Standard TIFF
227 #[cfg(feature = "tiff")]
228 Tiff,
229 /// Valve Texture Format
230 #[cfg(feature = "vtf")]
231 Vtf,
232 /// Standard Webp
233 #[cfg(feature = "webp")]
234 Webp,
235}
236
237impl ImageType {
238 /// Returns the compression family for texture formats
239 ///
240 /// Groups related compression algorithms regardless of their container format.
241 /// Returns None for simple image formats like PNG, JPEG, etc.
242 ///
243 /// # Examples
244 ///
245 /// ```rust
246 /// use ai_imagesize::{ImageType, CompressionFamily, DdsCompression, PvrtcCompression};
247 ///
248 /// let dds_type = ImageType::Dds(DdsCompression::Bc1);
249 /// assert_eq!(dds_type.compression_family(), Some(CompressionFamily::BlockCompression));
250 ///
251 /// let pvrtc_etc2_type = ImageType::Pvrtc(PvrtcCompression::Etc2Rgb);
252 /// assert_eq!(pvrtc_etc2_type.compression_family(), Some(CompressionFamily::Etc));
253 ///
254 /// let png_type = ImageType::Png;
255 /// assert_eq!(png_type.compression_family(), None);
256 /// ```
257 pub fn compression_family(&self) -> Option<CompressionFamily> {
258 match self {
259 #[cfg(feature = "dds")]
260 ImageType::Dds(compression) => match compression {
261 DdsCompression::Bc1
262 | DdsCompression::Bc2
263 | DdsCompression::Bc3
264 | DdsCompression::Bc4
265 | DdsCompression::Bc5
266 | DdsCompression::Bc6h
267 | DdsCompression::Bc7 => Some(CompressionFamily::BlockCompression),
268 DdsCompression::Rgba32 | DdsCompression::Rgb24 => {
269 Some(CompressionFamily::Uncompressed)
270 }
271 DdsCompression::Unknown => None,
272 },
273
274 #[cfg(feature = "etc2")]
275 ImageType::Etc2(compression) => match compression {
276 PkmCompression::Etc1
277 | PkmCompression::Etc2
278 | PkmCompression::Etc2A1
279 | PkmCompression::Etc2A8 => Some(CompressionFamily::Etc),
280 PkmCompression::EacR
281 | PkmCompression::EacRg
282 | PkmCompression::EacRSigned
283 | PkmCompression::EacRgSigned => Some(CompressionFamily::Eac),
284 PkmCompression::Unknown => None,
285 },
286
287 #[cfg(feature = "eac")]
288 ImageType::Eac(compression) => match compression {
289 PkmCompression::EacR
290 | PkmCompression::EacRg
291 | PkmCompression::EacRSigned
292 | PkmCompression::EacRgSigned => Some(CompressionFamily::Eac),
293 PkmCompression::Etc1
294 | PkmCompression::Etc2
295 | PkmCompression::Etc2A1
296 | PkmCompression::Etc2A8 => Some(CompressionFamily::Etc),
297 PkmCompression::Unknown => None,
298 },
299
300 #[cfg(feature = "pvrtc")]
301 ImageType::Pvrtc(compression) => match compression {
302 PvrtcCompression::Pvrtc2BppRgb
303 | PvrtcCompression::Pvrtc2BppRgba
304 | PvrtcCompression::Pvrtc4BppRgb
305 | PvrtcCompression::Pvrtc4BppRgba => Some(CompressionFamily::Pvrtc),
306 PvrtcCompression::Etc2Rgb
307 | PvrtcCompression::Etc2Rgba
308 | PvrtcCompression::Etc2RgbA1 => Some(CompressionFamily::Etc),
309 PvrtcCompression::EacR11 | PvrtcCompression::EacRg11 => {
310 Some(CompressionFamily::Eac)
311 }
312 PvrtcCompression::Unknown => None,
313 },
314
315 #[cfg(feature = "atc")]
316 ImageType::Atc(_) => Some(CompressionFamily::Atc),
317
318 #[cfg(feature = "astc")]
319 ImageType::Astc => Some(CompressionFamily::Astc),
320
321 // Simple formats don't have compression families
322 _ => None,
323 }
324 }
325
326 /// Returns true if the image uses block compression (BC/DXT family)
327 ///
328 /// Block compression includes BC1-7 formats (also known as DXT1-5, ATI1-2).
329 ///
330 /// # Examples
331 ///
332 /// ```rust
333 /// use ai_imagesize::{ImageType, DdsCompression};
334 ///
335 /// let bc1_type = ImageType::Dds(DdsCompression::Bc1);
336 /// assert!(bc1_type.is_block_compressed());
337 ///
338 /// let png_type = ImageType::Png;
339 /// assert!(!png_type.is_block_compressed());
340 /// ```
341 pub fn is_block_compressed(&self) -> bool {
342 matches!(
343 self.compression_family(),
344 Some(CompressionFamily::BlockCompression)
345 )
346 }
347
348 /// Returns the container format name for texture formats
349 ///
350 /// Returns a human-readable string identifying the container format.
351 /// Returns None for simple image formats.
352 ///
353 /// # Examples
354 ///
355 /// ```rust
356 /// use ai_imagesize::{ImageType, DdsCompression, PvrtcCompression};
357 ///
358 /// let dds_type = ImageType::Dds(DdsCompression::Bc1);
359 /// assert_eq!(dds_type.container_format(), Some("DDS"));
360 ///
361 /// let pvr_type = ImageType::Pvrtc(PvrtcCompression::Pvrtc2BppRgb);
362 /// assert_eq!(pvr_type.container_format(), Some("PowerVR"));
363 ///
364 /// let png_type = ImageType::Png;
365 /// assert_eq!(png_type.container_format(), None);
366 /// ```
367 pub fn container_format(&self) -> Option<&'static str> {
368 match self {
369 #[cfg(feature = "dds")]
370 ImageType::Dds(_) => Some("DDS"),
371
372 #[cfg(feature = "etc2")]
373 ImageType::Etc2(_) => Some("PKM"),
374
375 #[cfg(feature = "eac")]
376 ImageType::Eac(_) => Some("PKM"),
377
378 #[cfg(feature = "pvrtc")]
379 ImageType::Pvrtc(_) => Some("PowerVR"),
380
381 #[cfg(feature = "atc")]
382 ImageType::Atc(_) => Some("PKM"), // ATC typically uses PKM containers
383
384 #[cfg(feature = "astc")]
385 ImageType::Astc => Some("ASTC"), // Direct ASTC format
386
387 #[cfg(feature = "heif")]
388 ImageType::Heif(_) => Some("HEIF"),
389
390 #[cfg(feature = "ktx2")]
391 ImageType::Ktx2 => Some("KTX2"),
392
393 // Simple formats don't have containers
394 _ => None,
395 }
396 }
397
398 /// Returns true if the image format supports multiple compression types within the same container
399 ///
400 /// Some container formats like PowerVR can store different compression algorithms.
401 ///
402 /// # Examples
403 ///
404 /// ```rust
405 /// use ai_imagesize::{ImageType, PvrtcCompression, DdsCompression};
406 ///
407 /// let pvr_type = ImageType::Pvrtc(PvrtcCompression::Etc2Rgb);
408 /// assert!(pvr_type.is_multi_compression_container());
409 ///
410 /// let dds_type = ImageType::Dds(DdsCompression::Bc1);
411 /// assert!(dds_type.is_multi_compression_container());
412 ///
413 /// let png_type = ImageType::Png;
414 /// assert!(!png_type.is_multi_compression_container());
415 /// ```
416 pub fn is_multi_compression_container(&self) -> bool {
417 match self {
418 #[cfg(feature = "dds")]
419 ImageType::Dds(_) => true, // DDS supports BC1-7, RGBA, etc.
420
421 #[cfg(feature = "pvrtc")]
422 ImageType::Pvrtc(_) => true, // PowerVR supports PVRTC, ETC2, EAC
423
424 #[cfg(feature = "ktx2")]
425 ImageType::Ktx2 => true, // KTX2 supports many formats
426
427 _ => false,
428 }
429 }
430
431 /// Calls the correct image size method based on the image type
432 ///
433 /// # Arguments
434 /// * `reader` - A reader for the data
435 pub fn reader_size<R: BufRead + Seek>(&self, reader: &mut R) -> ImageResult<ImageSize> {
436 match self {
437 #[cfg(feature = "aesprite")]
438 ImageType::Aseprite => aesprite::size(reader),
439 #[cfg(feature = "astc")]
440 ImageType::Astc => astc::size(reader),
441 #[cfg(feature = "atc")]
442 ImageType::Atc(..) => container::atc::size(reader),
443 #[cfg(feature = "bmp")]
444 ImageType::Bmp => bmp::size(reader),
445 #[cfg(feature = "dds")]
446 ImageType::Dds(..) => container::dds::size(reader),
447 #[cfg(feature = "eac")]
448 ImageType::Eac(..) => container::pkm::size(reader),
449 #[cfg(feature = "etc2")]
450 ImageType::Etc2(..) => container::pkm::size(reader),
451 #[cfg(feature = "exr")]
452 ImageType::Exr => exr::size(reader),
453 #[cfg(feature = "farbfeld")]
454 ImageType::Farbfeld => farbfeld::size(reader),
455 #[cfg(feature = "gif")]
456 ImageType::Gif => gif::size(reader),
457 #[cfg(feature = "hdr")]
458 ImageType::Hdr => hdr::size(reader),
459 #[cfg(feature = "ico")]
460 ImageType::Ico => ico::size(reader),
461 #[cfg(feature = "ilbm")]
462 ImageType::Ilbm => ilbm::size(reader),
463 #[cfg(feature = "jpeg")]
464 ImageType::Jpeg => jpeg::size(reader),
465 #[cfg(feature = "jxl")]
466 ImageType::Jxl => jxl::size(reader),
467 #[cfg(feature = "ktx2")]
468 ImageType::Ktx2 => ktx2::size(reader),
469 #[cfg(feature = "png")]
470 ImageType::Png => png::size(reader),
471 #[cfg(feature = "pnm")]
472 ImageType::Pnm => pnm::size(reader),
473 #[cfg(feature = "pvrtc")]
474 ImageType::Pvrtc(..) => container::pvrtc::size(reader),
475 #[cfg(feature = "psd")]
476 ImageType::Psd => psd::size(reader),
477 #[cfg(feature = "qoi")]
478 ImageType::Qoi => qoi::size(reader),
479 #[cfg(feature = "tga")]
480 ImageType::Tga => tga::size(reader),
481 #[cfg(feature = "tiff")]
482 ImageType::Tiff => tiff::size(reader),
483 #[cfg(feature = "vtf")]
484 ImageType::Vtf => vtf::size(reader),
485 #[cfg(feature = "webp")]
486 ImageType::Webp => webp::size(reader),
487
488 #[cfg(feature = "heif")]
489 ImageType::Heif(..) => heif::size(reader),
490
491 // Required for when no format features are enabled
492 #[allow(unreachable_patterns)]
493 _ => { let _ = reader; Err(ImageError::NotSupported) }
494 }
495 }
496}
497
498/// Holds the size information of an image.
499#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
500pub struct ImageSize {
501 /// Width of an image in pixels.
502 pub width: usize,
503 /// Height of an image in pixels.
504 pub height: usize,
505}
506
507impl Ord for ImageSize {
508 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
509 (self.width * self.height).cmp(&(other.width * other.height))
510 }
511}
512
513impl PartialOrd for ImageSize {
514 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
515 Some(self.cmp(other))
516 }
517}
518
519/// Get the image type from a header
520///
521/// # Arguments
522/// * `header` - The header of the file.
523///
524/// # Remarks
525///
526/// This will check the header to determine what image type the data is.
527pub fn image_type(header: &[u8]) -> ImageResult<ImageType> {
528 formats::image_type(&mut Cursor::new(header))
529}
530
531/// Get the image size from a local file
532///
533/// # Arguments
534/// * `path` - A local path to the file to parse.
535///
536/// # Remarks
537///
538/// Will try to read as little of the file as possible in order to get the
539/// proper size information.
540///
541/// # Error
542///
543/// This method will return an [`ImageError`] under the following conditions:
544///
545/// * The header isn't recognized as a supported image format
546/// * The data isn't long enough to find the size for the given format
547///
548/// The minimum data required is 12 bytes. Anything shorter will return [`ImageError::IoError`].
549///
550/// # Examples
551///
552/// ```
553/// use ai_imagesize::size;
554///
555/// match size("test/test.webp") {
556/// Ok(dim) => {
557/// assert_eq!(dim.width, 716);
558/// assert_eq!(dim.height, 716);
559/// }
560/// Err(why) => println!("Error getting size: {:?}", why)
561/// }
562/// ```
563///
564/// [`ImageError`]: enum.ImageError.html
565#[cfg(feature = "std")]
566pub fn size<P: AsRef<Path>>(path: P) -> ImageResult<ImageSize> {
567 let file = File::open(path)?;
568 let reader = std::io::BufReader::new(file);
569 reader_size(reader)
570}
571
572/// Get the image size from a block of raw data.
573///
574/// # Arguments
575/// * `data` - A Vec containing the data to parse for image size.
576///
577/// # Error
578///
579/// This method will return an [`ImageError`] under the following conditions:
580///
581/// * The header isn't recognized as a supported image format
582/// * The data isn't long enough to find the size for the given format
583///
584/// The minimum data required is 12 bytes. Anything shorter will return [`ImageError::IoError`].
585///
586/// # Examples
587///
588/// ```
589/// use ai_imagesize::blob_size;
590///
591/// // First few bytes of arbitrary data.
592/// let data = vec![0x89, 0x89, 0x89, 0x89, 0x0D, 0x0A, 0x1A, 0x0A,
593/// 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52,
594/// 0x00, 0x00, 0x00, 0x7B, 0x01, 0x00, 0x01, 0x41,
595/// 0x08, 0x06, 0x00, 0x00, 0x00, 0x9A, 0x38, 0xC4];
596///
597/// assert_eq!(blob_size(&data).is_err(), true);
598/// ```
599///
600/// [`ImageError`]: enum.ImageError.html
601pub fn blob_size(data: &[u8]) -> ImageResult<ImageSize> {
602 let reader = Cursor::new(data);
603 reader_size(reader)
604}
605
606/// Get the image size from a reader
607///
608/// # Arguments
609/// * `reader` - A reader for the data
610///
611/// # Error
612///
613/// This method will return an [`ImageError`] under the following conditions:
614///
615/// * The header isn't recognized as a supported image format
616/// * The data isn't long enough to find the size for the given format
617///
618/// The minimum data required is 12 bytes. Anything shorter will return [`ImageError::IoError`].
619///
620/// # Examples
621///
622/// ```
623/// use no_std_io::io::Cursor; // or std::io::Cursor with the "std" feature
624/// use ai_imagesize::reader_size;
625///
626/// // PNG Header with size 123x321
627/// let reader = Cursor::new([
628/// 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
629/// 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52,
630/// 0x00, 0x00, 0x00, 0x7B, 0x00, 0x00, 0x01, 0x41,
631/// 0x08, 0x06, 0x00, 0x00, 0x00, 0x9A, 0x38, 0xC4
632/// ]);
633///
634/// match reader_size(reader) {
635/// Ok(dim) => {
636/// assert_eq!(dim.width, 123);
637/// assert_eq!(dim.height, 321);
638/// }
639/// Err(why) => println!("Error getting reader size: {:?}", why)
640/// }
641/// ```
642///
643/// [`ImageError`]: enum.ImageError.html
644pub fn reader_size<R: BufRead + Seek>(mut reader: R) -> ImageResult<ImageSize> {
645 reader_type(&mut reader)?.reader_size(&mut reader)
646}
647
648/// Get the image type from a reader
649///
650/// # Arguments
651/// * `reader` - A reader for the data
652///
653/// # Remarks
654///
655/// This will check the header to determine what image type the data is.
656pub fn reader_type<R: BufRead + Seek>(mut reader: R) -> ImageResult<ImageType> {
657 formats::image_type(&mut reader)
658}