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

Provided by KDAB

Privacy Policy