1#![allow(clippy::too_many_arguments)]
2use std::ffi::OsStr;
3use std::io;
4use std::io::Read;
5use std::ops::{Deref, DerefMut};
6use std::path::Path;
7use std::usize;
8
9use crate::color::{ColorType, ExtendedColorType};
10use crate::error::{
11 ImageError, ImageFormatHint, ImageResult, LimitError, LimitErrorKind, ParameterError,
12 ParameterErrorKind,
13};
14use crate::math::Rect;
15use crate::traits::Pixel;
16use crate::ImageBuffer;
17
18use crate::animation::Frames;
19
20#[cfg(feature = "pnm")]
21use crate::codecs::pnm::PnmSubtype;
22
23/// An enumeration of supported image formats.
24/// Not all formats support both encoding and decoding.
25#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
26#[non_exhaustive]
27pub enum ImageFormat {
28 /// An Image in PNG Format
29 Png,
30
31 /// An Image in JPEG Format
32 Jpeg,
33
34 /// An Image in GIF Format
35 Gif,
36
37 /// An Image in WEBP Format
38 WebP,
39
40 /// An Image in general PNM Format
41 Pnm,
42
43 /// An Image in TIFF Format
44 Tiff,
45
46 /// An Image in TGA Format
47 Tga,
48
49 /// An Image in DDS Format
50 Dds,
51
52 /// An Image in BMP Format
53 Bmp,
54
55 /// An Image in ICO Format
56 Ico,
57
58 /// An Image in Radiance HDR Format
59 Hdr,
60
61 /// An Image in OpenEXR Format
62 OpenExr,
63
64 /// An Image in farbfeld Format
65 Farbfeld,
66
67 /// An Image in AVIF format.
68 Avif,
69
70 /// An Image in QOI format.
71 Qoi,
72}
73
74impl ImageFormat {
75 /// Return the image format specified by a path's file extension.
76 ///
77 /// # Example
78 ///
79 /// ```
80 /// use image::ImageFormat;
81 ///
82 /// let format = ImageFormat::from_extension("jpg");
83 /// assert_eq!(format, Some(ImageFormat::Jpeg));
84 /// ```
85 #[inline]
86 pub fn from_extension<S>(ext: S) -> Option<Self>
87 where
88 S: AsRef<OsStr>,
89 {
90 // thin wrapper function to strip generics
91 fn inner(ext: &OsStr) -> Option<ImageFormat> {
92 let ext = ext.to_str()?.to_ascii_lowercase();
93
94 Some(match ext.as_str() {
95 "avif" => ImageFormat::Avif,
96 "jpg" | "jpeg" => ImageFormat::Jpeg,
97 "png" => ImageFormat::Png,
98 "gif" => ImageFormat::Gif,
99 "webp" => ImageFormat::WebP,
100 "tif" | "tiff" => ImageFormat::Tiff,
101 "tga" => ImageFormat::Tga,
102 "dds" => ImageFormat::Dds,
103 "bmp" => ImageFormat::Bmp,
104 "ico" => ImageFormat::Ico,
105 "hdr" => ImageFormat::Hdr,
106 "exr" => ImageFormat::OpenExr,
107 "pbm" | "pam" | "ppm" | "pgm" => ImageFormat::Pnm,
108 "ff" | "farbfeld" => ImageFormat::Farbfeld,
109 "qoi" => ImageFormat::Qoi,
110 _ => return None,
111 })
112 }
113
114 inner(ext.as_ref())
115 }
116
117 /// Return the image format specified by the path's file extension.
118 ///
119 /// # Example
120 ///
121 /// ```
122 /// use image::ImageFormat;
123 ///
124 /// let format = ImageFormat::from_path("images/ferris.png")?;
125 /// assert_eq!(format, ImageFormat::Png);
126 ///
127 /// # Ok::<(), image::error::ImageError>(())
128 /// ```
129 #[inline]
130 pub fn from_path<P>(path: P) -> ImageResult<Self>
131 where
132 P: AsRef<Path>,
133 {
134 // thin wrapper function to strip generics
135 fn inner(path: &Path) -> ImageResult<ImageFormat> {
136 let exact_ext = path.extension();
137 exact_ext
138 .and_then(ImageFormat::from_extension)
139 .ok_or_else(|| {
140 let format_hint = match exact_ext {
141 None => ImageFormatHint::Unknown,
142 Some(os) => ImageFormatHint::PathExtension(os.into()),
143 };
144 ImageError::Unsupported(format_hint.into())
145 })
146 }
147
148 inner(path.as_ref())
149 }
150
151 /// Return the image format specified by a MIME type.
152 ///
153 /// # Example
154 ///
155 /// ```
156 /// use image::ImageFormat;
157 ///
158 /// let format = ImageFormat::from_mime_type("image/png").unwrap();
159 /// assert_eq!(format, ImageFormat::Png);
160 /// ```
161 pub fn from_mime_type<M>(mime_type: M) -> Option<Self>
162 where
163 M: AsRef<str>,
164 {
165 match mime_type.as_ref() {
166 "image/avif" => Some(ImageFormat::Avif),
167 "image/jpeg" => Some(ImageFormat::Jpeg),
168 "image/png" => Some(ImageFormat::Png),
169 "image/gif" => Some(ImageFormat::Gif),
170 "image/webp" => Some(ImageFormat::WebP),
171 "image/tiff" => Some(ImageFormat::Tiff),
172 "image/x-targa" | "image/x-tga" => Some(ImageFormat::Tga),
173 "image/vnd-ms.dds" => Some(ImageFormat::Dds),
174 "image/bmp" => Some(ImageFormat::Bmp),
175 "image/x-icon" => Some(ImageFormat::Ico),
176 "image/vnd.radiance" => Some(ImageFormat::Hdr),
177 "image/x-exr" => Some(ImageFormat::OpenExr),
178 "image/x-portable-bitmap"
179 | "image/x-portable-graymap"
180 | "image/x-portable-pixmap"
181 | "image/x-portable-anymap" => Some(ImageFormat::Pnm),
182 // Qoi's MIME type is being worked on.
183 // See: https://github.com/phoboslab/qoi/issues/167
184 "image/x-qoi" => Some(ImageFormat::Qoi),
185 _ => None,
186 }
187 }
188
189 /// Return the MIME type for this image format or "application/octet-stream" if no MIME type
190 /// exists for the format.
191 ///
192 /// Some notes on a few of the MIME types:
193 ///
194 /// - The portable anymap format has a separate MIME type for the pixmap, graymap and bitmap
195 /// formats, but this method returns the general "image/x-portable-anymap" MIME type.
196 /// - The Targa format has two common MIME types, "image/x-targa" and "image/x-tga"; this
197 /// method returns "image/x-targa" for that format.
198 /// - The QOI MIME type is still a work in progress. This method returns "image/x-qoi" for
199 /// that format.
200 ///
201 /// # Example
202 ///
203 /// ```
204 /// use image::ImageFormat;
205 ///
206 /// let mime_type = ImageFormat::Png.to_mime_type();
207 /// assert_eq!(mime_type, "image/png");
208 /// ```
209 pub fn to_mime_type(&self) -> &'static str {
210 match self {
211 ImageFormat::Avif => "image/avif",
212 ImageFormat::Jpeg => "image/jpeg",
213 ImageFormat::Png => "image/png",
214 ImageFormat::Gif => "image/gif",
215 ImageFormat::WebP => "image/webp",
216 ImageFormat::Tiff => "image/tiff",
217 // the targa MIME type has two options, but this one seems to be used more
218 ImageFormat::Tga => "image/x-targa",
219 ImageFormat::Dds => "image/vnd-ms.dds",
220 ImageFormat::Bmp => "image/bmp",
221 ImageFormat::Ico => "image/x-icon",
222 ImageFormat::Hdr => "image/vnd.radiance",
223 ImageFormat::OpenExr => "image/x-exr",
224 // return the most general MIME type
225 ImageFormat::Pnm => "image/x-portable-anymap",
226 // Qoi's MIME type is being worked on.
227 // See: https://github.com/phoboslab/qoi/issues/167
228 ImageFormat::Qoi => "image/x-qoi",
229 // farbfield's MIME type taken from https://www.wikidata.org/wiki/Q28206109
230 ImageFormat::Farbfeld => "application/octet-stream",
231 }
232 }
233
234 /// Return if the ImageFormat can be decoded by the lib.
235 #[inline]
236 pub fn can_read(&self) -> bool {
237 // Needs to be updated once a new variant's decoder is added to free_functions.rs::load
238 match self {
239 ImageFormat::Png => true,
240 ImageFormat::Gif => true,
241 ImageFormat::Jpeg => true,
242 ImageFormat::WebP => true,
243 ImageFormat::Tiff => true,
244 ImageFormat::Tga => true,
245 ImageFormat::Dds => false,
246 ImageFormat::Bmp => true,
247 ImageFormat::Ico => true,
248 ImageFormat::Hdr => true,
249 ImageFormat::OpenExr => true,
250 ImageFormat::Pnm => true,
251 ImageFormat::Farbfeld => true,
252 ImageFormat::Avif => true,
253 ImageFormat::Qoi => true,
254 }
255 }
256
257 /// Return if the ImageFormat can be encoded by the lib.
258 #[inline]
259 pub fn can_write(&self) -> bool {
260 // Needs to be updated once a new variant's encoder is added to free_functions.rs::save_buffer_with_format_impl
261 match self {
262 ImageFormat::Gif => true,
263 ImageFormat::Ico => true,
264 ImageFormat::Jpeg => true,
265 ImageFormat::Png => true,
266 ImageFormat::Bmp => true,
267 ImageFormat::Tiff => true,
268 ImageFormat::Tga => true,
269 ImageFormat::Pnm => true,
270 ImageFormat::Farbfeld => true,
271 ImageFormat::Avif => true,
272 ImageFormat::WebP => true,
273 ImageFormat::Hdr => false,
274 ImageFormat::OpenExr => true,
275 ImageFormat::Dds => false,
276 ImageFormat::Qoi => true,
277 }
278 }
279
280 /// Return a list of applicable extensions for this format.
281 ///
282 /// All currently recognized image formats specify at least on extension but for future
283 /// compatibility you should not rely on this fact. The list may be empty if the format has no
284 /// recognized file representation, for example in case it is used as a purely transient memory
285 /// format.
286 ///
287 /// The method name `extensions` remains reserved for introducing another method in the future
288 /// that yields a slice of `OsStr` which is blocked by several features of const evaluation.
289 pub fn extensions_str(self) -> &'static [&'static str] {
290 match self {
291 ImageFormat::Png => &["png"],
292 ImageFormat::Jpeg => &["jpg", "jpeg"],
293 ImageFormat::Gif => &["gif"],
294 ImageFormat::WebP => &["webp"],
295 ImageFormat::Pnm => &["pbm", "pam", "ppm", "pgm"],
296 ImageFormat::Tiff => &["tiff", "tif"],
297 ImageFormat::Tga => &["tga"],
298 ImageFormat::Dds => &["dds"],
299 ImageFormat::Bmp => &["bmp"],
300 ImageFormat::Ico => &["ico"],
301 ImageFormat::Hdr => &["hdr"],
302 ImageFormat::OpenExr => &["exr"],
303 ImageFormat::Farbfeld => &["ff"],
304 // According to: https://aomediacodec.github.io/av1-avif/#mime-registration
305 ImageFormat::Avif => &["avif"],
306 ImageFormat::Qoi => &["qoi"],
307 }
308 }
309
310 /// Return the ImageFormats which are enabled for reading.
311 #[inline]
312 pub fn reading_enabled(&self) -> bool {
313 match self {
314 ImageFormat::Png => cfg!(feature = "png"),
315 ImageFormat::Gif => cfg!(feature = "gif"),
316 ImageFormat::Jpeg => cfg!(feature = "jpeg"),
317 ImageFormat::WebP => cfg!(feature = "webp"),
318 ImageFormat::Tiff => cfg!(feature = "tiff"),
319 ImageFormat::Tga => cfg!(feature = "tga"),
320 ImageFormat::Bmp => cfg!(feature = "bmp"),
321 ImageFormat::Ico => cfg!(feature = "ico"),
322 ImageFormat::Hdr => cfg!(feature = "hdr"),
323 ImageFormat::OpenExr => cfg!(feature = "openexr"),
324 ImageFormat::Pnm => cfg!(feature = "pnm"),
325 ImageFormat::Farbfeld => cfg!(feature = "farbfeld"),
326 ImageFormat::Avif => cfg!(feature = "avif"),
327 ImageFormat::Qoi => cfg!(feature = "qoi"),
328 ImageFormat::Dds => false,
329 }
330 }
331
332 /// Return the ImageFormats which are enabled for writing.
333 #[inline]
334 pub fn writing_enabled(&self) -> bool {
335 match self {
336 ImageFormat::Gif => cfg!(feature = "gif"),
337 ImageFormat::Ico => cfg!(feature = "ico"),
338 ImageFormat::Jpeg => cfg!(feature = "jpeg"),
339 ImageFormat::Png => cfg!(feature = "png"),
340 ImageFormat::Bmp => cfg!(feature = "bmp"),
341 ImageFormat::Tiff => cfg!(feature = "tiff"),
342 ImageFormat::Tga => cfg!(feature = "tga"),
343 ImageFormat::Pnm => cfg!(feature = "pnm"),
344 ImageFormat::Farbfeld => cfg!(feature = "farbfeld"),
345 ImageFormat::Avif => cfg!(feature = "avif"),
346 ImageFormat::WebP => cfg!(feature = "webp"),
347 ImageFormat::OpenExr => cfg!(feature = "openexr"),
348 ImageFormat::Qoi => cfg!(feature = "qoi"),
349 ImageFormat::Dds => false,
350 ImageFormat::Hdr => false,
351 }
352 }
353
354 /// Return all ImageFormats
355 pub fn all() -> impl Iterator<Item = ImageFormat> {
356 [
357 ImageFormat::Gif,
358 ImageFormat::Ico,
359 ImageFormat::Jpeg,
360 ImageFormat::Png,
361 ImageFormat::Bmp,
362 ImageFormat::Tiff,
363 ImageFormat::Tga,
364 ImageFormat::Pnm,
365 ImageFormat::Farbfeld,
366 ImageFormat::Avif,
367 ImageFormat::WebP,
368 ImageFormat::OpenExr,
369 ImageFormat::Qoi,
370 ImageFormat::Dds,
371 ImageFormat::Hdr,
372 ]
373 .iter()
374 .copied()
375 }
376}
377
378/// An enumeration of supported image formats for encoding.
379#[derive(Clone, PartialEq, Eq, Debug)]
380#[non_exhaustive]
381pub enum ImageOutputFormat {
382 #[cfg(feature = "png")]
383 /// An Image in PNG Format
384 Png,
385
386 #[cfg(feature = "jpeg")]
387 /// An Image in JPEG Format with specified quality, up to 100
388 Jpeg(u8),
389
390 #[cfg(feature = "pnm")]
391 /// An Image in one of the PNM Formats
392 Pnm(PnmSubtype),
393
394 #[cfg(feature = "gif")]
395 /// An Image in GIF Format
396 Gif,
397
398 #[cfg(feature = "ico")]
399 /// An Image in ICO Format
400 Ico,
401
402 #[cfg(feature = "bmp")]
403 /// An Image in BMP Format
404 Bmp,
405
406 #[cfg(feature = "farbfeld")]
407 /// An Image in farbfeld Format
408 Farbfeld,
409
410 #[cfg(feature = "tga")]
411 /// An Image in TGA Format
412 Tga,
413
414 #[cfg(feature = "exr")]
415 /// An Image in OpenEXR Format
416 OpenExr,
417
418 #[cfg(feature = "tiff")]
419 /// An Image in TIFF Format
420 Tiff,
421
422 #[cfg(feature = "avif-encoder")]
423 /// An image in AVIF Format
424 Avif,
425
426 #[cfg(feature = "qoi")]
427 /// An image in QOI Format
428 Qoi,
429
430 #[cfg(feature = "webp")]
431 /// An image in WebP Format.
432 WebP,
433
434 /// A value for signalling an error: An unsupported format was requested
435 // Note: When TryFrom is stabilized, this value should not be needed, and
436 // a TryInto<ImageOutputFormat> should be used instead of an Into<ImageOutputFormat>.
437 Unsupported(String),
438}
439
440impl From<ImageFormat> for ImageOutputFormat {
441 fn from(fmt: ImageFormat) -> Self {
442 match fmt {
443 #[cfg(feature = "png")]
444 ImageFormat::Png => ImageOutputFormat::Png,
445 #[cfg(feature = "jpeg")]
446 ImageFormat::Jpeg => ImageOutputFormat::Jpeg(75),
447 #[cfg(feature = "pnm")]
448 ImageFormat::Pnm => ImageOutputFormat::Pnm(PnmSubtype::ArbitraryMap),
449 #[cfg(feature = "gif")]
450 ImageFormat::Gif => ImageOutputFormat::Gif,
451 #[cfg(feature = "ico")]
452 ImageFormat::Ico => ImageOutputFormat::Ico,
453 #[cfg(feature = "bmp")]
454 ImageFormat::Bmp => ImageOutputFormat::Bmp,
455 #[cfg(feature = "farbfeld")]
456 ImageFormat::Farbfeld => ImageOutputFormat::Farbfeld,
457 #[cfg(feature = "tga")]
458 ImageFormat::Tga => ImageOutputFormat::Tga,
459 #[cfg(feature = "exr")]
460 ImageFormat::OpenExr => ImageOutputFormat::OpenExr,
461 #[cfg(feature = "tiff")]
462 ImageFormat::Tiff => ImageOutputFormat::Tiff,
463
464 #[cfg(feature = "avif-encoder")]
465 ImageFormat::Avif => ImageOutputFormat::Avif,
466 #[cfg(feature = "webp")]
467 ImageFormat::WebP => ImageOutputFormat::WebP,
468
469 #[cfg(feature = "qoi")]
470 ImageFormat::Qoi => ImageOutputFormat::Qoi,
471
472 f => ImageOutputFormat::Unsupported(format!("{:?}", f)),
473 }
474 }
475}
476
477// This struct manages buffering associated with implementing `Read` and `Seek` on decoders that can
478// must decode ranges of bytes at a time.
479#[allow(dead_code)]
480// When no image formats that use it are enabled
481pub(crate) struct ImageReadBuffer {
482 scanline_bytes: usize,
483 buffer: Vec<u8>,
484 consumed: usize,
485
486 total_bytes: u64,
487 offset: u64,
488}
489impl ImageReadBuffer {
490 /// Create a new ImageReadBuffer.
491 ///
492 /// Panics if scanline_bytes doesn't fit into a usize, because that would mean reading anything
493 /// from the image would take more RAM than the entire virtual address space. In other words,
494 /// actually using this struct would instantly OOM so just get it out of the way now.
495 #[allow(dead_code)]
496 // When no image formats that use it are enabled
497 pub(crate) fn new(scanline_bytes: u64, total_bytes: u64) -> Self {
498 Self {
499 scanline_bytes: usize::try_from(scanline_bytes).unwrap(),
500 buffer: Vec::new(),
501 consumed: 0,
502 total_bytes,
503 offset: 0,
504 }
505 }
506
507 #[allow(dead_code)]
508 // When no image formats that use it are enabled
509 pub(crate) fn read<F>(&mut self, buf: &mut [u8], mut read_scanline: F) -> io::Result<usize>
510 where
511 F: FnMut(&mut [u8]) -> io::Result<usize>,
512 {
513 if self.buffer.len() == self.consumed {
514 if self.offset == self.total_bytes {
515 return Ok(0);
516 } else if buf.len() >= self.scanline_bytes {
517 // If there is nothing buffered and the user requested a full scanline worth of
518 // data, skip buffering.
519 let bytes_read = read_scanline(&mut buf[..self.scanline_bytes])?;
520 self.offset += u64::try_from(bytes_read).unwrap();
521 return Ok(bytes_read);
522 } else {
523 // Lazily allocate buffer the first time that read is called with a buffer smaller
524 // than the scanline size.
525 if self.buffer.is_empty() {
526 self.buffer.resize(self.scanline_bytes, 0);
527 }
528
529 self.consumed = 0;
530 let bytes_read = read_scanline(&mut self.buffer[..])?;
531 self.buffer.resize(bytes_read, 0);
532 self.offset += u64::try_from(bytes_read).unwrap();
533
534 assert!(bytes_read == self.scanline_bytes || self.offset == self.total_bytes);
535 }
536 }
537
538 // Finally, copy bytes into output buffer.
539 let bytes_buffered = self.buffer.len() - self.consumed;
540 if bytes_buffered > buf.len() {
541 buf.copy_from_slice(&self.buffer[self.consumed..][..buf.len()]);
542 self.consumed += buf.len();
543 Ok(buf.len())
544 } else {
545 buf[..bytes_buffered].copy_from_slice(&self.buffer[self.consumed..][..bytes_buffered]);
546 self.consumed = self.buffer.len();
547 Ok(bytes_buffered)
548 }
549 }
550}
551
552/// Decodes a specific region of the image, represented by the rectangle
553/// starting from ```x``` and ```y``` and having ```length``` and ```width```
554#[allow(dead_code)]
555// When no image formats that use it are enabled
556pub(crate) fn load_rect<'a, D, F, F1, F2, E>(
557 x: u32,
558 y: u32,
559 width: u32,
560 height: u32,
561 buf: &mut [u8],
562 progress_callback: F,
563 decoder: &mut D,
564 mut seek_scanline: F1,
565 mut read_scanline: F2,
566) -> ImageResult<()>
567where
568 D: ImageDecoder<'a>,
569 F: Fn(Progress),
570 F1: FnMut(&mut D, u64) -> io::Result<()>,
571 F2: FnMut(&mut D, &mut [u8]) -> Result<(), E>,
572 ImageError: From<E>,
573{
574 let (x, y, width, height) = (
575 u64::from(x),
576 u64::from(y),
577 u64::from(width),
578 u64::from(height),
579 );
580 let dimensions = decoder.dimensions();
581 let bytes_per_pixel = u64::from(decoder.color_type().bytes_per_pixel());
582 let row_bytes = bytes_per_pixel * u64::from(dimensions.0);
583 #[allow(deprecated)]
584 let scanline_bytes = decoder.scanline_bytes();
585 let total_bytes = width * height * bytes_per_pixel;
586
587 if buf.len() < usize::try_from(total_bytes).unwrap_or(usize::max_value()) {
588 panic!(
589 "output buffer too short\n expected `{}`, provided `{}`",
590 total_bytes,
591 buf.len()
592 );
593 }
594
595 let mut bytes_read = 0u64;
596 let mut current_scanline = 0;
597 let mut tmp = Vec::new();
598 let mut tmp_scanline = None;
599
600 {
601 // Read a range of the image starting from byte number `start` and continuing until byte
602 // number `end`. Updates `current_scanline` and `bytes_read` appropriately.
603 let mut read_image_range = |mut start: u64, end: u64| -> ImageResult<()> {
604 // If the first scanline we need is already stored in the temporary buffer, then handle
605 // it first.
606 let target_scanline = start / scanline_bytes;
607 if tmp_scanline == Some(target_scanline) {
608 let position = target_scanline * scanline_bytes;
609 let offset = start.saturating_sub(position);
610 let len = (end - start)
611 .min(scanline_bytes - offset)
612 .min(end - position);
613
614 buf[(bytes_read as usize)..][..len as usize]
615 .copy_from_slice(&tmp[offset as usize..][..len as usize]);
616 bytes_read += len;
617 start += len;
618
619 progress_callback(Progress {
620 current: bytes_read,
621 total: total_bytes,
622 });
623
624 if start == end {
625 return Ok(());
626 }
627 }
628
629 let target_scanline = start / scanline_bytes;
630 if target_scanline != current_scanline {
631 seek_scanline(decoder, target_scanline)?;
632 current_scanline = target_scanline;
633 }
634
635 let mut position = current_scanline * scanline_bytes;
636 while position < end {
637 if position >= start && end - position >= scanline_bytes {
638 read_scanline(
639 decoder,
640 &mut buf[(bytes_read as usize)..][..(scanline_bytes as usize)],
641 )?;
642 bytes_read += scanline_bytes;
643 } else {
644 tmp.resize(scanline_bytes as usize, 0u8);
645 read_scanline(decoder, &mut tmp)?;
646 tmp_scanline = Some(current_scanline);
647
648 let offset = start.saturating_sub(position);
649 let len = (end - start)
650 .min(scanline_bytes - offset)
651 .min(end - position);
652
653 buf[(bytes_read as usize)..][..len as usize]
654 .copy_from_slice(&tmp[offset as usize..][..len as usize]);
655 bytes_read += len;
656 }
657
658 current_scanline += 1;
659 position += scanline_bytes;
660 progress_callback(Progress {
661 current: bytes_read,
662 total: total_bytes,
663 });
664 }
665 Ok(())
666 };
667
668 if x + width > u64::from(dimensions.0)
669 || y + height > u64::from(dimensions.1)
670 || width == 0
671 || height == 0
672 {
673 return Err(ImageError::Parameter(ParameterError::from_kind(
674 ParameterErrorKind::DimensionMismatch,
675 )));
676 }
677 if scanline_bytes > usize::max_value() as u64 {
678 return Err(ImageError::Limits(LimitError::from_kind(
679 LimitErrorKind::InsufficientMemory,
680 )));
681 }
682
683 progress_callback(Progress {
684 current: 0,
685 total: total_bytes,
686 });
687 if x == 0 && width == u64::from(dimensions.0) {
688 let start = x * bytes_per_pixel + y * row_bytes;
689 let end = (x + width) * bytes_per_pixel + (y + height - 1) * row_bytes;
690 read_image_range(start, end)?;
691 } else {
692 for row in y..(y + height) {
693 let start = x * bytes_per_pixel + row * row_bytes;
694 let end = (x + width) * bytes_per_pixel + row * row_bytes;
695 read_image_range(start, end)?;
696 }
697 }
698 }
699
700 // Seek back to the start
701 Ok(seek_scanline(decoder, 0)?)
702}
703
704/// Reads all of the bytes of a decoder into a Vec<T>. No particular alignment
705/// of the output buffer is guaranteed.
706///
707/// Panics if there isn't enough memory to decode the image.
708pub(crate) fn decoder_to_vec<'a, T>(decoder: impl ImageDecoder<'a>) -> ImageResult<Vec<T>>
709where
710 T: crate::traits::Primitive + bytemuck::Pod,
711{
712 let total_bytes: Result = usize::try_from(decoder.total_bytes());
713 if total_bytes.is_err() || total_bytes.unwrap() > isize::max_value() as usize {
714 return Err(ImageError::Limits(LimitError::from_kind(
715 LimitErrorKind::InsufficientMemory,
716 )));
717 }
718
719 let mut buf: Vec = vec![num_traits::Zero::zero(); total_bytes.unwrap() / std::mem::size_of::<T>()];
720 decoder.read_image(buf:bytemuck::cast_slice_mut(buf.as_mut_slice()))?;
721 Ok(buf)
722}
723
724/// Represents the progress of an image operation.
725///
726/// Note that this is not necessarily accurate and no change to the values passed to the progress
727/// function during decoding will be considered breaking. A decoder could in theory report the
728/// progress `(0, 0)` if progress is unknown, without violating the interface contract of the type.
729#[derive(Clone, Copy, Debug, PartialEq, Eq)]
730pub struct Progress {
731 current: u64,
732 total: u64,
733}
734
735impl Progress {
736 /// Create Progress. Result in invalid progress if you provide a greater `current` than `total`.
737 pub(crate) fn new(current: u64, total: u64) -> Self {
738 Self { current, total }
739 }
740
741 /// A measure of completed decoding.
742 pub fn current(self) -> u64 {
743 self.current
744 }
745
746 /// A measure of all necessary decoding work.
747 ///
748 /// This is in general greater or equal than `current`.
749 pub fn total(self) -> u64 {
750 self.total
751 }
752
753 /// Calculate a measure for remaining decoding work.
754 pub fn remaining(self) -> u64 {
755 self.total.max(self.current) - self.current
756 }
757}
758
759/// The trait that all decoders implement
760pub trait ImageDecoder<'a>: Sized {
761 /// The type of reader produced by `into_reader`.
762 type Reader: Read + 'a;
763
764 /// Returns a tuple containing the width and height of the image
765 fn dimensions(&self) -> (u32, u32);
766
767 /// Returns the color type of the image data produced by this decoder
768 fn color_type(&self) -> ColorType;
769
770 /// Returns the color type of the image file before decoding
771 fn original_color_type(&self) -> ExtendedColorType {
772 self.color_type().into()
773 }
774
775 /// Returns the ICC color profile embedded in the image
776 ///
777 /// For formats that don't support embedded profiles this function will always return `None`.
778 /// This feature is currently only supported for the JPEG, PNG, and AVIF formats.
779 fn icc_profile(&mut self) -> Option<Vec<u8>> {
780 None
781 }
782
783 /// Returns a reader that can be used to obtain the bytes of the image. For the best
784 /// performance, always try to read at least `scanline_bytes` from the reader at a time. Reading
785 /// fewer bytes will cause the reader to perform internal buffering.
786 #[deprecated = "Planned for removal. See https://github.com/image-rs/image/issues/1989"]
787 fn into_reader(self) -> ImageResult<Self::Reader>;
788
789 /// Returns the total number of bytes in the decoded image.
790 ///
791 /// This is the size of the buffer that must be passed to `read_image` or
792 /// `read_image_with_progress`. The returned value may exceed usize::MAX, in
793 /// which case it isn't actually possible to construct a buffer to decode all the image data
794 /// into. If, however, the size does not fit in a u64 then u64::MAX is returned.
795 fn total_bytes(&self) -> u64 {
796 let dimensions = self.dimensions();
797 let total_pixels = u64::from(dimensions.0) * u64::from(dimensions.1);
798 let bytes_per_pixel = u64::from(self.color_type().bytes_per_pixel());
799 total_pixels.saturating_mul(bytes_per_pixel)
800 }
801
802 /// Returns the minimum number of bytes that can be efficiently read from this decoder. This may
803 /// be as few as 1 or as many as `total_bytes()`.
804 #[deprecated = "Planned for removal. See https://github.com/image-rs/image/issues/1989"]
805 fn scanline_bytes(&self) -> u64 {
806 self.total_bytes()
807 }
808
809 /// Returns all the bytes in the image.
810 ///
811 /// This function takes a slice of bytes and writes the pixel data of the image into it.
812 /// Although not required, for certain color types callers may want to pass buffers which are
813 /// aligned to 2 or 4 byte boundaries to the slice can be cast to a [u16] or [u32]. To accommodate
814 /// such casts, the returned contents will always be in native endian.
815 ///
816 /// # Panics
817 ///
818 /// This function panics if buf.len() != self.total_bytes().
819 ///
820 /// # Examples
821 ///
822 /// ```no_build
823 /// use zerocopy::{AsBytes, FromBytes};
824 /// fn read_16bit_image(decoder: impl ImageDecoder) -> Vec<16> {
825 /// let mut buf: Vec<u16> = vec![0; decoder.total_bytes()/2];
826 /// decoder.read_image(buf.as_bytes());
827 /// buf
828 /// }
829 /// ```
830 fn read_image(self, buf: &mut [u8]) -> ImageResult<()> {
831 #[allow(deprecated)]
832 self.read_image_with_progress(buf, |_| {})
833 }
834
835 /// Same as `read_image` but periodically calls the provided callback to give updates on loading
836 /// progress.
837 #[deprecated = "Use read_image instead. See https://github.com/image-rs/image/issues/1989"]
838 fn read_image_with_progress<F: Fn(Progress)>(
839 self,
840 buf: &mut [u8],
841 progress_callback: F,
842 ) -> ImageResult<()> {
843 assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));
844
845 let total_bytes = self.total_bytes() as usize;
846 #[allow(deprecated)]
847 let scanline_bytes = self.scanline_bytes() as usize;
848 let target_read_size = if scanline_bytes < 4096 {
849 (4096 / scanline_bytes) * scanline_bytes
850 } else {
851 scanline_bytes
852 };
853
854 #[allow(deprecated)]
855 let mut reader = self.into_reader()?;
856
857 let mut bytes_read = 0;
858 while bytes_read < total_bytes {
859 let read_size = target_read_size.min(total_bytes - bytes_read);
860 reader.read_exact(&mut buf[bytes_read..][..read_size])?;
861 bytes_read += read_size;
862
863 progress_callback(Progress {
864 current: bytes_read as u64,
865 total: total_bytes as u64,
866 });
867 }
868
869 Ok(())
870 }
871
872 /// Set decoding limits for this decoder. See [`Limits`] for the different kinds of
873 /// limits that is possible to set.
874 ///
875 /// Note to implementors: make sure you call [`Limits::check_support`] so that
876 /// decoding fails if any unsupported strict limits are set. Also make sure
877 /// you call [`Limits::check_dimensions`] to check the `max_image_width` and
878 /// `max_image_height` limits.
879 ///
880 /// [`Limits`]: ./io/struct.Limits.html
881 /// [`Limits::check_support`]: ./io/struct.Limits.html#method.check_support
882 /// [`Limits::check_dimensions`]: ./io/struct.Limits.html#method.check_dimensions
883 fn set_limits(&mut self, limits: crate::io::Limits) -> ImageResult<()> {
884 limits.check_support(&crate::io::LimitSupport::default())?;
885
886 let (width, height) = self.dimensions();
887 limits.check_dimensions(width, height)?;
888
889 Ok(())
890 }
891}
892
893/// Specialized image decoding not be supported by all formats
894pub trait ImageDecoderRect<'a>: ImageDecoder<'a> + Sized {
895 /// Decode a rectangular section of the image; see [`read_rect_with_progress()`](#fn.read_rect_with_progress).
896 fn read_rect(
897 &mut self,
898 x: u32,
899 y: u32,
900 width: u32,
901 height: u32,
902 buf: &mut [u8],
903 ) -> ImageResult<()> {
904 #[allow(deprecated)]
905 self.read_rect_with_progress(x, y, width, height, buf, |_| {})
906 }
907
908 /// Decode a rectangular section of the image, periodically reporting progress.
909 ///
910 /// The output buffer will be filled with fields specified by
911 /// [`ImageDecoder::color_type()`](trait.ImageDecoder.html#fn.color_type),
912 /// in that order, each field represented in native-endian.
913 ///
914 /// The progress callback will be called at least once at the start and the end of decoding,
915 /// implementations are encouraged to call this more often,
916 /// with a frequency meaningful for display to the end-user.
917 ///
918 /// This function will panic if the output buffer isn't at least
919 /// `color_type().bytes_per_pixel() * color_type().channel_count() * width * height` bytes long.
920 #[deprecated = "Use read_image instead. See https://github.com/image-rs/image/issues/1989"]
921 fn read_rect_with_progress<F: Fn(Progress)>(
922 &mut self,
923 x: u32,
924 y: u32,
925 width: u32,
926 height: u32,
927 buf: &mut [u8],
928 progress_callback: F,
929 ) -> ImageResult<()>;
930}
931
932/// AnimationDecoder trait
933pub trait AnimationDecoder<'a> {
934 /// Consume the decoder producing a series of frames.
935 fn into_frames(self) -> Frames<'a>;
936}
937
938/// The trait all encoders implement
939pub trait ImageEncoder {
940 /// Writes all the bytes in an image to the encoder.
941 ///
942 /// This function takes a slice of bytes of the pixel data of the image
943 /// and encodes them. Unlike particular format encoders inherent impl encode
944 /// methods where endianness is not specified, here image data bytes should
945 /// always be in native endian. The implementor will reorder the endianness
946 /// as necessary for the target encoding format.
947 ///
948 /// See also `ImageDecoder::read_image` which reads byte buffers into
949 /// native endian.
950 ///
951 /// # Panics
952 ///
953 /// Panics if `width * height * color_type.bytes_per_pixel() != buf.len()`.
954 fn write_image(
955 self,
956 buf: &[u8],
957 width: u32,
958 height: u32,
959 color_type: ColorType,
960 ) -> ImageResult<()>;
961}
962
963/// Immutable pixel iterator
964#[derive(Debug)]
965pub struct Pixels<'a, I: ?Sized + 'a> {
966 image: &'a I,
967 x: u32,
968 y: u32,
969 width: u32,
970 height: u32,
971}
972
973impl<'a, I: GenericImageView> Iterator for Pixels<'a, I> {
974 type Item = (u32, u32, I::Pixel);
975
976 fn next(&mut self) -> Option<(u32, u32, I::Pixel)> {
977 if self.x >= self.width {
978 self.x = 0;
979 self.y += 1;
980 }
981
982 if self.y >= self.height {
983 None
984 } else {
985 let pixel: ::Pixel = self.image.get_pixel(self.x, self.y);
986 let p: (u32, u32, ::Pixel) = (self.x, self.y, pixel);
987
988 self.x += 1;
989
990 Some(p)
991 }
992 }
993}
994
995impl<I: ?Sized> Clone for Pixels<'_, I> {
996 fn clone(&self) -> Self {
997 Pixels { ..*self }
998 }
999}
1000
1001/// Trait to inspect an image.
1002///
1003/// ```
1004/// use image::{GenericImageView, Rgb, RgbImage};
1005///
1006/// let buffer = RgbImage::new(10, 10);
1007/// let image: &dyn GenericImageView<Pixel=Rgb<u8>> = &buffer;
1008/// ```
1009pub trait GenericImageView {
1010 /// The type of pixel.
1011 type Pixel: Pixel;
1012
1013 /// The width and height of this image.
1014 fn dimensions(&self) -> (u32, u32);
1015
1016 /// The width of this image.
1017 fn width(&self) -> u32 {
1018 let (w, _) = self.dimensions();
1019 w
1020 }
1021
1022 /// The height of this image.
1023 fn height(&self) -> u32 {
1024 let (_, h) = self.dimensions();
1025 h
1026 }
1027
1028 /// The bounding rectangle of this image.
1029 #[deprecated = "This method has inconsistent behavior between implementations (#1829). Use `dimensions` instead"]
1030 fn bounds(&self) -> (u32, u32, u32, u32);
1031
1032 /// Returns true if this x, y coordinate is contained inside the image.
1033 fn in_bounds(&self, x: u32, y: u32) -> bool {
1034 #[allow(deprecated)]
1035 let (ix, iy, iw, ih) = self.bounds();
1036 x >= ix && x < ix + iw && y >= iy && y < iy + ih
1037 }
1038
1039 /// Returns the pixel located at (x, y). Indexed from top left.
1040 ///
1041 /// # Panics
1042 ///
1043 /// Panics if `(x, y)` is out of bounds.
1044 fn get_pixel(&self, x: u32, y: u32) -> Self::Pixel;
1045
1046 /// Returns the pixel located at (x, y). Indexed from top left.
1047 ///
1048 /// This function can be implemented in a way that ignores bounds checking.
1049 /// # Safety
1050 ///
1051 /// The coordinates must be [`in_bounds`] of the image.
1052 ///
1053 /// [`in_bounds`]: #method.in_bounds
1054 unsafe fn unsafe_get_pixel(&self, x: u32, y: u32) -> Self::Pixel {
1055 self.get_pixel(x, y)
1056 }
1057
1058 /// Returns an Iterator over the pixels of this image.
1059 /// The iterator yields the coordinates of each pixel
1060 /// along with their value
1061 fn pixels(&self) -> Pixels<Self>
1062 where
1063 Self: Sized,
1064 {
1065 let (width, height) = self.dimensions();
1066
1067 Pixels {
1068 image: self,
1069 x: 0,
1070 y: 0,
1071 width,
1072 height,
1073 }
1074 }
1075
1076 /// Returns a subimage that is an immutable view into this image.
1077 /// You can use [`GenericImage::sub_image`] if you need a mutable view instead.
1078 /// The coordinates set the position of the top left corner of the view.
1079 fn view(&self, x: u32, y: u32, width: u32, height: u32) -> SubImage<&Self>
1080 where
1081 Self: Sized,
1082 {
1083 assert!(x as u64 + width as u64 <= self.width() as u64);
1084 assert!(y as u64 + height as u64 <= self.height() as u64);
1085 SubImage::new(self, x, y, width, height)
1086 }
1087}
1088
1089/// A trait for manipulating images.
1090pub trait GenericImage: GenericImageView {
1091 /// Gets a reference to the mutable pixel at location `(x, y)`. Indexed from top left.
1092 ///
1093 /// # Panics
1094 ///
1095 /// Panics if `(x, y)` is out of bounds.
1096 ///
1097 /// Panics for dynamic images (this method is deprecated and will be removed).
1098 ///
1099 /// ## Known issues
1100 ///
1101 /// This requires the buffer to contain a unique set of continuous channels in the exact order
1102 /// and byte representation that the pixel type requires. This is somewhat restrictive.
1103 ///
1104 /// TODO: Maybe use some kind of entry API? this would allow pixel type conversion on the fly
1105 /// while still doing only one array lookup:
1106 ///
1107 /// ```ignore
1108 /// let px = image.pixel_entry_at(x,y);
1109 /// px.set_from_rgba(rgba)
1110 /// ```
1111 #[deprecated(since = "0.24.0", note = "Use `get_pixel` and `put_pixel` instead.")]
1112 fn get_pixel_mut(&mut self, x: u32, y: u32) -> &mut Self::Pixel;
1113
1114 /// Put a pixel at location (x, y). Indexed from top left.
1115 ///
1116 /// # Panics
1117 ///
1118 /// Panics if `(x, y)` is out of bounds.
1119 fn put_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel);
1120
1121 /// Puts a pixel at location (x, y). Indexed from top left.
1122 ///
1123 /// This function can be implemented in a way that ignores bounds checking.
1124 /// # Safety
1125 ///
1126 /// The coordinates must be [`in_bounds`] of the image.
1127 ///
1128 /// [`in_bounds`]: traits.GenericImageView.html#method.in_bounds
1129 unsafe fn unsafe_put_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel) {
1130 self.put_pixel(x, y, pixel);
1131 }
1132
1133 /// Put a pixel at location (x, y), taking into account alpha channels
1134 #[deprecated(
1135 since = "0.24.0",
1136 note = "Use iterator `pixels_mut` to blend the pixels directly"
1137 )]
1138 fn blend_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel);
1139
1140 /// Copies all of the pixels from another image into this image.
1141 ///
1142 /// The other image is copied with the top-left corner of the
1143 /// other image placed at (x, y).
1144 ///
1145 /// In order to copy only a piece of the other image, use [`GenericImageView::view`].
1146 ///
1147 /// You can use [`FlatSamples`] to source pixels from an arbitrary regular raster of channel
1148 /// values, for example from a foreign interface or a fixed image.
1149 ///
1150 /// # Returns
1151 /// Returns an error if the image is too large to be copied at the given position
1152 ///
1153 /// [`GenericImageView::view`]: trait.GenericImageView.html#method.view
1154 /// [`FlatSamples`]: flat/struct.FlatSamples.html
1155 fn copy_from<O>(&mut self, other: &O, x: u32, y: u32) -> ImageResult<()>
1156 where
1157 O: GenericImageView<Pixel = Self::Pixel>,
1158 {
1159 // Do bounds checking here so we can use the non-bounds-checking
1160 // functions to copy pixels.
1161 if self.width() < other.width() + x || self.height() < other.height() + y {
1162 return Err(ImageError::Parameter(ParameterError::from_kind(
1163 ParameterErrorKind::DimensionMismatch,
1164 )));
1165 }
1166
1167 for k in 0..other.height() {
1168 for i in 0..other.width() {
1169 let p = other.get_pixel(i, k);
1170 self.put_pixel(i + x, k + y, p);
1171 }
1172 }
1173 Ok(())
1174 }
1175
1176 /// Copies all of the pixels from one part of this image to another part of this image.
1177 ///
1178 /// The destination rectangle of the copy is specified with the top-left corner placed at (x, y).
1179 ///
1180 /// # Returns
1181 /// `true` if the copy was successful, `false` if the image could not
1182 /// be copied due to size constraints.
1183 fn copy_within(&mut self, source: Rect, x: u32, y: u32) -> bool {
1184 let Rect {
1185 x: sx,
1186 y: sy,
1187 width,
1188 height,
1189 } = source;
1190 let dx = x;
1191 let dy = y;
1192 assert!(sx < self.width() && dx < self.width());
1193 assert!(sy < self.height() && dy < self.height());
1194 if self.width() - dx.max(sx) < width || self.height() - dy.max(sy) < height {
1195 return false;
1196 }
1197 // since `.rev()` creates a new dype we would either have to go with dynamic dispatch for the ranges
1198 // or have quite a lot of code bloat. A macro gives us static dispatch with less visible bloat.
1199 macro_rules! copy_within_impl_ {
1200 ($xiter:expr, $yiter:expr) => {
1201 for y in $yiter {
1202 let sy = sy + y;
1203 let dy = dy + y;
1204 for x in $xiter {
1205 let sx = sx + x;
1206 let dx = dx + x;
1207 let pixel = self.get_pixel(sx, sy);
1208 self.put_pixel(dx, dy, pixel);
1209 }
1210 }
1211 };
1212 }
1213 // check how target and source rectangles relate to each other so we dont overwrite data before we copied it.
1214 match (sx < dx, sy < dy) {
1215 (true, true) => copy_within_impl_!((0..width).rev(), (0..height).rev()),
1216 (true, false) => copy_within_impl_!((0..width).rev(), 0..height),
1217 (false, true) => copy_within_impl_!(0..width, (0..height).rev()),
1218 (false, false) => copy_within_impl_!(0..width, 0..height),
1219 }
1220 true
1221 }
1222
1223 /// Returns a mutable subimage that is a view into this image.
1224 /// If you want an immutable subimage instead, use [`GenericImageView::view`]
1225 /// The coordinates set the position of the top left corner of the SubImage.
1226 fn sub_image(&mut self, x: u32, y: u32, width: u32, height: u32) -> SubImage<&mut Self>
1227 where
1228 Self: Sized,
1229 {
1230 assert!(x as u64 + width as u64 <= self.width() as u64);
1231 assert!(y as u64 + height as u64 <= self.height() as u64);
1232 SubImage::new(self, x, y, width, height)
1233 }
1234}
1235
1236/// A View into another image
1237///
1238/// Instances of this struct can be created using:
1239/// - [`GenericImage::sub_image`] to create a mutable view,
1240/// - [`GenericImageView::view`] to create an immutable view,
1241/// - [`SubImage::new`] to instantiate the struct directly.
1242///
1243/// Note that this does _not_ implement `GenericImage`, but it dereferences to one which allows you
1244/// to use it as if it did. See [Design Considerations](#Design-Considerations) below for details.
1245///
1246/// # Design Considerations
1247///
1248/// For reasons relating to coherence, this is not itself a `GenericImage` or a `GenericImageView`.
1249/// In short, we want to reserve the ability of adding traits implemented for _all_ generic images
1250/// but in a different manner for `SubImage`. This may be required to ensure that stacking
1251/// sub-images comes at no double indirect cost.
1252///
1253/// If, ultimately, this is not needed then a directly implementation of `GenericImage` can and
1254/// will get added. This inconvenience may alternatively get resolved if Rust allows some forms of
1255/// specialization, which might make this trick unnecessary and thus also allows for a direct
1256/// implementation.
1257#[derive(Copy, Clone)]
1258pub struct SubImage<I> {
1259 inner: SubImageInner<I>,
1260}
1261
1262/// The inner type of `SubImage` that implements `GenericImage{,View}`.
1263///
1264/// This type is _nominally_ `pub` but it is not exported from the crate. It should be regarded as
1265/// an existential type in any case.
1266#[derive(Copy, Clone)]
1267pub struct SubImageInner<I> {
1268 image: I,
1269 xoffset: u32,
1270 yoffset: u32,
1271 xstride: u32,
1272 ystride: u32,
1273}
1274
1275/// Alias to access Pixel behind a reference
1276type DerefPixel<I> = <<I as Deref>::Target as GenericImageView>::Pixel;
1277
1278/// Alias to access Subpixel behind a reference
1279type DerefSubpixel<I> = <DerefPixel<I> as Pixel>::Subpixel;
1280
1281impl<I> SubImage<I> {
1282 /// Construct a new subimage
1283 /// The coordinates set the position of the top left corner of the SubImage.
1284 pub fn new(image: I, x: u32, y: u32, width: u32, height: u32) -> SubImage<I> {
1285 SubImage {
1286 inner: SubImageInner {
1287 image,
1288 xoffset: x,
1289 yoffset: y,
1290 xstride: width,
1291 ystride: height,
1292 },
1293 }
1294 }
1295
1296 /// Change the coordinates of this subimage.
1297 pub fn change_bounds(&mut self, x: u32, y: u32, width: u32, height: u32) {
1298 self.inner.xoffset = x;
1299 self.inner.yoffset = y;
1300 self.inner.xstride = width;
1301 self.inner.ystride = height;
1302 }
1303
1304 /// The offsets of this subimage relative to the underlying image.
1305 pub fn offsets(&self) -> (u32, u32) {
1306 (self.inner.xoffset, self.inner.yoffset)
1307 }
1308
1309 /// Convert this subimage to an ImageBuffer
1310 pub fn to_image(&self) -> ImageBuffer<DerefPixel<I>, Vec<DerefSubpixel<I>>>
1311 where
1312 I: Deref,
1313 I::Target: GenericImageView + 'static,
1314 {
1315 let mut out = ImageBuffer::new(self.inner.xstride, self.inner.ystride);
1316 let borrowed = self.inner.image.deref();
1317
1318 for y in 0..self.inner.ystride {
1319 for x in 0..self.inner.xstride {
1320 let p = borrowed.get_pixel(x + self.inner.xoffset, y + self.inner.yoffset);
1321 out.put_pixel(x, y, p);
1322 }
1323 }
1324
1325 out
1326 }
1327}
1328
1329/// Methods for readable images.
1330impl<I> SubImage<I>
1331where
1332 I: Deref,
1333 I::Target: GenericImageView,
1334{
1335 /// Create a sub-view of the image.
1336 ///
1337 /// The coordinates given are relative to the current view on the underlying image.
1338 ///
1339 /// Note that this method is preferred to the one from `GenericImageView`. This is accessible
1340 /// with the explicit method call syntax but it should rarely be needed due to causing an
1341 /// extra level of indirection.
1342 ///
1343 /// ```
1344 /// use image::{GenericImageView, RgbImage, SubImage};
1345 /// let buffer = RgbImage::new(10, 10);
1346 ///
1347 /// let subimage: SubImage<&RgbImage> = buffer.view(0, 0, 10, 10);
1348 /// let subview: SubImage<&RgbImage> = subimage.view(0, 0, 10, 10);
1349 ///
1350 /// // Less efficient and NOT &RgbImage
1351 /// let _: SubImage<&_> = GenericImageView::view(&*subimage, 0, 0, 10, 10);
1352 /// ```
1353 pub fn view(&self, x: u32, y: u32, width: u32, height: u32) -> SubImage<&I::Target> {
1354 use crate::GenericImageView as _;
1355 assert!(x as u64 + width as u64 <= self.inner.width() as u64);
1356 assert!(y as u64 + height as u64 <= self.inner.height() as u64);
1357 let x = self.inner.xoffset.saturating_add(x);
1358 let y = self.inner.yoffset.saturating_add(y);
1359 SubImage::new(&*self.inner.image, x, y, width, height)
1360 }
1361
1362 /// Get a reference to the underlying image.
1363 pub fn inner(&self) -> &I::Target {
1364 &self.inner.image
1365 }
1366}
1367
1368impl<I> SubImage<I>
1369where
1370 I: DerefMut,
1371 I::Target: GenericImage,
1372{
1373 /// Create a mutable sub-view of the image.
1374 ///
1375 /// The coordinates given are relative to the current view on the underlying image.
1376 pub fn sub_image(
1377 &mut self,
1378 x: u32,
1379 y: u32,
1380 width: u32,
1381 height: u32,
1382 ) -> SubImage<&mut I::Target> {
1383 assert!(x as u64 + width as u64 <= self.inner.width() as u64);
1384 assert!(y as u64 + height as u64 <= self.inner.height() as u64);
1385 let x: u32 = self.inner.xoffset.saturating_add(x);
1386 let y: u32 = self.inner.yoffset.saturating_add(y);
1387 SubImage::new(&mut *self.inner.image, x, y, width, height)
1388 }
1389
1390 /// Get a mutable reference to the underlying image.
1391 pub fn inner_mut(&mut self) -> &mut I::Target {
1392 &mut self.inner.image
1393 }
1394}
1395
1396impl<I> Deref for SubImage<I>
1397where
1398 I: Deref,
1399{
1400 type Target = SubImageInner<I>;
1401 fn deref(&self) -> &Self::Target {
1402 &self.inner
1403 }
1404}
1405
1406impl<I> DerefMut for SubImage<I>
1407where
1408 I: DerefMut,
1409{
1410 fn deref_mut(&mut self) -> &mut Self::Target {
1411 &mut self.inner
1412 }
1413}
1414
1415#[allow(deprecated)]
1416impl<I> GenericImageView for SubImageInner<I>
1417where
1418 I: Deref,
1419 I::Target: GenericImageView,
1420{
1421 type Pixel = DerefPixel<I>;
1422
1423 fn dimensions(&self) -> (u32, u32) {
1424 (self.xstride, self.ystride)
1425 }
1426
1427 fn bounds(&self) -> (u32, u32, u32, u32) {
1428 (self.xoffset, self.yoffset, self.xstride, self.ystride)
1429 }
1430
1431 fn get_pixel(&self, x: u32, y: u32) -> Self::Pixel {
1432 self.image.get_pixel(x:x + self.xoffset, y:y + self.yoffset)
1433 }
1434}
1435
1436#[allow(deprecated)]
1437impl<I> GenericImage for SubImageInner<I>
1438where
1439 I: DerefMut,
1440 I::Target: GenericImage + Sized,
1441{
1442 fn get_pixel_mut(&mut self, x: u32, y: u32) -> &mut Self::Pixel {
1443 self.image.get_pixel_mut(x:x + self.xoffset, y:y + self.yoffset)
1444 }
1445
1446 fn put_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel) {
1447 self.image
1448 .put_pixel(x:x + self.xoffset, y:y + self.yoffset, pixel)
1449 }
1450
1451 /// DEPRECATED: This method will be removed. Blend the pixel directly instead.
1452 fn blend_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel) {
1453 self.image
1454 .blend_pixel(x:x + self.xoffset, y:y + self.yoffset, pixel)
1455 }
1456}
1457
1458#[cfg(test)]
1459mod tests {
1460 use std::collections::HashSet;
1461 use std::io;
1462 use std::path::Path;
1463
1464 use super::{
1465 load_rect, ColorType, GenericImage, GenericImageView, ImageDecoder, ImageFormat,
1466 ImageResult,
1467 };
1468 use crate::color::Rgba;
1469 use crate::math::Rect;
1470 use crate::{GrayImage, ImageBuffer};
1471
1472 #[test]
1473 #[allow(deprecated)]
1474 /// Test that alpha blending works as expected
1475 fn test_image_alpha_blending() {
1476 let mut target = ImageBuffer::new(1, 1);
1477 target.put_pixel(0, 0, Rgba([255u8, 0, 0, 255]));
1478 assert!(*target.get_pixel(0, 0) == Rgba([255, 0, 0, 255]));
1479 target.blend_pixel(0, 0, Rgba([0, 255, 0, 255]));
1480 assert!(*target.get_pixel(0, 0) == Rgba([0, 255, 0, 255]));
1481
1482 // Blending an alpha channel onto a solid background
1483 target.blend_pixel(0, 0, Rgba([255, 0, 0, 127]));
1484 assert!(*target.get_pixel(0, 0) == Rgba([127, 127, 0, 255]));
1485
1486 // Blending two alpha channels
1487 target.put_pixel(0, 0, Rgba([0, 255, 0, 127]));
1488 target.blend_pixel(0, 0, Rgba([255, 0, 0, 127]));
1489 assert!(*target.get_pixel(0, 0) == Rgba([169, 85, 0, 190]));
1490 }
1491
1492 #[test]
1493 fn test_in_bounds() {
1494 let mut target = ImageBuffer::new(2, 2);
1495 target.put_pixel(0, 0, Rgba([255u8, 0, 0, 255]));
1496
1497 assert!(target.in_bounds(0, 0));
1498 assert!(target.in_bounds(1, 0));
1499 assert!(target.in_bounds(0, 1));
1500 assert!(target.in_bounds(1, 1));
1501
1502 assert!(!target.in_bounds(2, 0));
1503 assert!(!target.in_bounds(0, 2));
1504 assert!(!target.in_bounds(2, 2));
1505 }
1506
1507 #[test]
1508 fn test_can_subimage_clone_nonmut() {
1509 let mut source = ImageBuffer::new(3, 3);
1510 source.put_pixel(1, 1, Rgba([255u8, 0, 0, 255]));
1511
1512 // A non-mutable copy of the source image
1513 let source = source.clone();
1514
1515 // Clone a view into non-mutable to a separate buffer
1516 let cloned = source.view(1, 1, 1, 1).to_image();
1517
1518 assert!(cloned.get_pixel(0, 0) == source.get_pixel(1, 1));
1519 }
1520
1521 #[test]
1522 fn test_can_nest_views() {
1523 let mut source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
1524
1525 {
1526 let mut sub1 = source.sub_image(0, 0, 2, 2);
1527 let mut sub2 = sub1.sub_image(1, 1, 1, 1);
1528 sub2.put_pixel(0, 0, Rgba([0, 0, 0, 0]));
1529 }
1530
1531 assert_eq!(*source.get_pixel(1, 1), Rgba([0, 0, 0, 0]));
1532
1533 let view1 = source.view(0, 0, 2, 2);
1534 assert_eq!(*source.get_pixel(1, 1), view1.get_pixel(1, 1));
1535
1536 let view2 = view1.view(1, 1, 1, 1);
1537 assert_eq!(*source.get_pixel(1, 1), view2.get_pixel(0, 0));
1538 }
1539
1540 #[test]
1541 #[should_panic]
1542 fn test_view_out_of_bounds() {
1543 let source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
1544 source.view(1, 1, 3, 3);
1545 }
1546
1547 #[test]
1548 #[should_panic]
1549 fn test_view_coordinates_out_of_bounds() {
1550 let source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
1551 source.view(3, 3, 3, 3);
1552 }
1553
1554 #[test]
1555 #[should_panic]
1556 fn test_view_width_out_of_bounds() {
1557 let source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
1558 source.view(1, 1, 3, 2);
1559 }
1560
1561 #[test]
1562 #[should_panic]
1563 fn test_view_height_out_of_bounds() {
1564 let source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
1565 source.view(1, 1, 2, 3);
1566 }
1567
1568 #[test]
1569 #[should_panic]
1570 fn test_view_x_out_of_bounds() {
1571 let source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
1572 source.view(3, 1, 3, 3);
1573 }
1574
1575 #[test]
1576 #[should_panic]
1577 fn test_view_y_out_of_bounds() {
1578 let source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
1579 source.view(1, 3, 3, 3);
1580 }
1581
1582 #[test]
1583 fn test_view_in_bounds() {
1584 let source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
1585 source.view(0, 0, 3, 3);
1586 source.view(1, 1, 2, 2);
1587 source.view(2, 2, 0, 0);
1588 }
1589
1590 #[test]
1591 fn test_copy_sub_image() {
1592 let source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
1593 let view = source.view(0, 0, 3, 3);
1594 let _view2 = view;
1595 view.to_image();
1596 }
1597
1598 #[test]
1599 fn test_load_rect() {
1600 struct MockDecoder {
1601 scanline_number: u64,
1602 scanline_bytes: u64,
1603 }
1604 impl<'a> ImageDecoder<'a> for MockDecoder {
1605 type Reader = Box<dyn io::Read>;
1606 fn dimensions(&self) -> (u32, u32) {
1607 (5, 5)
1608 }
1609 fn color_type(&self) -> ColorType {
1610 ColorType::L8
1611 }
1612 fn into_reader(self) -> ImageResult<Self::Reader> {
1613 unimplemented!()
1614 }
1615 fn scanline_bytes(&self) -> u64 {
1616 self.scanline_bytes
1617 }
1618 }
1619
1620 const DATA: [u8; 25] = [
1621 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
1622 24,
1623 ];
1624
1625 fn seek_scanline(m: &mut MockDecoder, n: u64) -> io::Result<()> {
1626 m.scanline_number = n;
1627 Ok(())
1628 }
1629 fn read_scanline(m: &mut MockDecoder, buf: &mut [u8]) -> io::Result<()> {
1630 let bytes_read = m.scanline_number * m.scanline_bytes;
1631 if bytes_read >= 25 {
1632 return Ok(());
1633 }
1634
1635 let len = m.scanline_bytes.min(25 - bytes_read);
1636 buf[..(len as usize)].copy_from_slice(&DATA[(bytes_read as usize)..][..(len as usize)]);
1637 m.scanline_number += 1;
1638 Ok(())
1639 }
1640
1641 for scanline_bytes in 1..30 {
1642 let mut output = [0u8; 26];
1643
1644 load_rect(
1645 0,
1646 0,
1647 5,
1648 5,
1649 &mut output,
1650 |_| {},
1651 &mut MockDecoder {
1652 scanline_number: 0,
1653 scanline_bytes,
1654 },
1655 seek_scanline,
1656 read_scanline,
1657 )
1658 .unwrap();
1659 assert_eq!(output[0..25], DATA);
1660 assert_eq!(output[25], 0);
1661
1662 output = [0u8; 26];
1663 load_rect(
1664 3,
1665 2,
1666 1,
1667 1,
1668 &mut output,
1669 |_| {},
1670 &mut MockDecoder {
1671 scanline_number: 0,
1672 scanline_bytes,
1673 },
1674 seek_scanline,
1675 read_scanline,
1676 )
1677 .unwrap();
1678 assert_eq!(output[0..2], [13, 0]);
1679
1680 output = [0u8; 26];
1681 load_rect(
1682 3,
1683 2,
1684 2,
1685 2,
1686 &mut output,
1687 |_| {},
1688 &mut MockDecoder {
1689 scanline_number: 0,
1690 scanline_bytes,
1691 },
1692 seek_scanline,
1693 read_scanline,
1694 )
1695 .unwrap();
1696 assert_eq!(output[0..5], [13, 14, 18, 19, 0]);
1697
1698 output = [0u8; 26];
1699 load_rect(
1700 1,
1701 1,
1702 2,
1703 4,
1704 &mut output,
1705 |_| {},
1706 &mut MockDecoder {
1707 scanline_number: 0,
1708 scanline_bytes,
1709 },
1710 seek_scanline,
1711 read_scanline,
1712 )
1713 .unwrap();
1714 assert_eq!(output[0..9], [6, 7, 11, 12, 16, 17, 21, 22, 0]);
1715 }
1716 }
1717
1718 #[test]
1719 fn test_load_rect_single_scanline() {
1720 const DATA: [u8; 25] = [
1721 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
1722 24,
1723 ];
1724
1725 struct MockDecoder;
1726 impl<'a> ImageDecoder<'a> for MockDecoder {
1727 type Reader = Box<dyn io::Read>;
1728 fn dimensions(&self) -> (u32, u32) {
1729 (5, 5)
1730 }
1731 fn color_type(&self) -> ColorType {
1732 ColorType::L8
1733 }
1734 fn into_reader(self) -> ImageResult<Self::Reader> {
1735 unimplemented!()
1736 }
1737 fn scanline_bytes(&self) -> u64 {
1738 25
1739 }
1740 }
1741
1742 // Ensure that seek scanline is called only once.
1743 let mut seeks = 0;
1744 let seek_scanline = |_d: &mut MockDecoder, n: u64| -> io::Result<()> {
1745 seeks += 1;
1746 assert_eq!(n, 0);
1747 assert_eq!(seeks, 1);
1748 Ok(())
1749 };
1750
1751 fn read_scanline(_m: &mut MockDecoder, buf: &mut [u8]) -> io::Result<()> {
1752 buf.copy_from_slice(&DATA);
1753 Ok(())
1754 }
1755
1756 let mut output = [0; 26];
1757 load_rect(
1758 1,
1759 1,
1760 2,
1761 4,
1762 &mut output,
1763 |_| {},
1764 &mut MockDecoder,
1765 seek_scanline,
1766 read_scanline,
1767 )
1768 .unwrap();
1769 assert_eq!(output[0..9], [6, 7, 11, 12, 16, 17, 21, 22, 0]);
1770 }
1771
1772 #[test]
1773 fn test_image_format_from_path() {
1774 fn from_path(s: &str) -> ImageResult<ImageFormat> {
1775 ImageFormat::from_path(Path::new(s))
1776 }
1777 assert_eq!(from_path("./a.jpg").unwrap(), ImageFormat::Jpeg);
1778 assert_eq!(from_path("./a.jpeg").unwrap(), ImageFormat::Jpeg);
1779 assert_eq!(from_path("./a.JPEG").unwrap(), ImageFormat::Jpeg);
1780 assert_eq!(from_path("./a.pNg").unwrap(), ImageFormat::Png);
1781 assert_eq!(from_path("./a.gif").unwrap(), ImageFormat::Gif);
1782 assert_eq!(from_path("./a.webp").unwrap(), ImageFormat::WebP);
1783 assert_eq!(from_path("./a.tiFF").unwrap(), ImageFormat::Tiff);
1784 assert_eq!(from_path("./a.tif").unwrap(), ImageFormat::Tiff);
1785 assert_eq!(from_path("./a.tga").unwrap(), ImageFormat::Tga);
1786 assert_eq!(from_path("./a.dds").unwrap(), ImageFormat::Dds);
1787 assert_eq!(from_path("./a.bmp").unwrap(), ImageFormat::Bmp);
1788 assert_eq!(from_path("./a.Ico").unwrap(), ImageFormat::Ico);
1789 assert_eq!(from_path("./a.hdr").unwrap(), ImageFormat::Hdr);
1790 assert_eq!(from_path("./a.exr").unwrap(), ImageFormat::OpenExr);
1791 assert_eq!(from_path("./a.pbm").unwrap(), ImageFormat::Pnm);
1792 assert_eq!(from_path("./a.pAM").unwrap(), ImageFormat::Pnm);
1793 assert_eq!(from_path("./a.Ppm").unwrap(), ImageFormat::Pnm);
1794 assert_eq!(from_path("./a.pgm").unwrap(), ImageFormat::Pnm);
1795 assert_eq!(from_path("./a.AViF").unwrap(), ImageFormat::Avif);
1796 assert!(from_path("./a.txt").is_err());
1797 assert!(from_path("./a").is_err());
1798 }
1799
1800 #[test]
1801 fn test_generic_image_copy_within_oob() {
1802 let mut image: GrayImage = ImageBuffer::from_raw(4, 4, vec![0u8; 16]).unwrap();
1803 assert!(!image.sub_image(0, 0, 4, 4).copy_within(
1804 Rect {
1805 x: 0,
1806 y: 0,
1807 width: 5,
1808 height: 4
1809 },
1810 0,
1811 0
1812 ));
1813 assert!(!image.sub_image(0, 0, 4, 4).copy_within(
1814 Rect {
1815 x: 0,
1816 y: 0,
1817 width: 4,
1818 height: 5
1819 },
1820 0,
1821 0
1822 ));
1823 assert!(!image.sub_image(0, 0, 4, 4).copy_within(
1824 Rect {
1825 x: 1,
1826 y: 0,
1827 width: 4,
1828 height: 4
1829 },
1830 0,
1831 0
1832 ));
1833 assert!(!image.sub_image(0, 0, 4, 4).copy_within(
1834 Rect {
1835 x: 0,
1836 y: 0,
1837 width: 4,
1838 height: 4
1839 },
1840 1,
1841 0
1842 ));
1843 assert!(!image.sub_image(0, 0, 4, 4).copy_within(
1844 Rect {
1845 x: 0,
1846 y: 1,
1847 width: 4,
1848 height: 4
1849 },
1850 0,
1851 0
1852 ));
1853 assert!(!image.sub_image(0, 0, 4, 4).copy_within(
1854 Rect {
1855 x: 0,
1856 y: 0,
1857 width: 4,
1858 height: 4
1859 },
1860 0,
1861 1
1862 ));
1863 assert!(!image.sub_image(0, 0, 4, 4).copy_within(
1864 Rect {
1865 x: 1,
1866 y: 1,
1867 width: 4,
1868 height: 4
1869 },
1870 0,
1871 0
1872 ));
1873 }
1874
1875 #[test]
1876 fn test_generic_image_copy_within_tl() {
1877 let data = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
1878 let expected = [0, 1, 2, 3, 4, 0, 1, 2, 8, 4, 5, 6, 12, 8, 9, 10];
1879 let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap();
1880 assert!(image.sub_image(0, 0, 4, 4).copy_within(
1881 Rect {
1882 x: 0,
1883 y: 0,
1884 width: 3,
1885 height: 3
1886 },
1887 1,
1888 1
1889 ));
1890 assert_eq!(&image.into_raw(), &expected);
1891 }
1892
1893 #[test]
1894 fn test_generic_image_copy_within_tr() {
1895 let data = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
1896 let expected = [0, 1, 2, 3, 1, 2, 3, 7, 5, 6, 7, 11, 9, 10, 11, 15];
1897 let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap();
1898 assert!(image.sub_image(0, 0, 4, 4).copy_within(
1899 Rect {
1900 x: 1,
1901 y: 0,
1902 width: 3,
1903 height: 3
1904 },
1905 0,
1906 1
1907 ));
1908 assert_eq!(&image.into_raw(), &expected);
1909 }
1910
1911 #[test]
1912 fn test_generic_image_copy_within_bl() {
1913 let data = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
1914 let expected = [0, 4, 5, 6, 4, 8, 9, 10, 8, 12, 13, 14, 12, 13, 14, 15];
1915 let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap();
1916 assert!(image.sub_image(0, 0, 4, 4).copy_within(
1917 Rect {
1918 x: 0,
1919 y: 1,
1920 width: 3,
1921 height: 3
1922 },
1923 1,
1924 0
1925 ));
1926 assert_eq!(&image.into_raw(), &expected);
1927 }
1928
1929 #[test]
1930 fn test_generic_image_copy_within_br() {
1931 let data = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
1932 let expected = [5, 6, 7, 3, 9, 10, 11, 7, 13, 14, 15, 11, 12, 13, 14, 15];
1933 let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap();
1934 assert!(image.sub_image(0, 0, 4, 4).copy_within(
1935 Rect {
1936 x: 1,
1937 y: 1,
1938 width: 3,
1939 height: 3
1940 },
1941 0,
1942 0
1943 ));
1944 assert_eq!(&image.into_raw(), &expected);
1945 }
1946
1947 #[test]
1948 fn image_formats_are_recognized() {
1949 use ImageFormat::*;
1950 const ALL_FORMATS: &[ImageFormat] = &[
1951 Avif, Png, Jpeg, Gif, WebP, Pnm, Tiff, Tga, Dds, Bmp, Ico, Hdr, Farbfeld, OpenExr,
1952 ];
1953 for &format in ALL_FORMATS {
1954 let mut file = Path::new("file.nothing").to_owned();
1955 for ext in format.extensions_str() {
1956 assert!(file.set_extension(ext));
1957 match ImageFormat::from_path(&file) {
1958 Err(_) => panic!("Path {} not recognized as {:?}", file.display(), format),
1959 Ok(result) => assert_eq!(format, result),
1960 }
1961 }
1962 }
1963 }
1964
1965 #[test]
1966 fn total_bytes_overflow() {
1967 struct D;
1968 impl<'a> ImageDecoder<'a> for D {
1969 type Reader = std::io::Cursor<Vec<u8>>;
1970 fn color_type(&self) -> ColorType {
1971 ColorType::Rgb8
1972 }
1973 fn dimensions(&self) -> (u32, u32) {
1974 (0xffffffff, 0xffffffff)
1975 }
1976 fn into_reader(self) -> ImageResult<Self::Reader> {
1977 unreachable!()
1978 }
1979 }
1980 assert_eq!(D.total_bytes(), u64::max_value());
1981
1982 let v: ImageResult<Vec<u8>> = super::decoder_to_vec(D);
1983 assert!(v.is_err());
1984 }
1985
1986 #[test]
1987 fn all() {
1988 let all_formats: HashSet<ImageFormat> = HashSet::from_iter(ImageFormat::all());
1989 assert!(all_formats.contains(&ImageFormat::Avif));
1990 assert!(all_formats.contains(&ImageFormat::Gif));
1991 assert!(all_formats.contains(&ImageFormat::Bmp));
1992 assert!(all_formats.contains(&ImageFormat::Farbfeld));
1993 assert!(all_formats.contains(&ImageFormat::Jpeg));
1994 }
1995
1996 #[test]
1997 fn reading_enabled() {
1998 assert_eq!(cfg!(feature = "jpeg"), ImageFormat::Jpeg.reading_enabled());
1999 assert!(!ImageFormat::Dds.reading_enabled());
2000 }
2001
2002 #[test]
2003 fn writing_enabled() {
2004 assert_eq!(cfg!(feature = "jpeg"), ImageFormat::Jpeg.writing_enabled());
2005 assert!(!ImageFormat::Hdr.writing_enabled());
2006 assert!(!ImageFormat::Dds.writing_enabled());
2007 }
2008}
2009