1use std::io;
2use std::io::{Seek, Write};
3use std::path::Path;
4use std::u32;
5
6#[cfg(feature = "gif")]
7use crate::codecs::gif;
8#[cfg(feature = "png")]
9use crate::codecs::png;
10#[cfg(feature = "pnm")]
11use crate::codecs::pnm;
12
13use crate::buffer_::{
14 ConvertBuffer, Gray16Image, GrayAlpha16Image, GrayAlphaImage, GrayImage, ImageBuffer,
15 Rgb16Image, RgbImage, Rgba16Image, RgbaImage,
16};
17use crate::color::{self, IntoColor};
18use crate::error::{ImageError, ImageResult, ParameterError, ParameterErrorKind};
19use crate::flat::FlatSamples;
20use crate::image::{
21 GenericImage, GenericImageView, ImageDecoder, ImageEncoder, ImageFormat, ImageOutputFormat,
22};
23use crate::imageops;
24use crate::io::free_functions;
25use crate::math::resize_dimensions;
26use crate::traits::Pixel;
27use crate::{image, Luma, LumaA};
28use crate::{Rgb32FImage, Rgba32FImage};
29
30/// A Dynamic Image
31///
32/// This represents a _matrix_ of _pixels_ which are _convertible_ from and to an _RGBA_
33/// representation. More variants that adhere to these principles may get added in the future, in
34/// particular to cover other combinations typically used.
35///
36/// # Usage
37///
38/// This type can act as a converter between specific `ImageBuffer` instances.
39///
40/// ```
41/// use image::{DynamicImage, GrayImage, RgbImage};
42///
43/// let rgb: RgbImage = RgbImage::new(10, 10);
44/// let luma: GrayImage = DynamicImage::ImageRgb8(rgb).into_luma8();
45/// ```
46///
47/// # Design
48///
49/// There is no goal to provide an all-encompassing type with all possible memory layouts. This
50/// would hardly be feasible as a simple enum, due to the sheer number of combinations of channel
51/// kinds, channel order, and bit depth. Rather, this type provides an opinionated selection with
52/// normalized channel order which can store common pixel values without loss.
53#[derive(Clone, Debug, PartialEq)]
54#[non_exhaustive]
55pub enum DynamicImage {
56 /// Each pixel in this image is 8-bit Luma
57 ImageLuma8(GrayImage),
58
59 /// Each pixel in this image is 8-bit Luma with alpha
60 ImageLumaA8(GrayAlphaImage),
61
62 /// Each pixel in this image is 8-bit Rgb
63 ImageRgb8(RgbImage),
64
65 /// Each pixel in this image is 8-bit Rgb with alpha
66 ImageRgba8(RgbaImage),
67
68 /// Each pixel in this image is 16-bit Luma
69 ImageLuma16(Gray16Image),
70
71 /// Each pixel in this image is 16-bit Luma with alpha
72 ImageLumaA16(GrayAlpha16Image),
73
74 /// Each pixel in this image is 16-bit Rgb
75 ImageRgb16(Rgb16Image),
76
77 /// Each pixel in this image is 16-bit Rgb with alpha
78 ImageRgba16(Rgba16Image),
79
80 /// Each pixel in this image is 32-bit float Rgb
81 ImageRgb32F(Rgb32FImage),
82
83 /// Each pixel in this image is 32-bit float Rgb with alpha
84 ImageRgba32F(Rgba32FImage),
85}
86
87macro_rules! dynamic_map(
88 ($dynimage: expr, $image: pat => $action: expr) => ({
89 use DynamicImage::*;
90 match $dynimage {
91 ImageLuma8($image) => ImageLuma8($action),
92 ImageLumaA8($image) => ImageLumaA8($action),
93 ImageRgb8($image) => ImageRgb8($action),
94 ImageRgba8($image) => ImageRgba8($action),
95 ImageLuma16($image) => ImageLuma16($action),
96 ImageLumaA16($image) => ImageLumaA16($action),
97 ImageRgb16($image) => ImageRgb16($action),
98 ImageRgba16($image) => ImageRgba16($action),
99 ImageRgb32F($image) => ImageRgb32F($action),
100 ImageRgba32F($image) => ImageRgba32F($action),
101 }
102 });
103
104 ($dynimage: expr, $image:pat_param, $action: expr) => (
105 match $dynimage {
106 DynamicImage::ImageLuma8($image) => $action,
107 DynamicImage::ImageLumaA8($image) => $action,
108 DynamicImage::ImageRgb8($image) => $action,
109 DynamicImage::ImageRgba8($image) => $action,
110 DynamicImage::ImageLuma16($image) => $action,
111 DynamicImage::ImageLumaA16($image) => $action,
112 DynamicImage::ImageRgb16($image) => $action,
113 DynamicImage::ImageRgba16($image) => $action,
114 DynamicImage::ImageRgb32F($image) => $action,
115 DynamicImage::ImageRgba32F($image) => $action,
116 }
117 );
118);
119
120impl DynamicImage {
121 /// Creates a dynamic image backed by a buffer depending on
122 /// the color type given.
123 pub fn new(w: u32, h: u32, color: color::ColorType) -> DynamicImage {
124 use color::ColorType::*;
125 match color {
126 L8 => Self::new_luma8(w, h),
127 La8 => Self::new_luma_a8(w, h),
128 Rgb8 => Self::new_rgb8(w, h),
129 Rgba8 => Self::new_rgba8(w, h),
130 L16 => Self::new_luma16(w, h),
131 La16 => Self::new_luma_a16(w, h),
132 Rgb16 => Self::new_rgb16(w, h),
133 Rgba16 => Self::new_rgba16(w, h),
134 Rgb32F => Self::new_rgb32f(w, h),
135 Rgba32F => Self::new_rgba32f(w, h),
136 }
137 }
138
139 /// Creates a dynamic image backed by a buffer of gray pixels.
140 pub fn new_luma8(w: u32, h: u32) -> DynamicImage {
141 DynamicImage::ImageLuma8(ImageBuffer::new(w, h))
142 }
143
144 /// Creates a dynamic image backed by a buffer of gray
145 /// pixels with transparency.
146 pub fn new_luma_a8(w: u32, h: u32) -> DynamicImage {
147 DynamicImage::ImageLumaA8(ImageBuffer::new(w, h))
148 }
149
150 /// Creates a dynamic image backed by a buffer of RGB pixels.
151 pub fn new_rgb8(w: u32, h: u32) -> DynamicImage {
152 DynamicImage::ImageRgb8(ImageBuffer::new(w, h))
153 }
154
155 /// Creates a dynamic image backed by a buffer of RGBA pixels.
156 pub fn new_rgba8(w: u32, h: u32) -> DynamicImage {
157 DynamicImage::ImageRgba8(ImageBuffer::new(w, h))
158 }
159
160 /// Creates a dynamic image backed by a buffer of gray pixels.
161 pub fn new_luma16(w: u32, h: u32) -> DynamicImage {
162 DynamicImage::ImageLuma16(ImageBuffer::new(w, h))
163 }
164
165 /// Creates a dynamic image backed by a buffer of gray
166 /// pixels with transparency.
167 pub fn new_luma_a16(w: u32, h: u32) -> DynamicImage {
168 DynamicImage::ImageLumaA16(ImageBuffer::new(w, h))
169 }
170
171 /// Creates a dynamic image backed by a buffer of RGB pixels.
172 pub fn new_rgb16(w: u32, h: u32) -> DynamicImage {
173 DynamicImage::ImageRgb16(ImageBuffer::new(w, h))
174 }
175
176 /// Creates a dynamic image backed by a buffer of RGBA pixels.
177 pub fn new_rgba16(w: u32, h: u32) -> DynamicImage {
178 DynamicImage::ImageRgba16(ImageBuffer::new(w, h))
179 }
180
181 /// Creates a dynamic image backed by a buffer of RGB pixels.
182 pub fn new_rgb32f(w: u32, h: u32) -> DynamicImage {
183 DynamicImage::ImageRgb32F(ImageBuffer::new(w, h))
184 }
185
186 /// Creates a dynamic image backed by a buffer of RGBA pixels.
187 pub fn new_rgba32f(w: u32, h: u32) -> DynamicImage {
188 DynamicImage::ImageRgba32F(ImageBuffer::new(w, h))
189 }
190
191 /// Decodes an encoded image into a dynamic image.
192 pub fn from_decoder<'a>(decoder: impl ImageDecoder<'a>) -> ImageResult<Self> {
193 decoder_to_image(decoder)
194 }
195
196 /// Returns a copy of this image as an RGB image.
197 pub fn to_rgb8(&self) -> RgbImage {
198 dynamic_map!(*self, ref p, p.convert())
199 }
200
201 /// Returns a copy of this image as an RGB image.
202 pub fn to_rgb16(&self) -> Rgb16Image {
203 dynamic_map!(*self, ref p, p.convert())
204 }
205
206 /// Returns a copy of this image as an RGB image.
207 pub fn to_rgb32f(&self) -> Rgb32FImage {
208 dynamic_map!(*self, ref p, p.convert())
209 }
210
211 /// Returns a copy of this image as an RGBA image.
212 pub fn to_rgba8(&self) -> RgbaImage {
213 dynamic_map!(*self, ref p, p.convert())
214 }
215
216 /// Returns a copy of this image as an RGBA image.
217 pub fn to_rgba16(&self) -> Rgba16Image {
218 dynamic_map!(*self, ref p, p.convert())
219 }
220
221 /// Returns a copy of this image as an RGBA image.
222 pub fn to_rgba32f(&self) -> Rgba32FImage {
223 dynamic_map!(*self, ref p, p.convert())
224 }
225
226 /// Returns a copy of this image as a Luma image.
227 pub fn to_luma8(&self) -> GrayImage {
228 dynamic_map!(*self, ref p, p.convert())
229 }
230
231 /// Returns a copy of this image as a Luma image.
232 pub fn to_luma16(&self) -> Gray16Image {
233 dynamic_map!(*self, ref p, p.convert())
234 }
235
236 /// Returns a copy of this image as a Luma image.
237 pub fn to_luma32f(&self) -> ImageBuffer<Luma<f32>, Vec<f32>> {
238 dynamic_map!(*self, ref p, p.convert())
239 }
240
241 /// Returns a copy of this image as a LumaA image.
242 pub fn to_luma_alpha8(&self) -> GrayAlphaImage {
243 dynamic_map!(*self, ref p, p.convert())
244 }
245
246 /// Returns a copy of this image as a LumaA image.
247 pub fn to_luma_alpha16(&self) -> GrayAlpha16Image {
248 dynamic_map!(*self, ref p, p.convert())
249 }
250
251 /// Returns a copy of this image as a LumaA image.
252 pub fn to_luma_alpha32f(&self) -> ImageBuffer<LumaA<f32>, Vec<f32>> {
253 dynamic_map!(*self, ref p, p.convert())
254 }
255
256 /// Consume the image and returns a RGB image.
257 ///
258 /// If the image was already the correct format, it is returned as is.
259 /// Otherwise, a copy is created.
260 pub fn into_rgb8(self) -> RgbImage {
261 match self {
262 DynamicImage::ImageRgb8(x) => x,
263 x => x.to_rgb8(),
264 }
265 }
266
267 /// Consume the image and returns a RGB image.
268 ///
269 /// If the image was already the correct format, it is returned as is.
270 /// Otherwise, a copy is created.
271 pub fn into_rgb16(self) -> Rgb16Image {
272 match self {
273 DynamicImage::ImageRgb16(x) => x,
274 x => x.to_rgb16(),
275 }
276 }
277
278 /// Consume the image and returns a RGB image.
279 ///
280 /// If the image was already the correct format, it is returned as is.
281 /// Otherwise, a copy is created.
282 pub fn into_rgb32f(self) -> Rgb32FImage {
283 match self {
284 DynamicImage::ImageRgb32F(x) => x,
285 x => x.to_rgb32f(),
286 }
287 }
288
289 /// Consume the image and returns a RGBA image.
290 ///
291 /// If the image was already the correct format, it is returned as is.
292 /// Otherwise, a copy is created.
293 pub fn into_rgba8(self) -> RgbaImage {
294 match self {
295 DynamicImage::ImageRgba8(x) => x,
296 x => x.to_rgba8(),
297 }
298 }
299
300 /// Consume the image and returns a RGBA image.
301 ///
302 /// If the image was already the correct format, it is returned as is.
303 /// Otherwise, a copy is created.
304 pub fn into_rgba16(self) -> Rgba16Image {
305 match self {
306 DynamicImage::ImageRgba16(x) => x,
307 x => x.to_rgba16(),
308 }
309 }
310
311 /// Consume the image and returns a RGBA image.
312 ///
313 /// If the image was already the correct format, it is returned as is.
314 /// Otherwise, a copy is created.
315 pub fn into_rgba32f(self) -> Rgba32FImage {
316 match self {
317 DynamicImage::ImageRgba32F(x) => x,
318 x => x.to_rgba32f(),
319 }
320 }
321
322 /// Consume the image and returns a Luma image.
323 ///
324 /// If the image was already the correct format, it is returned as is.
325 /// Otherwise, a copy is created.
326 pub fn into_luma8(self) -> GrayImage {
327 match self {
328 DynamicImage::ImageLuma8(x) => x,
329 x => x.to_luma8(),
330 }
331 }
332
333 /// Consume the image and returns a Luma image.
334 ///
335 /// If the image was already the correct format, it is returned as is.
336 /// Otherwise, a copy is created.
337 pub fn into_luma16(self) -> Gray16Image {
338 match self {
339 DynamicImage::ImageLuma16(x) => x,
340 x => x.to_luma16(),
341 }
342 }
343
344 /// Consume the image and returns a LumaA image.
345 ///
346 /// If the image was already the correct format, it is returned as is.
347 /// Otherwise, a copy is created.
348 pub fn into_luma_alpha8(self) -> GrayAlphaImage {
349 match self {
350 DynamicImage::ImageLumaA8(x) => x,
351 x => x.to_luma_alpha8(),
352 }
353 }
354
355 /// Consume the image and returns a LumaA image.
356 ///
357 /// If the image was already the correct format, it is returned as is.
358 /// Otherwise, a copy is created.
359 pub fn into_luma_alpha16(self) -> GrayAlpha16Image {
360 match self {
361 DynamicImage::ImageLumaA16(x) => x,
362 x => x.to_luma_alpha16(),
363 }
364 }
365
366 /// Return a cut-out of this image delimited by the bounding rectangle.
367 ///
368 /// Note: this method does *not* modify the object,
369 /// and its signature will be replaced with `crop_imm()`'s in the 0.24 release
370 pub fn crop(&mut self, x: u32, y: u32, width: u32, height: u32) -> DynamicImage {
371 dynamic_map!(*self, ref mut p => imageops::crop(p, x, y, width, height).to_image())
372 }
373
374 /// Return a cut-out of this image delimited by the bounding rectangle.
375 pub fn crop_imm(&self, x: u32, y: u32, width: u32, height: u32) -> DynamicImage {
376 dynamic_map!(*self, ref p => imageops::crop_imm(p, x, y, width, height).to_image())
377 }
378
379 /// Return a reference to an 8bit RGB image
380 pub fn as_rgb8(&self) -> Option<&RgbImage> {
381 match *self {
382 DynamicImage::ImageRgb8(ref p) => Some(p),
383 _ => None,
384 }
385 }
386
387 /// Return a mutable reference to an 8bit RGB image
388 pub fn as_mut_rgb8(&mut self) -> Option<&mut RgbImage> {
389 match *self {
390 DynamicImage::ImageRgb8(ref mut p) => Some(p),
391 _ => None,
392 }
393 }
394
395 /// Return a reference to an 8bit RGBA image
396 pub fn as_rgba8(&self) -> Option<&RgbaImage> {
397 match *self {
398 DynamicImage::ImageRgba8(ref p) => Some(p),
399 _ => None,
400 }
401 }
402
403 /// Return a mutable reference to an 8bit RGBA image
404 pub fn as_mut_rgba8(&mut self) -> Option<&mut RgbaImage> {
405 match *self {
406 DynamicImage::ImageRgba8(ref mut p) => Some(p),
407 _ => None,
408 }
409 }
410
411 /// Return a reference to an 8bit Grayscale image
412 pub fn as_luma8(&self) -> Option<&GrayImage> {
413 match *self {
414 DynamicImage::ImageLuma8(ref p) => Some(p),
415 _ => None,
416 }
417 }
418
419 /// Return a mutable reference to an 8bit Grayscale image
420 pub fn as_mut_luma8(&mut self) -> Option<&mut GrayImage> {
421 match *self {
422 DynamicImage::ImageLuma8(ref mut p) => Some(p),
423 _ => None,
424 }
425 }
426
427 /// Return a reference to an 8bit Grayscale image with an alpha channel
428 pub fn as_luma_alpha8(&self) -> Option<&GrayAlphaImage> {
429 match *self {
430 DynamicImage::ImageLumaA8(ref p) => Some(p),
431 _ => None,
432 }
433 }
434
435 /// Return a mutable reference to an 8bit Grayscale image with an alpha channel
436 pub fn as_mut_luma_alpha8(&mut self) -> Option<&mut GrayAlphaImage> {
437 match *self {
438 DynamicImage::ImageLumaA8(ref mut p) => Some(p),
439 _ => None,
440 }
441 }
442
443 /// Return a reference to an 16bit RGB image
444 pub fn as_rgb16(&self) -> Option<&Rgb16Image> {
445 match *self {
446 DynamicImage::ImageRgb16(ref p) => Some(p),
447 _ => None,
448 }
449 }
450
451 /// Return a mutable reference to an 16bit RGB image
452 pub fn as_mut_rgb16(&mut self) -> Option<&mut Rgb16Image> {
453 match *self {
454 DynamicImage::ImageRgb16(ref mut p) => Some(p),
455 _ => None,
456 }
457 }
458
459 /// Return a reference to an 16bit RGBA image
460 pub fn as_rgba16(&self) -> Option<&Rgba16Image> {
461 match *self {
462 DynamicImage::ImageRgba16(ref p) => Some(p),
463 _ => None,
464 }
465 }
466
467 /// Return a mutable reference to an 16bit RGBA image
468 pub fn as_mut_rgba16(&mut self) -> Option<&mut Rgba16Image> {
469 match *self {
470 DynamicImage::ImageRgba16(ref mut p) => Some(p),
471 _ => None,
472 }
473 }
474
475 /// Return a reference to an 32bit RGB image
476 pub fn as_rgb32f(&self) -> Option<&Rgb32FImage> {
477 match *self {
478 DynamicImage::ImageRgb32F(ref p) => Some(p),
479 _ => None,
480 }
481 }
482
483 /// Return a mutable reference to an 32bit RGB image
484 pub fn as_mut_rgb32f(&mut self) -> Option<&mut Rgb32FImage> {
485 match *self {
486 DynamicImage::ImageRgb32F(ref mut p) => Some(p),
487 _ => None,
488 }
489 }
490
491 /// Return a reference to an 32bit RGBA image
492 pub fn as_rgba32f(&self) -> Option<&Rgba32FImage> {
493 match *self {
494 DynamicImage::ImageRgba32F(ref p) => Some(p),
495 _ => None,
496 }
497 }
498
499 /// Return a mutable reference to an 16bit RGBA image
500 pub fn as_mut_rgba32f(&mut self) -> Option<&mut Rgba32FImage> {
501 match *self {
502 DynamicImage::ImageRgba32F(ref mut p) => Some(p),
503 _ => None,
504 }
505 }
506
507 /// Return a reference to an 16bit Grayscale image
508 pub fn as_luma16(&self) -> Option<&Gray16Image> {
509 match *self {
510 DynamicImage::ImageLuma16(ref p) => Some(p),
511 _ => None,
512 }
513 }
514
515 /// Return a mutable reference to an 16bit Grayscale image
516 pub fn as_mut_luma16(&mut self) -> Option<&mut Gray16Image> {
517 match *self {
518 DynamicImage::ImageLuma16(ref mut p) => Some(p),
519 _ => None,
520 }
521 }
522
523 /// Return a reference to an 16bit Grayscale image with an alpha channel
524 pub fn as_luma_alpha16(&self) -> Option<&GrayAlpha16Image> {
525 match *self {
526 DynamicImage::ImageLumaA16(ref p) => Some(p),
527 _ => None,
528 }
529 }
530
531 /// Return a mutable reference to an 16bit Grayscale image with an alpha channel
532 pub fn as_mut_luma_alpha16(&mut self) -> Option<&mut GrayAlpha16Image> {
533 match *self {
534 DynamicImage::ImageLumaA16(ref mut p) => Some(p),
535 _ => None,
536 }
537 }
538
539 /// Return a view on the raw sample buffer for 8 bit per channel images.
540 pub fn as_flat_samples_u8(&self) -> Option<FlatSamples<&[u8]>> {
541 match *self {
542 DynamicImage::ImageLuma8(ref p) => Some(p.as_flat_samples()),
543 DynamicImage::ImageLumaA8(ref p) => Some(p.as_flat_samples()),
544 DynamicImage::ImageRgb8(ref p) => Some(p.as_flat_samples()),
545 DynamicImage::ImageRgba8(ref p) => Some(p.as_flat_samples()),
546 _ => None,
547 }
548 }
549
550 /// Return a view on the raw sample buffer for 16 bit per channel images.
551 pub fn as_flat_samples_u16(&self) -> Option<FlatSamples<&[u16]>> {
552 match *self {
553 DynamicImage::ImageLuma16(ref p) => Some(p.as_flat_samples()),
554 DynamicImage::ImageLumaA16(ref p) => Some(p.as_flat_samples()),
555 DynamicImage::ImageRgb16(ref p) => Some(p.as_flat_samples()),
556 DynamicImage::ImageRgba16(ref p) => Some(p.as_flat_samples()),
557 _ => None,
558 }
559 }
560
561 /// Return a view on the raw sample buffer for 32bit per channel images.
562 pub fn as_flat_samples_f32(&self) -> Option<FlatSamples<&[f32]>> {
563 match *self {
564 DynamicImage::ImageRgb32F(ref p) => Some(p.as_flat_samples()),
565 DynamicImage::ImageRgba32F(ref p) => Some(p.as_flat_samples()),
566 _ => None,
567 }
568 }
569
570 /// Return this image's pixels as a native endian byte slice.
571 pub fn as_bytes(&self) -> &[u8] {
572 // we can do this because every variant contains an `ImageBuffer<_, Vec<_>>`
573 dynamic_map!(
574 *self,
575 ref image_buffer,
576 bytemuck::cast_slice(image_buffer.as_raw().as_ref())
577 )
578 }
579
580 // TODO: choose a name under which to expose?
581 fn inner_bytes(&self) -> &[u8] {
582 // we can do this because every variant contains an `ImageBuffer<_, Vec<_>>`
583 dynamic_map!(
584 *self,
585 ref image_buffer,
586 bytemuck::cast_slice(image_buffer.inner_pixels())
587 )
588 }
589
590 /// Return this image's pixels as a byte vector. If the `ImageBuffer`
591 /// container is `Vec<u8>`, this operation is free. Otherwise, a copy
592 /// is returned.
593 pub fn into_bytes(self) -> Vec<u8> {
594 // we can do this because every variant contains an `ImageBuffer<_, Vec<_>>`
595 dynamic_map!(self, image_buffer, {
596 match bytemuck::allocation::try_cast_vec(image_buffer.into_raw()) {
597 Ok(vec) => vec,
598 Err((_, vec)) => {
599 // Fallback: vector requires an exact alignment and size match
600 // Reuse of the allocation as done in the Ok branch only works if the
601 // underlying container is exactly Vec<u8> (or compatible but that's the only
602 // alternative at the time of writing).
603 // In all other cases we must allocate a new vector with the 'same' contents.
604 bytemuck::cast_slice(&vec).to_owned()
605 }
606 }
607 })
608 }
609
610 /// Return a copy of this image's pixels as a byte vector.
611 /// Deprecated, because it does nothing but hide an expensive clone operation.
612 #[deprecated(
613 since = "0.24.0",
614 note = "use `image.into_bytes()` or `image.as_bytes().to_vec()` instead"
615 )]
616 pub fn to_bytes(&self) -> Vec<u8> {
617 self.as_bytes().to_vec()
618 }
619
620 /// Return this image's color type.
621 pub fn color(&self) -> color::ColorType {
622 match *self {
623 DynamicImage::ImageLuma8(_) => color::ColorType::L8,
624 DynamicImage::ImageLumaA8(_) => color::ColorType::La8,
625 DynamicImage::ImageRgb8(_) => color::ColorType::Rgb8,
626 DynamicImage::ImageRgba8(_) => color::ColorType::Rgba8,
627 DynamicImage::ImageLuma16(_) => color::ColorType::L16,
628 DynamicImage::ImageLumaA16(_) => color::ColorType::La16,
629 DynamicImage::ImageRgb16(_) => color::ColorType::Rgb16,
630 DynamicImage::ImageRgba16(_) => color::ColorType::Rgba16,
631 DynamicImage::ImageRgb32F(_) => color::ColorType::Rgb32F,
632 DynamicImage::ImageRgba32F(_) => color::ColorType::Rgba32F,
633 }
634 }
635
636 /// Returns the width of the underlying image
637 pub fn width(&self) -> u32 {
638 dynamic_map!(*self, ref p, { p.width() })
639 }
640
641 /// Returns the height of the underlying image
642 pub fn height(&self) -> u32 {
643 dynamic_map!(*self, ref p, { p.height() })
644 }
645
646 /// Return a grayscale version of this image.
647 /// Returns `Luma` images in most cases. However, for `f32` images,
648 /// this will return a grayscale `Rgb/Rgba` image instead.
649 pub fn grayscale(&self) -> DynamicImage {
650 match *self {
651 DynamicImage::ImageLuma8(ref p) => DynamicImage::ImageLuma8(p.clone()),
652 DynamicImage::ImageLumaA8(ref p) => {
653 DynamicImage::ImageLumaA8(imageops::grayscale_alpha(p))
654 }
655 DynamicImage::ImageRgb8(ref p) => DynamicImage::ImageLuma8(imageops::grayscale(p)),
656 DynamicImage::ImageRgba8(ref p) => {
657 DynamicImage::ImageLumaA8(imageops::grayscale_alpha(p))
658 }
659 DynamicImage::ImageLuma16(ref p) => DynamicImage::ImageLuma16(p.clone()),
660 DynamicImage::ImageLumaA16(ref p) => {
661 DynamicImage::ImageLumaA16(imageops::grayscale_alpha(p))
662 }
663 DynamicImage::ImageRgb16(ref p) => DynamicImage::ImageLuma16(imageops::grayscale(p)),
664 DynamicImage::ImageRgba16(ref p) => {
665 DynamicImage::ImageLumaA16(imageops::grayscale_alpha(p))
666 }
667 DynamicImage::ImageRgb32F(ref p) => {
668 DynamicImage::ImageRgb32F(imageops::grayscale_with_type(p))
669 }
670 DynamicImage::ImageRgba32F(ref p) => {
671 DynamicImage::ImageRgba32F(imageops::grayscale_with_type_alpha(p))
672 }
673 }
674 }
675
676 /// Invert the colors of this image.
677 /// This method operates inplace.
678 pub fn invert(&mut self) {
679 dynamic_map!(*self, ref mut p, imageops::invert(p))
680 }
681
682 /// Resize this image using the specified filter algorithm.
683 /// Returns a new image. The image's aspect ratio is preserved.
684 /// The image is scaled to the maximum possible size that fits
685 /// within the bounds specified by `nwidth` and `nheight`.
686 pub fn resize(&self, nwidth: u32, nheight: u32, filter: imageops::FilterType) -> DynamicImage {
687 if (nwidth, nheight) == self.dimensions() {
688 return self.clone();
689 }
690 let (width2, height2) =
691 resize_dimensions(self.width(), self.height(), nwidth, nheight, false);
692
693 self.resize_exact(width2, height2, filter)
694 }
695
696 /// Resize this image using the specified filter algorithm.
697 /// Returns a new image. Does not preserve aspect ratio.
698 /// `nwidth` and `nheight` are the new image's dimensions
699 pub fn resize_exact(
700 &self,
701 nwidth: u32,
702 nheight: u32,
703 filter: imageops::FilterType,
704 ) -> DynamicImage {
705 dynamic_map!(*self, ref p => imageops::resize(p, nwidth, nheight, filter))
706 }
707
708 /// Scale this image down to fit within a specific size.
709 /// Returns a new image. The image's aspect ratio is preserved.
710 /// The image is scaled to the maximum possible size that fits
711 /// within the bounds specified by `nwidth` and `nheight`.
712 ///
713 /// This method uses a fast integer algorithm where each source
714 /// pixel contributes to exactly one target pixel.
715 /// May give aliasing artifacts if new size is close to old size.
716 pub fn thumbnail(&self, nwidth: u32, nheight: u32) -> DynamicImage {
717 let (width2, height2) =
718 resize_dimensions(self.width(), self.height(), nwidth, nheight, false);
719 self.thumbnail_exact(width2, height2)
720 }
721
722 /// Scale this image down to a specific size.
723 /// Returns a new image. Does not preserve aspect ratio.
724 /// `nwidth` and `nheight` are the new image's dimensions.
725 /// This method uses a fast integer algorithm where each source
726 /// pixel contributes to exactly one target pixel.
727 /// May give aliasing artifacts if new size is close to old size.
728 pub fn thumbnail_exact(&self, nwidth: u32, nheight: u32) -> DynamicImage {
729 dynamic_map!(*self, ref p => imageops::thumbnail(p, nwidth, nheight))
730 }
731
732 /// Resize this image using the specified filter algorithm.
733 /// Returns a new image. The image's aspect ratio is preserved.
734 /// The image is scaled to the maximum possible size that fits
735 /// within the larger (relative to aspect ratio) of the bounds
736 /// specified by `nwidth` and `nheight`, then cropped to
737 /// fit within the other bound.
738 pub fn resize_to_fill(
739 &self,
740 nwidth: u32,
741 nheight: u32,
742 filter: imageops::FilterType,
743 ) -> DynamicImage {
744 let (width2, height2) =
745 resize_dimensions(self.width(), self.height(), nwidth, nheight, true);
746
747 let mut intermediate = self.resize_exact(width2, height2, filter);
748 let (iwidth, iheight) = intermediate.dimensions();
749 let ratio = u64::from(iwidth) * u64::from(nheight);
750 let nratio = u64::from(nwidth) * u64::from(iheight);
751
752 if nratio > ratio {
753 intermediate.crop(0, (iheight - nheight) / 2, nwidth, nheight)
754 } else {
755 intermediate.crop((iwidth - nwidth) / 2, 0, nwidth, nheight)
756 }
757 }
758
759 /// Performs a Gaussian blur on this image.
760 /// `sigma` is a measure of how much to blur by.
761 pub fn blur(&self, sigma: f32) -> DynamicImage {
762 dynamic_map!(*self, ref p => imageops::blur(p, sigma))
763 }
764
765 /// Performs an unsharpen mask on this image.
766 /// `sigma` is the amount to blur the image by.
767 /// `threshold` is a control of how much to sharpen.
768 ///
769 /// See <https://en.wikipedia.org/wiki/Unsharp_masking#Digital_unsharp_masking>
770 pub fn unsharpen(&self, sigma: f32, threshold: i32) -> DynamicImage {
771 dynamic_map!(*self, ref p => imageops::unsharpen(p, sigma, threshold))
772 }
773
774 /// Filters this image with the specified 3x3 kernel.
775 pub fn filter3x3(&self, kernel: &[f32]) -> DynamicImage {
776 if kernel.len() != 9 {
777 panic!("filter must be 3 x 3")
778 }
779
780 dynamic_map!(*self, ref p => imageops::filter3x3(p, kernel))
781 }
782
783 /// Adjust the contrast of this image.
784 /// `contrast` is the amount to adjust the contrast by.
785 /// Negative values decrease the contrast and positive values increase the contrast.
786 pub fn adjust_contrast(&self, c: f32) -> DynamicImage {
787 dynamic_map!(*self, ref p => imageops::contrast(p, c))
788 }
789
790 /// Brighten the pixels of this image.
791 /// `value` is the amount to brighten each pixel by.
792 /// Negative values decrease the brightness and positive values increase it.
793 pub fn brighten(&self, value: i32) -> DynamicImage {
794 dynamic_map!(*self, ref p => imageops::brighten(p, value))
795 }
796
797 /// Hue rotate the supplied image.
798 /// `value` is the degrees to rotate each pixel by.
799 /// 0 and 360 do nothing, the rest rotates by the given degree value.
800 /// just like the css webkit filter hue-rotate(180)
801 pub fn huerotate(&self, value: i32) -> DynamicImage {
802 dynamic_map!(*self, ref p => imageops::huerotate(p, value))
803 }
804
805 /// Flip this image vertically
806 pub fn flipv(&self) -> DynamicImage {
807 dynamic_map!(*self, ref p => imageops::flip_vertical(p))
808 }
809
810 /// Flip this image horizontally
811 pub fn fliph(&self) -> DynamicImage {
812 dynamic_map!(*self, ref p => imageops::flip_horizontal(p))
813 }
814
815 /// Rotate this image 90 degrees clockwise.
816 pub fn rotate90(&self) -> DynamicImage {
817 dynamic_map!(*self, ref p => imageops::rotate90(p))
818 }
819
820 /// Rotate this image 180 degrees clockwise.
821 pub fn rotate180(&self) -> DynamicImage {
822 dynamic_map!(*self, ref p => imageops::rotate180(p))
823 }
824
825 /// Rotate this image 270 degrees clockwise.
826 pub fn rotate270(&self) -> DynamicImage {
827 dynamic_map!(*self, ref p => imageops::rotate270(p))
828 }
829
830 /// Encode this image and write it to ```w```.
831 ///
832 /// Assumes the writer is buffered. In most cases,
833 /// you should wrap your writer in a `BufWriter` for best performance.
834 pub fn write_to<W: Write + Seek, F: Into<ImageOutputFormat>>(
835 &self,
836 w: &mut W,
837 format: F,
838 ) -> ImageResult<()> {
839 let bytes = self.inner_bytes();
840 let (width, height) = self.dimensions();
841 let color = self.color();
842 let format = format.into();
843
844 // TODO do not repeat this match statement across the crate
845
846 #[allow(deprecated)]
847 match format {
848 #[cfg(feature = "png")]
849 image::ImageOutputFormat::Png => {
850 let p = png::PngEncoder::new(w);
851 p.write_image(bytes, width, height, color)?;
852 Ok(())
853 }
854
855 #[cfg(feature = "pnm")]
856 image::ImageOutputFormat::Pnm(subtype) => {
857 let p = pnm::PnmEncoder::new(w).with_subtype(subtype);
858 p.write_image(bytes, width, height, color)?;
859 Ok(())
860 }
861
862 #[cfg(feature = "gif")]
863 image::ImageOutputFormat::Gif => {
864 let mut g = gif::GifEncoder::new(w);
865 g.encode_frame(crate::animation::Frame::new(self.to_rgba8()))?;
866 Ok(())
867 }
868
869 format => write_buffer_with_format(w, bytes, width, height, color, format),
870 }
871 }
872
873 /// Encode this image with the provided encoder.
874 pub fn write_with_encoder(&self, encoder: impl ImageEncoder) -> ImageResult<()> {
875 dynamic_map!(self, ref p, p.write_with_encoder(encoder))
876 }
877
878 /// Saves the buffer to a file at the path specified.
879 ///
880 /// The image format is derived from the file extension.
881 pub fn save<Q>(&self, path: Q) -> ImageResult<()>
882 where
883 Q: AsRef<Path>,
884 {
885 dynamic_map!(*self, ref p, p.save(path))
886 }
887
888 /// Saves the buffer to a file at the specified path in
889 /// the specified format.
890 ///
891 /// See [`save_buffer_with_format`](fn.save_buffer_with_format.html) for
892 /// supported types.
893 pub fn save_with_format<Q>(&self, path: Q, format: ImageFormat) -> ImageResult<()>
894 where
895 Q: AsRef<Path>,
896 {
897 dynamic_map!(*self, ref p, p.save_with_format(path, format))
898 }
899}
900
901impl From<GrayImage> for DynamicImage {
902 fn from(image: GrayImage) -> Self {
903 DynamicImage::ImageLuma8(image)
904 }
905}
906
907impl From<GrayAlphaImage> for DynamicImage {
908 fn from(image: GrayAlphaImage) -> Self {
909 DynamicImage::ImageLumaA8(image)
910 }
911}
912
913impl From<RgbImage> for DynamicImage {
914 fn from(image: RgbImage) -> Self {
915 DynamicImage::ImageRgb8(image)
916 }
917}
918
919impl From<RgbaImage> for DynamicImage {
920 fn from(image: RgbaImage) -> Self {
921 DynamicImage::ImageRgba8(image)
922 }
923}
924
925impl From<Gray16Image> for DynamicImage {
926 fn from(image: Gray16Image) -> Self {
927 DynamicImage::ImageLuma16(image)
928 }
929}
930
931impl From<GrayAlpha16Image> for DynamicImage {
932 fn from(image: GrayAlpha16Image) -> Self {
933 DynamicImage::ImageLumaA16(image)
934 }
935}
936
937impl From<Rgb16Image> for DynamicImage {
938 fn from(image: Rgb16Image) -> Self {
939 DynamicImage::ImageRgb16(image)
940 }
941}
942
943impl From<Rgba16Image> for DynamicImage {
944 fn from(image: Rgba16Image) -> Self {
945 DynamicImage::ImageRgba16(image)
946 }
947}
948
949impl From<Rgb32FImage> for DynamicImage {
950 fn from(image: Rgb32FImage) -> Self {
951 DynamicImage::ImageRgb32F(image)
952 }
953}
954
955impl From<Rgba32FImage> for DynamicImage {
956 fn from(image: Rgba32FImage) -> Self {
957 DynamicImage::ImageRgba32F(image)
958 }
959}
960
961impl From<ImageBuffer<Luma<f32>, Vec<f32>>> for DynamicImage {
962 fn from(image: ImageBuffer<Luma<f32>, Vec<f32>>) -> Self {
963 DynamicImage::ImageRgb32F(image.convert())
964 }
965}
966
967impl From<ImageBuffer<LumaA<f32>, Vec<f32>>> for DynamicImage {
968 fn from(image: ImageBuffer<LumaA<f32>, Vec<f32>>) -> Self {
969 DynamicImage::ImageRgba32F(image.convert())
970 }
971}
972
973#[allow(deprecated)]
974impl GenericImageView for DynamicImage {
975 type Pixel = color::Rgba<u8>; // TODO use f32 as default for best precision and unbounded color?
976
977 fn dimensions(&self) -> (u32, u32) {
978 dynamic_map!(*self, ref p, p.dimensions())
979 }
980
981 fn bounds(&self) -> (u32, u32, u32, u32) {
982 dynamic_map!(*self, ref p, p.bounds())
983 }
984
985 fn get_pixel(&self, x: u32, y: u32) -> color::Rgba<u8> {
986 dynamic_map!(*self, ref p, p.get_pixel(x, y).to_rgba().into_color())
987 }
988}
989
990#[allow(deprecated)]
991impl GenericImage for DynamicImage {
992 fn put_pixel(&mut self, x: u32, y: u32, pixel: color::Rgba<u8>) {
993 match *self {
994 DynamicImage::ImageLuma8(ref mut p) => p.put_pixel(x, y, pixel.to_luma()),
995 DynamicImage::ImageLumaA8(ref mut p) => p.put_pixel(x, y, pixel.to_luma_alpha()),
996 DynamicImage::ImageRgb8(ref mut p) => p.put_pixel(x, y, pixel.to_rgb()),
997 DynamicImage::ImageRgba8(ref mut p) => p.put_pixel(x, y, pixel),
998 DynamicImage::ImageLuma16(ref mut p) => p.put_pixel(x, y, pixel.to_luma().into_color()),
999 DynamicImage::ImageLumaA16(ref mut p) => {
1000 p.put_pixel(x, y, pixel.to_luma_alpha().into_color())
1001 }
1002 DynamicImage::ImageRgb16(ref mut p) => p.put_pixel(x, y, pixel.to_rgb().into_color()),
1003 DynamicImage::ImageRgba16(ref mut p) => p.put_pixel(x, y, pixel.into_color()),
1004 DynamicImage::ImageRgb32F(ref mut p) => p.put_pixel(x, y, pixel.to_rgb().into_color()),
1005 DynamicImage::ImageRgba32F(ref mut p) => p.put_pixel(x, y, pixel.into_color()),
1006 }
1007 }
1008
1009 fn blend_pixel(&mut self, x: u32, y: u32, pixel: color::Rgba<u8>) {
1010 match *self {
1011 DynamicImage::ImageLuma8(ref mut p) => p.blend_pixel(x, y, pixel.to_luma()),
1012 DynamicImage::ImageLumaA8(ref mut p) => p.blend_pixel(x, y, pixel.to_luma_alpha()),
1013 DynamicImage::ImageRgb8(ref mut p) => p.blend_pixel(x, y, pixel.to_rgb()),
1014 DynamicImage::ImageRgba8(ref mut p) => p.blend_pixel(x, y, pixel),
1015 DynamicImage::ImageLuma16(ref mut p) => {
1016 p.blend_pixel(x, y, pixel.to_luma().into_color())
1017 }
1018 DynamicImage::ImageLumaA16(ref mut p) => {
1019 p.blend_pixel(x, y, pixel.to_luma_alpha().into_color())
1020 }
1021 DynamicImage::ImageRgb16(ref mut p) => p.blend_pixel(x, y, pixel.to_rgb().into_color()),
1022 DynamicImage::ImageRgba16(ref mut p) => p.blend_pixel(x, y, pixel.into_color()),
1023 DynamicImage::ImageRgb32F(ref mut p) => {
1024 p.blend_pixel(x, y, pixel.to_rgb().into_color())
1025 }
1026 DynamicImage::ImageRgba32F(ref mut p) => p.blend_pixel(x, y, pixel.into_color()),
1027 }
1028 }
1029
1030 /// Do not use is function: It is unimplemented!
1031 fn get_pixel_mut(&mut self, _: u32, _: u32) -> &mut color::Rgba<u8> {
1032 unimplemented!()
1033 }
1034}
1035
1036impl Default for DynamicImage {
1037 fn default() -> Self {
1038 Self::ImageRgba8(Default::default())
1039 }
1040}
1041
1042/// Decodes an image and stores it into a dynamic image
1043fn decoder_to_image<'a, I: ImageDecoder<'a>>(decoder: I) -> ImageResult<DynamicImage> {
1044 let (w, h) = decoder.dimensions();
1045 let color_type = decoder.color_type();
1046
1047 let image = match color_type {
1048 color::ColorType::Rgb8 => {
1049 let buf = image::decoder_to_vec(decoder)?;
1050 ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageRgb8)
1051 }
1052
1053 color::ColorType::Rgba8 => {
1054 let buf = image::decoder_to_vec(decoder)?;
1055 ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageRgba8)
1056 }
1057
1058 color::ColorType::L8 => {
1059 let buf = image::decoder_to_vec(decoder)?;
1060 ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageLuma8)
1061 }
1062
1063 color::ColorType::La8 => {
1064 let buf = image::decoder_to_vec(decoder)?;
1065 ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageLumaA8)
1066 }
1067
1068 color::ColorType::Rgb16 => {
1069 let buf = image::decoder_to_vec(decoder)?;
1070 ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageRgb16)
1071 }
1072
1073 color::ColorType::Rgba16 => {
1074 let buf = image::decoder_to_vec(decoder)?;
1075 ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageRgba16)
1076 }
1077
1078 color::ColorType::Rgb32F => {
1079 let buf = image::decoder_to_vec(decoder)?;
1080 ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageRgb32F)
1081 }
1082
1083 color::ColorType::Rgba32F => {
1084 let buf = image::decoder_to_vec(decoder)?;
1085 ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageRgba32F)
1086 }
1087
1088 color::ColorType::L16 => {
1089 let buf = image::decoder_to_vec(decoder)?;
1090 ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageLuma16)
1091 }
1092
1093 color::ColorType::La16 => {
1094 let buf = image::decoder_to_vec(decoder)?;
1095 ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageLumaA16)
1096 }
1097 };
1098
1099 match image {
1100 Some(image) => Ok(image),
1101 None => Err(ImageError::Parameter(ParameterError::from_kind(
1102 ParameterErrorKind::DimensionMismatch,
1103 ))),
1104 }
1105}
1106
1107/// Open the image located at the path specified.
1108/// The image's format is determined from the path's file extension.
1109///
1110/// Try [`io::Reader`] for more advanced uses, including guessing the format based on the file's
1111/// content before its path.
1112///
1113/// [`io::Reader`]: io/struct.Reader.html
1114pub fn open<P>(path: P) -> ImageResult<DynamicImage>
1115where
1116 P: AsRef<Path>,
1117{
1118 // thin wrapper function to strip generics before calling open_impl
1119 free_functions::open_impl(path.as_ref())
1120}
1121
1122/// Read a tuple containing the (width, height) of the image located at the specified path.
1123/// This is faster than fully loading the image and then getting its dimensions.
1124///
1125/// Try [`io::Reader`] for more advanced uses, including guessing the format based on the file's
1126/// content before its path or manually supplying the format.
1127///
1128/// [`io::Reader`]: io/struct.Reader.html
1129pub fn image_dimensions<P>(path: P) -> ImageResult<(u32, u32)>
1130where
1131 P: AsRef<Path>,
1132{
1133 // thin wrapper function to strip generics before calling open_impl
1134 free_functions::image_dimensions_impl(path.as_ref())
1135}
1136
1137/// Saves the supplied buffer to a file at the path specified.
1138///
1139/// The image format is derived from the file extension. The buffer is assumed to have
1140/// the correct format according to the specified color type.
1141///
1142/// This will lead to corrupted files if the buffer contains malformed data. Currently only
1143/// jpeg, png, ico, pnm, bmp, exr and tiff files are supported.
1144pub fn save_buffer<P>(
1145 path: P,
1146 buf: &[u8],
1147 width: u32,
1148 height: u32,
1149 color: color::ColorType,
1150) -> ImageResult<()>
1151where
1152 P: AsRef<Path>,
1153{
1154 // thin wrapper function to strip generics before calling save_buffer_impl
1155 free_functions::save_buffer_impl(path.as_ref(), buf, width, height, color)
1156}
1157
1158/// Saves the supplied buffer to a file at the path specified
1159/// in the specified format.
1160///
1161/// The buffer is assumed to have the correct format according
1162/// to the specified color type.
1163/// This will lead to corrupted files if the buffer contains
1164/// malformed data. Currently only jpeg, png, ico, bmp, exr and
1165/// tiff files are supported.
1166pub fn save_buffer_with_format<P>(
1167 path: P,
1168 buf: &[u8],
1169 width: u32,
1170 height: u32,
1171 color: color::ColorType,
1172 format: ImageFormat,
1173) -> ImageResult<()>
1174where
1175 P: AsRef<Path>,
1176{
1177 // thin wrapper function to strip generics
1178 free_functions::save_buffer_with_format_impl(path.as_ref(), buf, width, height, color, format)
1179}
1180
1181/// Writes the supplied buffer to a writer in the specified format.
1182///
1183/// The buffer is assumed to have the correct format according
1184/// to the specified color type.
1185/// This will lead to corrupted writers if the buffer contains
1186/// malformed data.
1187///
1188/// See [`ImageOutputFormat`](enum.ImageOutputFormat.html) for
1189/// supported types.
1190///
1191/// Assumes the writer is buffered. In most cases,
1192/// you should wrap your writer in a `BufWriter` for best performance.
1193pub fn write_buffer_with_format<W, F>(
1194 buffered_writer: &mut W,
1195 buf: &[u8],
1196 width: u32,
1197 height: u32,
1198 color: color::ColorType,
1199 format: F,
1200) -> ImageResult<()>
1201where
1202 W: Write + Seek,
1203 F: Into<ImageOutputFormat>,
1204{
1205 // thin wrapper function to strip generics
1206 free_functions::write_buffer_impl(buffered_write:buffered_writer, buf, width, height, color, format:format.into())
1207}
1208
1209/// Create a new image from a byte slice
1210///
1211/// Makes an educated guess about the image format.
1212/// TGA is not supported by this function.
1213///
1214/// Try [`io::Reader`] for more advanced uses.
1215///
1216/// [`io::Reader`]: io/struct.Reader.html
1217pub fn load_from_memory(buffer: &[u8]) -> ImageResult<DynamicImage> {
1218 let format: ImageFormat = free_functions::guess_format(buffer)?;
1219 load_from_memory_with_format(buf:buffer, format)
1220}
1221
1222/// Create a new image from a byte slice
1223///
1224/// This is just a simple wrapper that constructs an `std::io::Cursor` around the buffer and then
1225/// calls `load` with that reader.
1226///
1227/// Try [`io::Reader`] for more advanced uses.
1228///
1229/// [`load`]: fn.load.html
1230/// [`io::Reader`]: io/struct.Reader.html
1231#[inline(always)]
1232pub fn load_from_memory_with_format(buf: &[u8], format: ImageFormat) -> ImageResult<DynamicImage> {
1233 let b: Cursor<&[u8]> = io::Cursor::new(inner:buf);
1234 free_functions::load(r:b, format)
1235}
1236
1237#[cfg(test)]
1238mod bench {
1239 #[bench]
1240 #[cfg(feature = "benchmarks")]
1241 fn bench_conversion(b: &mut test::Bencher) {
1242 let a = super::DynamicImage::ImageRgb8(crate::ImageBuffer::new(1000, 1000));
1243 b.iter(|| a.to_luma8());
1244 b.bytes = 1000 * 1000 * 3
1245 }
1246}
1247
1248#[cfg(test)]
1249mod test {
1250 use crate::color::ColorType;
1251
1252 #[test]
1253 fn test_empty_file() {
1254 assert!(super::load_from_memory(b"").is_err());
1255 }
1256
1257 #[cfg(feature = "jpeg")]
1258 #[test]
1259 fn image_dimensions() {
1260 let im_path = "./tests/images/jpg/progressive/cat.jpg";
1261 let dims = super::image_dimensions(im_path).unwrap();
1262 assert_eq!(dims, (320, 240));
1263 }
1264
1265 #[cfg(feature = "png")]
1266 #[test]
1267 fn open_16bpc_png() {
1268 let im_path = "./tests/images/png/16bpc/basn6a16.png";
1269 let image = super::open(im_path).unwrap();
1270 assert_eq!(image.color(), super::color::ColorType::Rgba16);
1271 }
1272
1273 fn test_grayscale(mut img: super::DynamicImage, alpha_discarded: bool) {
1274 use crate::image::{GenericImage, GenericImageView};
1275 img.put_pixel(0, 0, crate::color::Rgba([255, 0, 0, 100]));
1276 let expected_alpha = if alpha_discarded { 255 } else { 100 };
1277 assert_eq!(
1278 img.grayscale().get_pixel(0, 0),
1279 crate::color::Rgba([54, 54, 54, expected_alpha])
1280 );
1281 }
1282
1283 fn test_grayscale_alpha_discarded(img: super::DynamicImage) {
1284 test_grayscale(img, true);
1285 }
1286
1287 fn test_grayscale_alpha_preserved(img: super::DynamicImage) {
1288 test_grayscale(img, false);
1289 }
1290
1291 #[test]
1292 fn test_grayscale_luma8() {
1293 test_grayscale_alpha_discarded(super::DynamicImage::new_luma8(1, 1));
1294 test_grayscale_alpha_discarded(super::DynamicImage::new(1, 1, ColorType::L8));
1295 }
1296
1297 #[test]
1298 fn test_grayscale_luma_a8() {
1299 test_grayscale_alpha_preserved(super::DynamicImage::new_luma_a8(1, 1));
1300 test_grayscale_alpha_preserved(super::DynamicImage::new(1, 1, ColorType::La8));
1301 }
1302
1303 #[test]
1304 fn test_grayscale_rgb8() {
1305 test_grayscale_alpha_discarded(super::DynamicImage::new_rgb8(1, 1));
1306 test_grayscale_alpha_discarded(super::DynamicImage::new(1, 1, ColorType::Rgb8));
1307 }
1308
1309 #[test]
1310 fn test_grayscale_rgba8() {
1311 test_grayscale_alpha_preserved(super::DynamicImage::new_rgba8(1, 1));
1312 test_grayscale_alpha_preserved(super::DynamicImage::new(1, 1, ColorType::Rgba8));
1313 }
1314
1315 #[test]
1316 fn test_grayscale_luma16() {
1317 test_grayscale_alpha_discarded(super::DynamicImage::new_luma16(1, 1));
1318 test_grayscale_alpha_discarded(super::DynamicImage::new(1, 1, ColorType::L16));
1319 }
1320
1321 #[test]
1322 fn test_grayscale_luma_a16() {
1323 test_grayscale_alpha_preserved(super::DynamicImage::new_luma_a16(1, 1));
1324 test_grayscale_alpha_preserved(super::DynamicImage::new(1, 1, ColorType::La16));
1325 }
1326
1327 #[test]
1328 fn test_grayscale_rgb16() {
1329 test_grayscale_alpha_discarded(super::DynamicImage::new_rgb16(1, 1));
1330 test_grayscale_alpha_discarded(super::DynamicImage::new(1, 1, ColorType::Rgb16));
1331 }
1332
1333 #[test]
1334 fn test_grayscale_rgba16() {
1335 test_grayscale_alpha_preserved(super::DynamicImage::new_rgba16(1, 1));
1336 test_grayscale_alpha_preserved(super::DynamicImage::new(1, 1, ColorType::Rgba16));
1337 }
1338
1339 #[test]
1340 fn test_grayscale_rgb32f() {
1341 test_grayscale_alpha_discarded(super::DynamicImage::new_rgb32f(1, 1));
1342 test_grayscale_alpha_discarded(super::DynamicImage::new(1, 1, ColorType::Rgb32F));
1343 }
1344
1345 #[test]
1346 fn test_grayscale_rgba32f() {
1347 test_grayscale_alpha_preserved(super::DynamicImage::new_rgba32f(1, 1));
1348 test_grayscale_alpha_preserved(super::DynamicImage::new(1, 1, ColorType::Rgba32F));
1349 }
1350
1351 #[test]
1352 fn test_dynamic_image_default_implementation() {
1353 // Test that structs wrapping a DynamicImage are able to auto-derive the Default trait
1354 // ensures that DynamicImage implements Default (if it didn't, this would cause a compile error).
1355 #[derive(Default)]
1356 struct Foo {
1357 _image: super::DynamicImage,
1358 }
1359 }
1360
1361 #[test]
1362 fn test_to_vecu8() {
1363 let _ = super::DynamicImage::new_luma8(1, 1).into_bytes();
1364 let _ = super::DynamicImage::new_luma16(1, 1).into_bytes();
1365 }
1366
1367 #[test]
1368 fn issue_1705_can_turn_16bit_image_into_bytes() {
1369 let pixels = vec![65535u16; 64 * 64];
1370 let img = super::ImageBuffer::from_vec(64, 64, pixels).unwrap();
1371
1372 let img = super::DynamicImage::ImageLuma16(img);
1373 assert!(img.as_luma16().is_some());
1374
1375 let bytes: Vec<u8> = img.into_bytes();
1376 assert_eq!(bytes, vec![0xFF; 64 * 64 * 2]);
1377 }
1378}
1379