1 #![allow(clippy::too_many_arguments)]
2 use std::convert::TryFrom;
3 use std::ffi::OsStr;
4 use std::io;
5 use std::io::Read;
6 use std::ops::{Deref, DerefMut};
7 use std::path::Path;
8 use std::usize;
9
10 use crate::ImageBuffer;
11 use crate::color::{ColorType, ExtendedColorType};
12 use crate::error::{ImageError, ImageFormatHint, ImageResult, LimitError, LimitErrorKind, ParameterError, ParameterErrorKind};
13 use crate::math::Rect;
14 use crate::traits::Pixel;
15
16 use crate::animation::Frames;
17
18 #[cfg(feature = "pnm")]
19 use crate::pnm::PNMSubtype;
20
21 /// An enumeration of supported image formats.
22 /// Not all formats support both encoding and decoding.
23 #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
24 pub enum ImageFormat {
25 /// An Image in PNG Format
26 Png,
27
28 /// An Image in JPEG Format
29 Jpeg,
30
31 /// An Image in GIF Format
32 Gif,
33
34 /// An Image in WEBP Format
35 WebP,
36
37 /// An Image in general PNM Format
38 Pnm,
39
40 /// An Image in TIFF Format
41 Tiff,
42
43 /// An Image in TGA Format
44 Tga,
45
46 /// An Image in DDS Format
47 Dds,
48
49 /// An Image in BMP Format
50 Bmp,
51
52 /// An Image in ICO Format
53 Ico,
54
55 /// An Image in Radiance HDR Format
56 Hdr,
57
58 /// An Image in farbfeld Format
59 Farbfeld,
60
61 /// An Image in AVIF format.
62 Avif,
63
64 #[doc(hidden)]
65 __NonExhaustive(crate::utils::NonExhaustiveMarker),
66 }
67
68 impl ImageFormat {
69 /// Return the image format specified by a path's file extension.
70 ///
71 /// # Example
72 ///
73 /// ```
74 /// use image::ImageFormat;
75 ///
76 /// let format = ImageFormat::from_extension("jpg");
77 /// assert_eq!(format, Some(ImageFormat::Jpeg));
78 /// ```
79 #[inline]
from_extension<S>(ext: S) -> Option<Self> where S: AsRef<OsStr>80 pub fn from_extension<S>(ext: S) -> Option<Self> where S: AsRef<OsStr> {
81 // thin wrapper function to strip generics
82 fn inner(ext: &OsStr) -> Option<ImageFormat> {
83 let ext = ext.to_str()?.to_ascii_lowercase();
84
85 Some(match ext.as_str() {
86 "avif" => ImageFormat::Avif,
87 "jpg" | "jpeg" => ImageFormat::Jpeg,
88 "png" => ImageFormat::Png,
89 "gif" => ImageFormat::Gif,
90 "webp" => ImageFormat::WebP,
91 "tif" | "tiff" => ImageFormat::Tiff,
92 "tga" => ImageFormat::Tga,
93 "dds" => ImageFormat::Dds,
94 "bmp" => ImageFormat::Bmp,
95 "ico" => ImageFormat::Ico,
96 "hdr" => ImageFormat::Hdr,
97 "pbm" | "pam" | "ppm" | "pgm" => ImageFormat::Pnm,
98 "ff" | "farbfeld" => ImageFormat::Farbfeld,
99 _ => return None,
100 })
101 }
102
103 inner(ext.as_ref())
104 }
105
106 /// Return the image format specified by the path's file extension.
107 ///
108 /// # Example
109 ///
110 /// ```
111 /// use image::ImageFormat;
112 ///
113 /// let format = ImageFormat::from_path("images/ferris.png")?;
114 /// assert_eq!(format, ImageFormat::Png);
115 ///
116 /// # Ok::<(), image::error::ImageError>(())
117 /// ```
118 #[inline]
from_path<P>(path: P) -> ImageResult<Self> where P : AsRef<Path>119 pub fn from_path<P>(path: P) -> ImageResult<Self> where P : AsRef<Path> {
120 // thin wrapper function to strip generics
121 fn inner(path: &Path) -> ImageResult<ImageFormat> {
122 let exact_ext = path.extension();
123 exact_ext
124 .and_then(ImageFormat::from_extension)
125 .ok_or_else(|| {
126 let format_hint = match exact_ext {
127 None => ImageFormatHint::Unknown,
128 Some(os) => ImageFormatHint::PathExtension(os.into()),
129 };
130 ImageError::Unsupported(format_hint.into())
131 })
132 }
133
134 inner(path.as_ref())
135 }
136
137 /// Return if the ImageFormat can be decoded by the lib.
138 #[inline]
can_read(&self) -> bool139 pub fn can_read(&self) -> bool {
140 // Needs to be updated once a new variant's decoder is added to free_functions.rs::load
141 match self {
142 ImageFormat::Png => true,
143 ImageFormat::Gif => true,
144 ImageFormat::Jpeg => true,
145 ImageFormat::WebP => true,
146 ImageFormat::Tiff => true,
147 ImageFormat::Tga => true,
148 ImageFormat::Dds => false,
149 ImageFormat::Bmp => true,
150 ImageFormat::Ico => true,
151 ImageFormat::Hdr => true,
152 ImageFormat::Pnm => true,
153 ImageFormat::Farbfeld => true,
154 ImageFormat::Avif => true,
155 ImageFormat::__NonExhaustive(marker) => match marker._private {},
156 }
157 }
158
159 /// Return if the ImageFormat can be encoded by the lib.
160 #[inline]
can_write(&self) -> bool161 pub fn can_write(&self) -> bool {
162 // Needs to be updated once a new variant's encoder is added to free_functions.rs::save_buffer_with_format_impl
163 match self {
164 ImageFormat::Gif => true,
165 ImageFormat::Ico => true,
166 ImageFormat::Jpeg => true,
167 ImageFormat::Png => true,
168 ImageFormat::Bmp => true,
169 ImageFormat::Tiff => true,
170 ImageFormat::Tga => true,
171 ImageFormat::Pnm => true,
172 ImageFormat::Farbfeld => true,
173 ImageFormat::Avif => true,
174 ImageFormat::WebP => false,
175 ImageFormat::Hdr => false,
176 ImageFormat::Dds => false,
177 ImageFormat::__NonExhaustive(marker) => match marker._private {},
178 }
179 }
180
181 /// Return a list of applicable extensions for this format.
182 ///
183 /// All currently recognized image formats specify at least on extension but for future
184 /// compatibility you should not rely on this fact. The list may be empty if the format has no
185 /// recognized file representation, for example in case it is used as a purely transient memory
186 /// format.
187 ///
188 /// The method name `extensions` remains reserved for introducing another method in the future
189 /// that yields a slice of `OsStr` which is blocked by several features of const evaluation.
extensions_str(self) -> &'static [&'static str]190 pub fn extensions_str(self) -> &'static [&'static str] {
191 match self {
192 ImageFormat::Png => &["png"],
193 ImageFormat::Jpeg => &["jpg", "jpeg"],
194 ImageFormat::Gif => &["gif"],
195 ImageFormat::WebP => &["webp"],
196 ImageFormat::Pnm => &["pbm", "pam", "ppm", "pgm"],
197 ImageFormat::Tiff => &["tiff", "tif"],
198 ImageFormat::Tga => &["tga"],
199 ImageFormat::Dds => &["dds"],
200 ImageFormat::Bmp => &["bmp"],
201 ImageFormat::Ico => &["ico"],
202 ImageFormat::Hdr => &["hdr"],
203 ImageFormat::Farbfeld => &["ff"],
204 // According to: https://aomediacodec.github.io/av1-avif/#mime-registration
205 ImageFormat::Avif => &["avif"],
206 ImageFormat::__NonExhaustive(marker) => match marker._private {},
207 }
208 }
209 }
210
211 /// An enumeration of supported image formats for encoding.
212 #[derive(Clone, PartialEq, Eq, Debug)]
213 pub enum ImageOutputFormat {
214 #[cfg(feature = "png")]
215 /// An Image in PNG Format
216 Png,
217
218 #[cfg(feature = "jpeg")]
219 /// An Image in JPEG Format with specified quality
220 Jpeg(u8),
221
222 #[cfg(feature = "pnm")]
223 /// An Image in one of the PNM Formats
224 Pnm(PNMSubtype),
225
226 #[cfg(feature = "gif")]
227 /// An Image in GIF Format
228 Gif,
229
230 #[cfg(feature = "ico")]
231 /// An Image in ICO Format
232 Ico,
233
234 #[cfg(feature = "bmp")]
235 /// An Image in BMP Format
236 Bmp,
237
238 #[cfg(feature = "farbfeld")]
239 /// An Image in farbfeld Format
240 Farbfeld,
241
242 #[cfg(feature = "tga")]
243 /// An Image in TGA Format
244 Tga,
245
246 #[cfg(feature = "avif")]
247 /// An image in AVIF Format
248 Avif,
249
250 /// A value for signalling an error: An unsupported format was requested
251 // Note: When TryFrom is stabilized, this value should not be needed, and
252 // a TryInto<ImageOutputFormat> should be used instead of an Into<ImageOutputFormat>.
253 Unsupported(String),
254
255 #[doc(hidden)]
256 __NonExhaustive(crate::utils::NonExhaustiveMarker),
257 }
258
259 impl From<ImageFormat> for ImageOutputFormat {
from(fmt: ImageFormat) -> Self260 fn from(fmt: ImageFormat) -> Self {
261 match fmt {
262 #[cfg(feature = "png")]
263 ImageFormat::Png => ImageOutputFormat::Png,
264 #[cfg(feature = "jpeg")]
265 ImageFormat::Jpeg => ImageOutputFormat::Jpeg(75),
266 #[cfg(feature = "pnm")]
267 ImageFormat::Pnm => ImageOutputFormat::Pnm(PNMSubtype::ArbitraryMap),
268 #[cfg(feature = "gif")]
269 ImageFormat::Gif => ImageOutputFormat::Gif,
270 #[cfg(feature = "ico")]
271 ImageFormat::Ico => ImageOutputFormat::Ico,
272 #[cfg(feature = "bmp")]
273 ImageFormat::Bmp => ImageOutputFormat::Bmp,
274 #[cfg(feature = "farbfeld")]
275 ImageFormat::Farbfeld => ImageOutputFormat::Farbfeld,
276 #[cfg(feature = "tga")]
277 ImageFormat::Tga => ImageOutputFormat::Tga,
278 #[cfg(feature = "avif")]
279 ImageFormat::Avif => ImageOutputFormat::Avif,
280
281 f => ImageOutputFormat::Unsupported(format!("{:?}", f)),
282 }
283 }
284 }
285
286 // This struct manages buffering associated with implementing `Read` and `Seek` on decoders that can
287 // must decode ranges of bytes at a time.
288 #[allow(dead_code)]
289 // When no image formats that use it are enabled
290 pub(crate) struct ImageReadBuffer {
291 scanline_bytes: usize,
292 buffer: Vec<u8>,
293 consumed: usize,
294
295 total_bytes: u64,
296 offset: u64,
297 }
298 impl ImageReadBuffer {
299 /// Create a new ImageReadBuffer.
300 ///
301 /// Panics if scanline_bytes doesn't fit into a usize, because that would mean reading anything
302 /// from the image would take more RAM than the entire virtual address space. In other words,
303 /// actually using this struct would instantly OOM so just get it out of the way now.
304 #[allow(dead_code)]
305 // When no image formats that use it are enabled
new(scanline_bytes: u64, total_bytes: u64) -> Self306 pub(crate) fn new(scanline_bytes: u64, total_bytes: u64) -> Self {
307 Self {
308 scanline_bytes: usize::try_from(scanline_bytes).unwrap(),
309 buffer: Vec::new(),
310 consumed: 0,
311 total_bytes,
312 offset: 0,
313 }
314 }
315
316 #[allow(dead_code)]
317 // When no image formats that use it are enabled
read<F>(&mut self, buf: &mut [u8], mut read_scanline: F) -> io::Result<usize> where F: FnMut(&mut [u8]) -> io::Result<usize>,318 pub(crate) fn read<F>(&mut self, buf: &mut [u8], mut read_scanline: F) -> io::Result<usize>
319 where
320 F: FnMut(&mut [u8]) -> io::Result<usize>,
321 {
322 if self.buffer.len() == self.consumed {
323 if self.offset == self.total_bytes {
324 return Ok(0);
325 } else if buf.len() >= self.scanline_bytes {
326 // If there is nothing buffered and the user requested a full scanline worth of
327 // data, skip buffering.
328 let bytes_read = read_scanline(&mut buf[..self.scanline_bytes])?;
329 self.offset += u64::try_from(bytes_read).unwrap();
330 return Ok(bytes_read);
331 } else {
332 // Lazily allocate buffer the first time that read is called with a buffer smaller
333 // than the scanline size.
334 if self.buffer.is_empty() {
335 self.buffer.resize(self.scanline_bytes, 0);
336 }
337
338 self.consumed = 0;
339 let bytes_read = read_scanline(&mut self.buffer[..])?;
340 self.buffer.resize(bytes_read, 0);
341 self.offset += u64::try_from(bytes_read).unwrap();
342
343 assert!(bytes_read == self.scanline_bytes || self.offset == self.total_bytes);
344 }
345 }
346
347 // Finally, copy bytes into output buffer.
348 let bytes_buffered = self.buffer.len() - self.consumed;
349 if bytes_buffered > buf.len() {
350 crate::copy_memory(&self.buffer[self.consumed..][..buf.len()], &mut buf[..]);
351 self.consumed += buf.len();
352 Ok(buf.len())
353 } else {
354 crate::copy_memory(&self.buffer[self.consumed..], &mut buf[..bytes_buffered]);
355 self.consumed = self.buffer.len();
356 Ok(bytes_buffered)
357 }
358 }
359 }
360
361 /// Decodes a specific region of the image, represented by the rectangle
362 /// starting from ```x``` and ```y``` and having ```length``` and ```width```
363 #[allow(dead_code)]
364 // When no image formats that use it are enabled
load_rect<'a, D, F, F1, F2, E>(x: u32, y: u32, width: u32, height: u32, buf: &mut [u8], progress_callback: F, decoder: &mut D, mut seek_scanline: F1, mut read_scanline: F2) -> ImageResult<()> where D: ImageDecoder<'a>, F: Fn(Progress), F1: FnMut(&mut D, u64) -> io::Result<()>, F2: FnMut(&mut D, &mut [u8]) -> Result<(), E>, ImageError: From<E>,365 pub(crate) fn load_rect<'a, D, F, F1, F2, E>(x: u32, y: u32, width: u32, height: u32, buf: &mut [u8],
366 progress_callback: F,
367 decoder: &mut D,
368 mut seek_scanline: F1,
369 mut read_scanline: F2) -> ImageResult<()>
370 where D: ImageDecoder<'a>,
371 F: Fn(Progress),
372 F1: FnMut(&mut D, u64) -> io::Result<()>,
373 F2: FnMut(&mut D, &mut [u8]) -> Result<(), E>,
374 ImageError: From<E>,
375 {
376 let (x, y, width, height) = (u64::from(x), u64::from(y), u64::from(width), u64::from(height));
377 let dimensions = decoder.dimensions();
378 let bytes_per_pixel = u64::from(decoder.color_type().bytes_per_pixel());
379 let row_bytes = bytes_per_pixel * u64::from(dimensions.0);
380 let scanline_bytes = decoder.scanline_bytes();
381 let total_bytes = width * height * bytes_per_pixel;
382
383 if buf.len() < usize::try_from(total_bytes).unwrap_or(usize::MAX) {
384 panic!("output buffer too short\n expected `{}`, provided `{}`", total_bytes, buf.len());
385 }
386
387 let mut bytes_read = 0u64;
388 let mut current_scanline = 0;
389 let mut tmp = Vec::new();
390 let mut tmp_scanline = None;
391
392 {
393 // Read a range of the image starting from byte number `start` and continuing until byte
394 // number `end`. Updates `current_scanline` and `bytes_read` appropiately.
395 let mut read_image_range = |mut start: u64, end: u64| -> ImageResult<()> {
396 // If the first scanline we need is already stored in the temporary buffer, then handle
397 // it first.
398 let target_scanline = start / scanline_bytes;
399 if tmp_scanline == Some(target_scanline) {
400 let position = target_scanline * scanline_bytes;
401 let offset = start.saturating_sub(position);
402 let len = (end - start)
403 .min(scanline_bytes - offset)
404 .min(end - position);
405
406 buf[(bytes_read as usize)..][..len as usize]
407 .copy_from_slice(&tmp[offset as usize..][..len as usize]);
408 bytes_read += len;
409 start += len;
410
411 progress_callback(Progress {current: bytes_read, total: total_bytes});
412
413 if start == end {
414 return Ok(());
415 }
416 }
417
418 let target_scanline = start / scanline_bytes;
419 if target_scanline != current_scanline {
420 seek_scanline(decoder, target_scanline)?;
421 current_scanline = target_scanline;
422 }
423
424 let mut position = current_scanline * scanline_bytes;
425 while position < end {
426 if position >= start && end - position >= scanline_bytes {
427 read_scanline(decoder, &mut buf[(bytes_read as usize)..]
428 [..(scanline_bytes as usize)])?;
429 bytes_read += scanline_bytes;
430 } else {
431 tmp.resize(scanline_bytes as usize, 0u8);
432 read_scanline(decoder, &mut tmp)?;
433 tmp_scanline = Some(current_scanline);
434
435 let offset = start.saturating_sub(position);
436 let len = (end - start)
437 .min(scanline_bytes - offset)
438 .min(end - position);
439
440 buf[(bytes_read as usize)..][..len as usize]
441 .copy_from_slice(&tmp[offset as usize..][..len as usize]);
442 bytes_read += len;
443 }
444
445 current_scanline += 1;
446 position += scanline_bytes;
447 progress_callback(Progress {current: bytes_read, total: total_bytes});
448 }
449 Ok(())
450 };
451
452 if x + width > u64::from(dimensions.0) || y + height > u64::from(dimensions.1)
453 || width == 0 || height == 0 {
454 return Err(ImageError::Parameter(ParameterError::from_kind(
455 ParameterErrorKind::DimensionMismatch,
456 )));
457 }
458 if scanline_bytes > usize::max_value() as u64 {
459 return Err(ImageError::Limits(LimitError::from_kind(
460 LimitErrorKind::InsufficientMemory,
461 )));
462 }
463
464 progress_callback(Progress {current: 0, total: total_bytes});
465 if x == 0 && width == u64::from(dimensions.0) {
466 let start = x * bytes_per_pixel + y * row_bytes;
467 let end = (x + width) * bytes_per_pixel + (y + height - 1) * row_bytes;
468 read_image_range(start, end)?;
469 } else {
470 for row in y..(y+height) {
471 let start = x * bytes_per_pixel + row * row_bytes;
472 let end = (x + width) * bytes_per_pixel + row * row_bytes;
473 read_image_range(start, end)?;
474 }
475 }
476 }
477
478 // Seek back to the start
479 Ok(seek_scanline(decoder, 0)?)
480 }
481
482 /// Reads all of the bytes of a decoder into a Vec<T>. No particular alignment
483 /// of the output buffer is guaranteed.
484 ///
485 /// Panics if there isn't enough memory to decode the image.
decoder_to_vec<'a, T>(decoder: impl ImageDecoder<'a>) -> ImageResult<Vec<T>> where T: crate::traits::Primitive + bytemuck::Pod,486 pub(crate) fn decoder_to_vec<'a, T>(decoder: impl ImageDecoder<'a>) -> ImageResult<Vec<T>>
487 where
488 T: crate::traits::Primitive + bytemuck::Pod,
489 {
490 let mut buf = vec![num_traits::Zero::zero(); usize::try_from(decoder.total_bytes()).unwrap() / std::mem::size_of::<T>()];
491 decoder.read_image(bytemuck::cast_slice_mut(buf.as_mut_slice()))?;
492 Ok(buf)
493 }
494
495 /// Represents the progress of an image operation.
496 ///
497 /// Note that this is not necessarily accurate and no change to the values passed to the progress
498 /// function during decoding will be considered breaking. A decoder could in theory report the
499 /// progress `(0, 0)` if progress is unknown, without violating the interface contract of the type.
500 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
501 pub struct Progress {
502 current: u64,
503 total: u64,
504 }
505
506 impl Progress {
507 /// A measure of completed decoding.
current(self) -> u64508 pub fn current(self) -> u64 {
509 self.current
510 }
511
512 /// A measure of all necessary decoding work.
513 ///
514 /// This is in general greater or equal than `current`.
total(self) -> u64515 pub fn total(self) -> u64 {
516 self.total
517 }
518
519 /// Calculate a measure for remaining decoding work.
remaining(self) -> u64520 pub fn remaining(self) -> u64 {
521 self.total.max(self.current) - self.current
522 }
523 }
524
525 /// The trait that all decoders implement
526 pub trait ImageDecoder<'a>: Sized {
527 /// The type of reader produced by `into_reader`.
528 type Reader: Read + 'a;
529
530 /// Returns a tuple containing the width and height of the image
dimensions(&self) -> (u32, u32)531 fn dimensions(&self) -> (u32, u32);
532
533 /// Returns the color type of the image data produced by this decoder
color_type(&self) -> ColorType534 fn color_type(&self) -> ColorType;
535
536 /// Retuns the color type of the image file before decoding
original_color_type(&self) -> ExtendedColorType537 fn original_color_type(&self) -> ExtendedColorType {
538 self.color_type().into()
539 }
540
541 /// Returns a reader that can be used to obtain the bytes of the image. For the best
542 /// performance, always try to read at least `scanline_bytes` from the reader at a time. Reading
543 /// fewer bytes will cause the reader to perform internal buffering.
into_reader(self) -> ImageResult<Self::Reader>544 fn into_reader(self) -> ImageResult<Self::Reader>;
545
546 /// Returns the total number of bytes in the decoded image.
547 ///
548 /// This is the size of the buffer that must be passed to `read_image` or
549 /// `read_image_with_progress`. The returned value may exceed usize::MAX, in
550 /// which case it isn't actually possible to construct a buffer to decode all the image data
551 /// into.
total_bytes(&self) -> u64552 fn total_bytes(&self) -> u64 {
553 let dimensions = self.dimensions();
554 u64::from(dimensions.0) * u64::from(dimensions.1) * u64::from(self.color_type().bytes_per_pixel())
555 }
556
557 /// Returns the minimum number of bytes that can be efficiently read from this decoder. This may
558 /// be as few as 1 or as many as `total_bytes()`.
scanline_bytes(&self) -> u64559 fn scanline_bytes(&self) -> u64 {
560 self.total_bytes()
561 }
562
563 /// Returns all the bytes in the image.
564 ///
565 /// This function takes a slice of bytes and writes the pixel data of the image into it.
566 /// Although not required, for certain color types callers may want to pass buffers which are
567 /// aligned to 2 or 4 byte boundaries to the slice can be cast to a [u16] or [u32]. To accommodate
568 /// such casts, the returned contents will always be in native endian.
569 ///
570 /// # Panics
571 ///
572 /// This function panics if buf.len() != self.total_bytes().
573 ///
574 /// # Examples
575 ///
576 /// ```no_build
577 /// use zerocopy::{AsBytes, FromBytes};
578 /// fn read_16bit_image(decoder: impl ImageDecoder) -> Vec<16> {
579 /// let mut buf: Vec<u16> = vec![0; decoder.total_bytes()/2];
580 /// decoder.read_image(buf.as_bytes());
581 /// buf
582 /// }
read_image(self, buf: &mut [u8]) -> ImageResult<()>583 fn read_image(self, buf: &mut [u8]) -> ImageResult<()> {
584 self.read_image_with_progress(buf, |_| {})
585 }
586
587 /// Same as `read_image` but periodically calls the provided callback to give updates on loading
588 /// progress.
read_image_with_progress<F: Fn(Progress)>( self, buf: &mut [u8], progress_callback: F, ) -> ImageResult<()>589 fn read_image_with_progress<F: Fn(Progress)>(
590 self,
591 buf: &mut [u8],
592 progress_callback: F,
593 ) -> ImageResult<()> {
594 assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));
595
596 let total_bytes = self.total_bytes() as usize;
597 let scanline_bytes = self.scanline_bytes() as usize;
598 let target_read_size = if scanline_bytes < 4096 {
599 (4096 / scanline_bytes) * scanline_bytes
600 } else {
601 scanline_bytes
602 };
603
604 let mut reader = self.into_reader()?;
605
606 let mut bytes_read = 0;
607 while bytes_read < total_bytes {
608 let read_size = target_read_size.min(total_bytes - bytes_read);
609 reader.read_exact(&mut buf[bytes_read..][..read_size])?;
610 bytes_read += read_size;
611
612 progress_callback(Progress {
613 current: bytes_read as u64,
614 total: total_bytes as u64,
615 });
616 }
617
618 Ok(())
619 }
620 }
621
622 /// Specialized image decoding not be supported by all formats
623 pub trait ImageDecoderExt<'a>: ImageDecoder<'a> + Sized {
624 /// Decode a rectangular section of the image; see [`read_rect_with_progress()`](#fn.read_rect_with_progress).
read_rect( &mut self, x: u32, y: u32, width: u32, height: u32, buf: &mut [u8], ) -> ImageResult<()>625 fn read_rect(
626 &mut self,
627 x: u32,
628 y: u32,
629 width: u32,
630 height: u32,
631 buf: &mut [u8],
632 ) -> ImageResult<()> {
633 self.read_rect_with_progress(x, y, width, height, buf, |_|{})
634 }
635
636 /// Decode a rectangular section of the image, periodically reporting progress.
637 ///
638 /// The output buffer will be filled with fields specified by
639 /// [`ImageDecoder::color_type()`](trait.ImageDecoder.html#fn.color_type),
640 /// in that order, each field represented in native-endian.
641 ///
642 /// The progress callback will be called at least once at the start and the end of decoding,
643 /// implementations are encouraged to call this more often,
644 /// with a frequency meaningful for display to the end-user.
645 ///
646 /// This function will panic if the output buffer isn't at least
647 /// `color_type().bytes_per_pixel() * color_type().channel_count() * width * height` bytes long.
read_rect_with_progress<F: Fn(Progress)>( &mut self, x: u32, y: u32, width: u32, height: u32, buf: &mut [u8], progress_callback: F, ) -> ImageResult<()>648 fn read_rect_with_progress<F: Fn(Progress)>(
649 &mut self,
650 x: u32,
651 y: u32,
652 width: u32,
653 height: u32,
654 buf: &mut [u8],
655 progress_callback: F,
656 ) -> ImageResult<()>;
657 }
658
659 /// AnimationDecoder trait
660 pub trait AnimationDecoder<'a> {
661 /// Consume the decoder producing a series of frames.
into_frames(self) -> Frames<'a>662 fn into_frames(self) -> Frames<'a>;
663 }
664
665 /// The trait all encoders implement
666 pub trait ImageEncoder {
667 /// Writes all the bytes in an image to the encoder.
668 ///
669 /// This function takes a slice of bytes of the pixel data of the image
670 /// and encodes them. Unlike particular format encoders inherent impl encode
671 /// methods where endianness is not specified, here image data bytes should
672 /// always be in native endian. The implementor will reorder the endianess
673 /// as necessary for the target encoding format.
674 ///
675 /// See also `ImageDecoder::read_image` which reads byte buffers into
676 /// native endian.
write_image( self, buf: &[u8], width: u32, height: u32, color_type: ColorType, ) -> ImageResult<()>677 fn write_image(
678 self,
679 buf: &[u8],
680 width: u32,
681 height: u32,
682 color_type: ColorType,
683 ) -> ImageResult<()>;
684 }
685
686 /// Immutable pixel iterator
687 #[derive(Debug)]
688 pub struct Pixels<'a, I: ?Sized + 'a> {
689 image: &'a I,
690 x: u32,
691 y: u32,
692 width: u32,
693 height: u32,
694 }
695
696 impl<'a, I: GenericImageView> Iterator for Pixels<'a, I> {
697 type Item = (u32, u32, I::Pixel);
698
next(&mut self) -> Option<(u32, u32, I::Pixel)>699 fn next(&mut self) -> Option<(u32, u32, I::Pixel)> {
700 if self.x >= self.width {
701 self.x = 0;
702 self.y += 1;
703 }
704
705 if self.y >= self.height {
706 None
707 } else {
708 let pixel = self.image.get_pixel(self.x, self.y);
709 let p = (self.x, self.y, pixel);
710
711 self.x += 1;
712
713 Some(p)
714 }
715 }
716 }
717
718 impl<I: ?Sized> Clone for Pixels<'_, I> {
clone(&self) -> Self719 fn clone(&self) -> Self {
720 Pixels { ..*self }
721 }
722 }
723
724 /// Trait to inspect an image.
725 pub trait GenericImageView {
726 /// The type of pixel.
727 type Pixel: Pixel;
728
729 /// Underlying image type. This is mainly used by SubImages in order to
730 /// always have a reference to the original image. This allows for less
731 /// indirections and it eases the use of nested SubImages.
732 type InnerImageView: GenericImageView<Pixel = Self::Pixel>;
733
734 /// The width and height of this image.
dimensions(&self) -> (u32, u32)735 fn dimensions(&self) -> (u32, u32);
736
737 /// The width of this image.
width(&self) -> u32738 fn width(&self) -> u32 {
739 let (w, _) = self.dimensions();
740 w
741 }
742
743 /// The height of this image.
height(&self) -> u32744 fn height(&self) -> u32 {
745 let (_, h) = self.dimensions();
746 h
747 }
748
749 /// The bounding rectangle of this image.
bounds(&self) -> (u32, u32, u32, u32)750 fn bounds(&self) -> (u32, u32, u32, u32);
751
752 /// Returns true if this x, y coordinate is contained inside the image.
in_bounds(&self, x: u32, y: u32) -> bool753 fn in_bounds(&self, x: u32, y: u32) -> bool {
754 let (ix, iy, iw, ih) = self.bounds();
755 x >= ix && x < ix + iw && y >= iy && y < iy + ih
756 }
757
758 /// Returns the pixel located at (x, y). Indexed from top left.
759 ///
760 /// # Panics
761 ///
762 /// Panics if `(x, y)` is out of bounds.
763 ///
764 /// TODO: change this signature to &P
get_pixel(&self, x: u32, y: u32) -> Self::Pixel765 fn get_pixel(&self, x: u32, y: u32) -> Self::Pixel;
766
767 /// Returns the pixel located at (x, y). Indexed from top left.
768 ///
769 /// This function can be implemented in a way that ignores bounds checking.
770 /// # Safety
771 ///
772 /// The coordinates must be [`in_bounds`] of the image.
773 ///
774 /// [`in_bounds`]: #method.in_bounds
unsafe_get_pixel(&self, x: u32, y: u32) -> Self::Pixel775 unsafe fn unsafe_get_pixel(&self, x: u32, y: u32) -> Self::Pixel {
776 self.get_pixel(x, y)
777 }
778
779 /// Returns an Iterator over the pixels of this image.
780 /// The iterator yields the coordinates of each pixel
781 /// along with their value
pixels(&self) -> Pixels<Self>782 fn pixels(&self) -> Pixels<Self> {
783 let (width, height) = self.dimensions();
784
785 Pixels {
786 image: self,
787 x: 0,
788 y: 0,
789 width,
790 height,
791 }
792 }
793
794 /// Returns a reference to the underlying image.
inner(&self) -> &Self::InnerImageView795 fn inner(&self) -> &Self::InnerImageView;
796
797 /// Returns an subimage that is an immutable view into this image.
798 /// You can use [`GenericImage::sub_image`] if you need a mutable view instead.
799 /// The coordinates set the position of the top left corner of the view.
view(&self, x: u32, y: u32, width: u32, height: u32) -> SubImage<&Self::InnerImageView>800 fn view(&self, x: u32, y: u32, width: u32, height: u32) -> SubImage<&Self::InnerImageView> {
801 SubImage::new(self.inner(), x, y, width, height)
802 }
803 }
804
805 /// A trait for manipulating images.
806 pub trait GenericImage: GenericImageView {
807 /// Underlying image type. This is mainly used by SubImages in order to
808 /// always have a reference to the original image. This allows for less
809 /// indirections and it eases the use of nested SubImages.
810 type InnerImage: GenericImage<Pixel = Self::Pixel>;
811
812 /// Gets a reference to the mutable pixel at location `(x, y)`. Indexed from top left.
813 ///
814 /// # Panics
815 ///
816 /// Panics if `(x, y)` is out of bounds.
get_pixel_mut(&mut self, x: u32, y: u32) -> &mut Self::Pixel817 fn get_pixel_mut(&mut self, x: u32, y: u32) -> &mut Self::Pixel;
818
819 /// Put a pixel at location (x, y). Indexed from top left.
820 ///
821 /// # Panics
822 ///
823 /// Panics if `(x, y)` is out of bounds.
put_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel)824 fn put_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel);
825
826 /// Puts a pixel at location (x, y). Indexed from top left.
827 ///
828 /// This function can be implemented in a way that ignores bounds checking.
829 /// # Safety
830 ///
831 /// The coordinates must be [`in_bounds`] of the image.
832 ///
833 /// [`in_bounds`]: traits.GenericImageView.html#method.in_bounds
unsafe_put_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel)834 unsafe fn unsafe_put_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel) {
835 self.put_pixel(x, y, pixel);
836 }
837
838 /// Put a pixel at location (x, y), taking into account alpha channels
839 ///
840 /// DEPRECATED: This method will be removed. Blend the pixel directly instead.
blend_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel)841 fn blend_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel);
842
843 /// Copies all of the pixels from another image into this image.
844 ///
845 /// The other image is copied with the top-left corner of the
846 /// other image placed at (x, y).
847 ///
848 /// In order to copy only a piece of the other image, use [`GenericImageView::view`].
849 ///
850 /// You can use [`FlatSamples`] to source pixels from an arbitrary regular raster of channel
851 /// values, for example from a foreign interface or a fixed image.
852 ///
853 /// # Returns
854 /// Returns an error if the image is too large to be copied at the given position
855 ///
856 /// [`GenericImageView::view`]: trait.GenericImageView.html#method.view
857 /// [`FlatSamples`]: flat/struct.FlatSamples.html
copy_from<O>(&mut self, other: &O, x: u32, y: u32) -> ImageResult<()> where O: GenericImageView<Pixel = Self::Pixel>,858 fn copy_from<O>(&mut self, other: &O, x: u32, y: u32) -> ImageResult<()>
859 where
860 O: GenericImageView<Pixel = Self::Pixel>,
861 {
862 // Do bounds checking here so we can use the non-bounds-checking
863 // functions to copy pixels.
864 if self.width() < other.width() + x || self.height() < other.height() + y {
865 return Err(ImageError::Parameter(ParameterError::from_kind(
866 ParameterErrorKind::DimensionMismatch,
867 )));
868 }
869
870 for k in 0..other.height() {
871 for i in 0..other.width() {
872 let p = other.get_pixel(i, k);
873 self.put_pixel(i + x, k + y, p);
874 }
875 }
876 Ok(())
877 }
878
879 /// Copies all of the pixels from one part of this image to another part of this image.
880 ///
881 /// The destination rectangle of the copy is specified with the top-left corner placed at (x, y).
882 ///
883 /// # Returns
884 /// `true` if the copy was successful, `false` if the image could not
885 /// be copied due to size constraints.
copy_within(&mut self, source: Rect, x: u32, y: u32) -> bool886 fn copy_within(&mut self, source: Rect, x: u32, y: u32) -> bool {
887 let Rect { x: sx, y: sy, width, height } = source;
888 let dx = x;
889 let dy = y;
890 assert!(sx < self.width() && dx < self.width());
891 assert!(sy < self.height() && dy < self.height());
892 if self.width() - dx.max(sx) < width || self.height() - dy.max(sy) < height {
893 return false;
894 }
895 // since `.rev()` creates a new dype we would either have to go with dynamic dispatch for the ranges
896 // or have quite a lot of code bloat. A macro gives us static dispatch with less visible bloat.
897 macro_rules! copy_within_impl_ {
898 ($xiter:expr, $yiter:expr) => {
899 for y in $yiter {
900 let sy = sy + y;
901 let dy = dy + y;
902 for x in $xiter {
903 let sx = sx + x;
904 let dx = dx + x;
905 let pixel = self.get_pixel(sx, sy);
906 self.put_pixel(dx, dy, pixel);
907 }
908 }
909 };
910 }
911 // check how target and source rectangles relate to each other so we dont overwrite data before we copied it.
912 match (sx < dx, sy < dy) {
913 (true, true) => copy_within_impl_!((0..width).rev(), (0..height).rev()),
914 (true, false) => copy_within_impl_!((0..width).rev(), 0..height),
915 (false, true) => copy_within_impl_!(0..width, (0..height).rev()),
916 (false, false) => copy_within_impl_!(0..width, 0..height),
917 }
918 true
919 }
920
921 /// Returns a mutable reference to the underlying image.
inner_mut(&mut self) -> &mut Self::InnerImage922 fn inner_mut(&mut self) -> &mut Self::InnerImage;
923
924 /// Returns a mutable subimage that is a view into this image.
925 /// If you want an immutable subimage instead, use [`GenericImageView::view`]
926 /// The coordinates set the position of the top left corner of the SubImage.
sub_image( &mut self, x: u32, y: u32, width: u32, height: u32, ) -> SubImage<&mut Self::InnerImage>927 fn sub_image(
928 &mut self,
929 x: u32,
930 y: u32,
931 width: u32,
932 height: u32,
933 ) -> SubImage<&mut Self::InnerImage> {
934 SubImage::new(self.inner_mut(), x, y, width, height)
935 }
936 }
937
938 /// A View into another image
939 ///
940 /// Instances of this struct can be created using:
941 /// - [`GenericImage::sub_image`] to create a mutable view,
942 /// - [`GenericImageView::view`] to create an immutable view,
943 /// - [`SubImage::new`] to instantiate the struct directly.
944 pub struct SubImage<I> {
945 image: I,
946 xoffset: u32,
947 yoffset: u32,
948 xstride: u32,
949 ystride: u32,
950 }
951
952 /// Alias to access Pixel behind a reference
953 type DerefPixel<I> = <<I as Deref>::Target as GenericImageView>::Pixel;
954
955 /// Alias to access Subpixel behind a reference
956 type DerefSubpixel<I> = <DerefPixel<I> as Pixel>::Subpixel;
957
958 impl<I> SubImage<I> {
959 /// Construct a new subimage
960 /// The coordinates set the position of the top left corner of the SubImage.
new(image: I, x: u32, y: u32, width: u32, height: u32) -> SubImage<I>961 pub fn new(image: I, x: u32, y: u32, width: u32, height: u32) -> SubImage<I> {
962 SubImage {
963 image,
964 xoffset: x,
965 yoffset: y,
966 xstride: width,
967 ystride: height,
968 }
969 }
970
971 /// Change the coordinates of this subimage.
change_bounds(&mut self, x: u32, y: u32, width: u32, height: u32)972 pub fn change_bounds(&mut self, x: u32, y: u32, width: u32, height: u32) {
973 self.xoffset = x;
974 self.yoffset = y;
975 self.xstride = width;
976 self.ystride = height;
977 }
978
979 /// Convert this subimage to an ImageBuffer
to_image(&self) -> ImageBuffer<DerefPixel<I>, Vec<DerefSubpixel<I>>> where I: Deref, I::Target: GenericImage + 'static,980 pub fn to_image(&self) -> ImageBuffer<DerefPixel<I>, Vec<DerefSubpixel<I>>>
981 where
982 I: Deref,
983 I::Target: GenericImage + 'static,
984 {
985 let mut out = ImageBuffer::new(self.xstride, self.ystride);
986 let borrowed = self.image.deref();
987
988 for y in 0..self.ystride {
989 for x in 0..self.xstride {
990 let p = borrowed.get_pixel(x + self.xoffset, y + self.yoffset);
991 out.put_pixel(x, y, p);
992 }
993 }
994
995 out
996 }
997 }
998
999 #[allow(deprecated)]
1000 impl<I> GenericImageView for SubImage<I>
1001 where
1002 I: Deref,
1003 I::Target: GenericImageView + Sized,
1004 {
1005 type Pixel = DerefPixel<I>;
1006 type InnerImageView = I::Target;
1007
dimensions(&self) -> (u32, u32)1008 fn dimensions(&self) -> (u32, u32) {
1009 (self.xstride, self.ystride)
1010 }
1011
bounds(&self) -> (u32, u32, u32, u32)1012 fn bounds(&self) -> (u32, u32, u32, u32) {
1013 (self.xoffset, self.yoffset, self.xstride, self.ystride)
1014 }
1015
get_pixel(&self, x: u32, y: u32) -> Self::Pixel1016 fn get_pixel(&self, x: u32, y: u32) -> Self::Pixel {
1017 self.image.get_pixel(x + self.xoffset, y + self.yoffset)
1018 }
1019
view(&self, x: u32, y: u32, width: u32, height: u32) -> SubImage<&Self::InnerImageView>1020 fn view(&self, x: u32, y: u32, width: u32, height: u32) -> SubImage<&Self::InnerImageView> {
1021 let x = self.xoffset + x;
1022 let y = self.yoffset + y;
1023 SubImage::new(self.inner(), x, y, width, height)
1024 }
1025
inner(&self) -> &Self::InnerImageView1026 fn inner(&self) -> &Self::InnerImageView {
1027 &self.image
1028 }
1029 }
1030
1031 #[allow(deprecated)]
1032 impl<I> GenericImage for SubImage<I>
1033 where
1034 I: DerefMut,
1035 I::Target: GenericImage + Sized,
1036 {
1037 type InnerImage = I::Target;
1038
get_pixel_mut(&mut self, x: u32, y: u32) -> &mut Self::Pixel1039 fn get_pixel_mut(&mut self, x: u32, y: u32) -> &mut Self::Pixel {
1040 self.image.get_pixel_mut(x + self.xoffset, y + self.yoffset)
1041 }
1042
put_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel)1043 fn put_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel) {
1044 self.image
1045 .put_pixel(x + self.xoffset, y + self.yoffset, pixel)
1046 }
1047
1048 /// DEPRECATED: This method will be removed. Blend the pixel directly instead.
blend_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel)1049 fn blend_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel) {
1050 self.image
1051 .blend_pixel(x + self.xoffset, y + self.yoffset, pixel)
1052 }
1053
sub_image( &mut self, x: u32, y: u32, width: u32, height: u32, ) -> SubImage<&mut Self::InnerImage>1054 fn sub_image(
1055 &mut self,
1056 x: u32,
1057 y: u32,
1058 width: u32,
1059 height: u32,
1060 ) -> SubImage<&mut Self::InnerImage> {
1061 let x = self.xoffset + x;
1062 let y = self.yoffset + y;
1063 SubImage::new(self.inner_mut(), x, y, width, height)
1064 }
1065
inner_mut(&mut self) -> &mut Self::InnerImage1066 fn inner_mut(&mut self) -> &mut Self::InnerImage {
1067 &mut self.image
1068 }
1069 }
1070
1071 #[cfg(test)]
1072 mod tests {
1073 use std::io;
1074 use std::path::Path;
1075
1076 use super::{ColorType, ImageDecoder, ImageResult, GenericImage, GenericImageView, load_rect, ImageFormat};
1077 use crate::{GrayImage, ImageBuffer};
1078 use crate::color::Rgba;
1079 use crate::math::Rect;
1080
1081 #[test]
1082 /// Test that alpha blending works as expected
test_image_alpha_blending()1083 fn test_image_alpha_blending() {
1084 let mut target = ImageBuffer::new(1, 1);
1085 target.put_pixel(0, 0, Rgba([255u8, 0, 0, 255]));
1086 assert!(*target.get_pixel(0, 0) == Rgba([255, 0, 0, 255]));
1087 target.blend_pixel(0, 0, Rgba([0, 255, 0, 255]));
1088 assert!(*target.get_pixel(0, 0) == Rgba([0, 255, 0, 255]));
1089
1090 // Blending an alpha channel onto a solid background
1091 target.blend_pixel(0, 0, Rgba([255, 0, 0, 127]));
1092 assert!(*target.get_pixel(0, 0) == Rgba([127, 127, 0, 255]));
1093
1094 // Blending two alpha channels
1095 target.put_pixel(0, 0, Rgba([0, 255, 0, 127]));
1096 target.blend_pixel(0, 0, Rgba([255, 0, 0, 127]));
1097 assert!(*target.get_pixel(0, 0) == Rgba([169, 85, 0, 190]));
1098 }
1099
1100 #[test]
test_in_bounds()1101 fn test_in_bounds() {
1102 let mut target = ImageBuffer::new(2, 2);
1103 target.put_pixel(0, 0, Rgba([255u8, 0, 0, 255]));
1104
1105 assert!(target.in_bounds(0, 0));
1106 assert!(target.in_bounds(1, 0));
1107 assert!(target.in_bounds(0, 1));
1108 assert!(target.in_bounds(1, 1));
1109
1110 assert!(!target.in_bounds(2, 0));
1111 assert!(!target.in_bounds(0, 2));
1112 assert!(!target.in_bounds(2, 2));
1113 }
1114
1115 #[test]
test_can_subimage_clone_nonmut()1116 fn test_can_subimage_clone_nonmut() {
1117 let mut source = ImageBuffer::new(3, 3);
1118 source.put_pixel(1, 1, Rgba([255u8, 0, 0, 255]));
1119
1120 // A non-mutable copy of the source image
1121 let source = source.clone();
1122
1123 // Clone a view into non-mutable to a separate buffer
1124 let cloned = source.view(1, 1, 1, 1).to_image();
1125
1126 assert!(cloned.get_pixel(0, 0) == source.get_pixel(1, 1));
1127 }
1128
1129 #[test]
test_can_nest_views()1130 fn test_can_nest_views() {
1131 let mut source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
1132
1133 {
1134 let mut sub1 = source.sub_image(0, 0, 2, 2);
1135 let mut sub2 = sub1.sub_image(1, 1, 1, 1);
1136 sub2.put_pixel(0, 0, Rgba([0, 0, 0, 0]));
1137 }
1138
1139 assert_eq!(*source.get_pixel(1, 1), Rgba([0, 0, 0, 0]));
1140
1141 let view1 = source.view(0, 0, 2, 2);
1142 assert_eq!(*source.get_pixel(1, 1), view1.get_pixel(1, 1));
1143
1144 let view2 = view1.view(1, 1, 1, 1);
1145 assert_eq!(*source.get_pixel(1, 1), view2.get_pixel(0, 0));
1146 }
1147
1148 #[test]
test_load_rect()1149 fn test_load_rect() {
1150 struct MockDecoder {scanline_number: u64, scanline_bytes: u64}
1151 impl<'a> ImageDecoder<'a> for MockDecoder {
1152 type Reader = Box<dyn io::Read>;
1153 fn dimensions(&self) -> (u32, u32) {(5, 5)}
1154 fn color_type(&self) -> ColorType { ColorType::L8 }
1155 fn into_reader(self) -> ImageResult<Self::Reader> {unimplemented!()}
1156 fn scanline_bytes(&self) -> u64 { self.scanline_bytes }
1157 }
1158
1159 const DATA: [u8; 25] = [0, 1, 2, 3, 4,
1160 5, 6, 7, 8, 9,
1161 10, 11, 12, 13, 14,
1162 15, 16, 17, 18, 19,
1163 20, 21, 22, 23, 24];
1164
1165 fn seek_scanline(m: &mut MockDecoder, n: u64) -> io::Result<()> {
1166 m.scanline_number = n;
1167 Ok(())
1168 }
1169 fn read_scanline(m: &mut MockDecoder, buf: &mut [u8]) -> io::Result<()> {
1170 let bytes_read = m.scanline_number * m.scanline_bytes;
1171 if bytes_read >= 25 {
1172 return Ok(());
1173 }
1174
1175 let len = m.scanline_bytes.min(25 - bytes_read);
1176 buf[..(len as usize)].copy_from_slice(&DATA[(bytes_read as usize)..][..(len as usize)]);
1177 m.scanline_number += 1;
1178 Ok(())
1179 }
1180
1181 for scanline_bytes in 1..30 {
1182 let mut output = [0u8; 26];
1183
1184 load_rect(0, 0, 5, 5, &mut output, |_|{},
1185 &mut MockDecoder{scanline_number:0, scanline_bytes},
1186 seek_scanline, read_scanline).unwrap();
1187 assert_eq!(output[0..25], DATA);
1188 assert_eq!(output[25], 0);
1189
1190 output = [0u8; 26];
1191 load_rect(3, 2, 1, 1, &mut output, |_|{},
1192 &mut MockDecoder{scanline_number:0, scanline_bytes},
1193 seek_scanline, read_scanline).unwrap();
1194 assert_eq!(output[0..2], [13, 0]);
1195
1196 output = [0u8; 26];
1197 load_rect(3, 2, 2, 2, &mut output, |_|{},
1198 &mut MockDecoder{scanline_number:0, scanline_bytes},
1199 seek_scanline, read_scanline).unwrap();
1200 assert_eq!(output[0..5], [13, 14, 18, 19, 0]);
1201
1202
1203 output = [0u8; 26];
1204 load_rect(1, 1, 2, 4, &mut output, |_|{},
1205 &mut MockDecoder{scanline_number:0, scanline_bytes},
1206 seek_scanline, read_scanline).unwrap();
1207 assert_eq!(output[0..9], [6, 7, 11, 12, 16, 17, 21, 22, 0]);
1208
1209 }
1210 }
1211
1212 #[test]
test_load_rect_single_scanline()1213 fn test_load_rect_single_scanline() {
1214 const DATA: [u8; 25] = [0, 1, 2, 3, 4,
1215 5, 6, 7, 8, 9,
1216 10, 11, 12, 13, 14,
1217 15, 16, 17, 18, 19,
1218 20, 21, 22, 23, 24];
1219
1220 struct MockDecoder;
1221 impl<'a> ImageDecoder<'a> for MockDecoder {
1222 type Reader = Box<dyn io::Read>;
1223 fn dimensions(&self) -> (u32, u32) {(5, 5)}
1224 fn color_type(&self) -> ColorType { ColorType::L8 }
1225 fn into_reader(self) -> ImageResult<Self::Reader> {unimplemented!()}
1226 fn scanline_bytes(&self) -> u64 { 25 }
1227 }
1228
1229 // Ensure that seek scanline is called only once.
1230 let mut seeks = 0;
1231 let seek_scanline = |_d: &mut MockDecoder, n: u64| -> io::Result<()> {
1232 seeks += 1;
1233 assert_eq!(n, 0);
1234 assert_eq!(seeks, 1);
1235 Ok(())
1236 };
1237
1238 fn read_scanline(_m: &mut MockDecoder, buf: &mut [u8]) -> io::Result<()> {
1239 buf.copy_from_slice(&DATA);
1240 Ok(())
1241 }
1242
1243 let mut output = [0; 26];
1244 load_rect(1, 1, 2, 4, &mut output, |_|{},
1245 &mut MockDecoder,
1246 seek_scanline, read_scanline).unwrap();
1247 assert_eq!(output[0..9], [6, 7, 11, 12, 16, 17, 21, 22, 0]);
1248 }
1249
1250
1251 #[test]
test_image_format_from_path()1252 fn test_image_format_from_path() {
1253 fn from_path(s: &str) -> ImageResult<ImageFormat> {
1254 ImageFormat::from_path(Path::new(s))
1255 }
1256 assert_eq!(from_path("./a.jpg").unwrap(), ImageFormat::Jpeg);
1257 assert_eq!(from_path("./a.jpeg").unwrap(), ImageFormat::Jpeg);
1258 assert_eq!(from_path("./a.JPEG").unwrap(), ImageFormat::Jpeg);
1259 assert_eq!(from_path("./a.pNg").unwrap(), ImageFormat::Png);
1260 assert_eq!(from_path("./a.gif").unwrap(), ImageFormat::Gif);
1261 assert_eq!(from_path("./a.webp").unwrap(), ImageFormat::WebP);
1262 assert_eq!(from_path("./a.tiFF").unwrap(), ImageFormat::Tiff);
1263 assert_eq!(from_path("./a.tif").unwrap(), ImageFormat::Tiff);
1264 assert_eq!(from_path("./a.tga").unwrap(), ImageFormat::Tga);
1265 assert_eq!(from_path("./a.dds").unwrap(), ImageFormat::Dds);
1266 assert_eq!(from_path("./a.bmp").unwrap(), ImageFormat::Bmp);
1267 assert_eq!(from_path("./a.Ico").unwrap(), ImageFormat::Ico);
1268 assert_eq!(from_path("./a.hdr").unwrap(), ImageFormat::Hdr);
1269 assert_eq!(from_path("./a.pbm").unwrap(), ImageFormat::Pnm);
1270 assert_eq!(from_path("./a.pAM").unwrap(), ImageFormat::Pnm);
1271 assert_eq!(from_path("./a.Ppm").unwrap(), ImageFormat::Pnm);
1272 assert_eq!(from_path("./a.pgm").unwrap(), ImageFormat::Pnm);
1273 assert_eq!(from_path("./a.AViF").unwrap(), ImageFormat::Avif);
1274 assert!(from_path("./a.txt").is_err());
1275 assert!(from_path("./a").is_err());
1276 }
1277
1278 #[test]
test_generic_image_copy_within_oob()1279 fn test_generic_image_copy_within_oob() {
1280 let mut image: GrayImage = ImageBuffer::from_raw(4, 4, vec![0u8; 16]).unwrap();
1281 assert!(!image.sub_image(0, 0, 4, 4).copy_within(Rect { x: 0, y: 0, width: 5, height: 4 }, 0, 0));
1282 assert!(!image.sub_image(0, 0, 4, 4).copy_within(Rect { x: 0, y: 0, width: 4, height: 5 }, 0, 0));
1283 assert!(!image.sub_image(0, 0, 4, 4).copy_within(Rect { x: 1, y: 0, width: 4, height: 4 }, 0, 0));
1284 assert!(!image.sub_image(0, 0, 4, 4).copy_within(Rect { x: 0, y: 0, width: 4, height: 4 }, 1, 0));
1285 assert!(!image.sub_image(0, 0, 4, 4).copy_within(Rect { x: 0, y: 1, width: 4, height: 4 }, 0, 0));
1286 assert!(!image.sub_image(0, 0, 4, 4).copy_within(Rect { x: 0, y: 0, width: 4, height: 4 }, 0, 1));
1287 assert!(!image.sub_image(0, 0, 4, 4).copy_within(Rect { x: 1, y: 1, width: 4, height: 4 }, 0, 0));
1288 }
1289
1290 #[test]
test_generic_image_copy_within_tl()1291 fn test_generic_image_copy_within_tl() {
1292 let data = &[
1293 00, 01, 02, 03,
1294 04, 05, 06, 07,
1295 08, 09, 10, 11,
1296 12, 13, 14, 15
1297 ];
1298 let expected = [
1299 00, 01, 02, 03,
1300 04, 00, 01, 02,
1301 08, 04, 05, 06,
1302 12, 08, 09, 10,
1303 ];
1304 let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap();
1305 assert!(image.sub_image(0, 0, 4, 4).copy_within(Rect { x: 0, y: 0, width: 3, height: 3 }, 1, 1));
1306 assert_eq!(&image.into_raw(), &expected);
1307 }
1308
1309 #[test]
test_generic_image_copy_within_tr()1310 fn test_generic_image_copy_within_tr() {
1311 let data = &[
1312 00, 01, 02, 03,
1313 04, 05, 06, 07,
1314 08, 09, 10, 11,
1315 12, 13, 14, 15
1316 ];
1317 let expected = [
1318 00, 01, 02, 03,
1319 01, 02, 03, 07,
1320 05, 06, 07, 11,
1321 09, 10, 11, 15
1322 ];
1323 let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap();
1324 assert!(image.sub_image(0, 0, 4, 4).copy_within(Rect { x: 1, y: 0, width: 3, height: 3 }, 0, 1));
1325 assert_eq!(&image.into_raw(), &expected);
1326 }
1327
1328 #[test]
test_generic_image_copy_within_bl()1329 fn test_generic_image_copy_within_bl() {
1330 let data = &[
1331 00, 01, 02, 03,
1332 04, 05, 06, 07,
1333 08, 09, 10, 11,
1334 12, 13, 14, 15
1335 ];
1336 let expected = [
1337 00, 04, 05, 06,
1338 04, 08, 09, 10,
1339 08, 12, 13, 14,
1340 12, 13, 14, 15
1341 ];
1342 let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap();
1343 assert!(image.sub_image(0, 0, 4, 4).copy_within(Rect { x: 0, y: 1, width: 3, height: 3 }, 1, 0));
1344 assert_eq!(&image.into_raw(), &expected);
1345 }
1346
1347 #[test]
test_generic_image_copy_within_br()1348 fn test_generic_image_copy_within_br() {
1349 let data = &[
1350 00, 01, 02, 03,
1351 04, 05, 06, 07,
1352 08, 09, 10, 11,
1353 12, 13, 14, 15
1354 ];
1355 let expected = [
1356 05, 06, 07, 03,
1357 09, 10, 11, 07,
1358 13, 14, 15, 11,
1359 12, 13, 14, 15
1360 ];
1361 let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap();
1362 assert!(image.sub_image(0, 0, 4, 4).copy_within(Rect { x: 1, y: 1, width: 3, height: 3 }, 0, 0));
1363 assert_eq!(&image.into_raw(), &expected);
1364 }
1365
1366 #[test]
image_formats_are_recognized()1367 fn image_formats_are_recognized() {
1368 use ImageFormat::*;
1369 const ALL_FORMATS: &'static [ImageFormat] = &[Avif, Png, Jpeg, Gif, WebP, Pnm, Tiff, Tga, Dds, Bmp, Ico, Hdr, Farbfeld];
1370 for &format in ALL_FORMATS {
1371 let mut file = Path::new("file.nothing").to_owned();
1372 for ext in format.extensions_str() {
1373 assert!(file.set_extension(ext));
1374 match ImageFormat::from_path(&file) {
1375 Err(_) => panic!("Path {} not recognized as {:?}", file.display(), format),
1376 Ok(result) => assert_eq!(format, result),
1377 }
1378 }
1379 }
1380 }
1381 }
1382