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