image/
dynimage.rs

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