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#[derive(Debug, PartialEq)]
50#[non_exhaustive]
51pub enum DynamicImage {
52    ImageLuma8(GrayImage),
54
55    ImageLumaA8(GrayAlphaImage),
57
58    ImageRgb8(RgbImage),
60
61    ImageRgba8(RgbaImage),
63
64    ImageLuma16(Gray16Image),
66
67    ImageLumaA16(GrayAlpha16Image),
69
70    ImageRgb16(Rgb16Image),
72
73    ImageRgba16(Rgba16Image),
75
76    ImageRgb32F(Rgb32FImage),
78
79    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    #[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    #[must_use]
160    pub fn new_luma8(w: u32, h: u32) -> DynamicImage {
161        DynamicImage::ImageLuma8(ImageBuffer::new(w, h))
162    }
163
164    #[must_use]
167    pub fn new_luma_a8(w: u32, h: u32) -> DynamicImage {
168        DynamicImage::ImageLumaA8(ImageBuffer::new(w, h))
169    }
170
171    #[must_use]
173    pub fn new_rgb8(w: u32, h: u32) -> DynamicImage {
174        DynamicImage::ImageRgb8(ImageBuffer::new(w, h))
175    }
176
177    #[must_use]
179    pub fn new_rgba8(w: u32, h: u32) -> DynamicImage {
180        DynamicImage::ImageRgba8(ImageBuffer::new(w, h))
181    }
182
183    #[must_use]
185    pub fn new_luma16(w: u32, h: u32) -> DynamicImage {
186        DynamicImage::ImageLuma16(ImageBuffer::new(w, h))
187    }
188
189    #[must_use]
192    pub fn new_luma_a16(w: u32, h: u32) -> DynamicImage {
193        DynamicImage::ImageLumaA16(ImageBuffer::new(w, h))
194    }
195
196    #[must_use]
198    pub fn new_rgb16(w: u32, h: u32) -> DynamicImage {
199        DynamicImage::ImageRgb16(ImageBuffer::new(w, h))
200    }
201
202    #[must_use]
204    pub fn new_rgba16(w: u32, h: u32) -> DynamicImage {
205        DynamicImage::ImageRgba16(ImageBuffer::new(w, h))
206    }
207
208    #[must_use]
210    pub fn new_rgb32f(w: u32, h: u32) -> DynamicImage {
211        DynamicImage::ImageRgb32F(ImageBuffer::new(w, h))
212    }
213
214    #[must_use]
216    pub fn new_rgba32f(w: u32, h: u32) -> DynamicImage {
217        DynamicImage::ImageRgba32F(ImageBuffer::new(w, h))
218    }
219
220    pub fn from_decoder(decoder: impl ImageDecoder) -> ImageResult<Self> {
222        decoder_to_image(decoder)
223    }
224
225    #[must_use]
227    pub fn to_rgb8(&self) -> RgbImage {
228        dynamic_map!(*self, ref p, p.convert())
229    }
230
231    #[must_use]
233    pub fn to_rgb16(&self) -> Rgb16Image {
234        dynamic_map!(*self, ref p, p.convert())
235    }
236
237    #[must_use]
239    pub fn to_rgb32f(&self) -> Rgb32FImage {
240        dynamic_map!(*self, ref p, p.convert())
241    }
242
243    #[must_use]
245    pub fn to_rgba8(&self) -> RgbaImage {
246        dynamic_map!(*self, ref p, p.convert())
247    }
248
249    #[must_use]
251    pub fn to_rgba16(&self) -> Rgba16Image {
252        dynamic_map!(*self, ref p, p.convert())
253    }
254
255    #[must_use]
257    pub fn to_rgba32f(&self) -> Rgba32FImage {
258        dynamic_map!(*self, ref p, p.convert())
259    }
260
261    #[must_use]
263    pub fn to_luma8(&self) -> GrayImage {
264        dynamic_map!(*self, ref p, p.convert())
265    }
266
267    #[must_use]
269    pub fn to_luma16(&self) -> Gray16Image {
270        dynamic_map!(*self, ref p, p.convert())
271    }
272
273    #[must_use]
275    pub fn to_luma32f(&self) -> ImageBuffer<Luma<f32>, Vec<f32>> {
276        dynamic_map!(*self, ref p, p.convert())
277    }
278
279    #[must_use]
281    pub fn to_luma_alpha8(&self) -> GrayAlphaImage {
282        dynamic_map!(*self, ref p, p.convert())
283    }
284
285    #[must_use]
287    pub fn to_luma_alpha16(&self) -> GrayAlpha16Image {
288        dynamic_map!(*self, ref p, p.convert())
289    }
290
291    #[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    #[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    #[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    #[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    #[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    #[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    #[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    #[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    #[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    #[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    #[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    #[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    #[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    #[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    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    #[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    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    #[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    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    #[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    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    #[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    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    #[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    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    #[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    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    #[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    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    #[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    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    #[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    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    #[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    #[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    #[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    #[must_use]
638    pub fn as_bytes(&self) -> &[u8] {
639        dynamic_map!(
641            *self,
642            ref image_buffer,
643            bytemuck::cast_slice(image_buffer.as_raw().as_ref())
644        )
645    }
646
647    fn inner_bytes(&self) -> &[u8] {
649        dynamic_map!(
651            *self,
652            ref image_buffer,
653            bytemuck::cast_slice(image_buffer.inner_pixels())
654        )
655    }
656
657    #[must_use]
661    pub fn into_bytes(self) -> Vec<u8> {
662        dynamic_map!(self, image_buffer, {
664            match bytemuck::allocation::try_cast_vec(image_buffer.into_raw()) {
665                Ok(vec) => vec,
666                Err((_, vec)) => {
667                    bytemuck::cast_slice(&vec).to_owned()
673                }
674            }
675        })
676    }
677
678    #[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    #[must_use]
697    pub fn width(&self) -> u32 {
698        dynamic_map!(*self, ref p, { p.width() })
699    }
700
701    #[must_use]
703    pub fn height(&self) -> u32 {
704        dynamic_map!(*self, ref p, { p.height() })
705    }
706
707    #[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    pub fn invert(&mut self) {
741        dynamic_map!(*self, ref mut p, imageops::invert(p));
742    }
743
744    #[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    #[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    #[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    #[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    #[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    #[must_use]
831    pub fn blur(&self, sigma: f32) -> DynamicImage {
832        dynamic_map!(*self, ref p => imageops::blur(p, sigma))
833    }
834
835    #[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    #[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    #[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    #[must_use]
865    pub fn adjust_contrast(&self, c: f32) -> DynamicImage {
866        dynamic_map!(*self, ref p => imageops::contrast(p, c))
867    }
868
869    #[must_use]
873    pub fn brighten(&self, value: i32) -> DynamicImage {
874        dynamic_map!(*self, ref p => imageops::brighten(p, value))
875    }
876
877    #[must_use]
882    pub fn huerotate(&self, value: i32) -> DynamicImage {
883        dynamic_map!(*self, ref p => imageops::huerotate(p, value))
884    }
885
886    #[must_use]
890    pub fn flipv(&self) -> DynamicImage {
891        dynamic_map!(*self, ref p => imageops::flip_vertical(p))
892    }
893
894    fn flipv_in_place(&mut self) {
896        dynamic_map!(*self, ref mut p, imageops::flip_vertical_in_place(p))
897    }
898
899    #[must_use]
903    pub fn fliph(&self) -> DynamicImage {
904        dynamic_map!(*self, ref p => imageops::flip_horizontal(p))
905    }
906
907    fn fliph_in_place(&mut self) {
909        dynamic_map!(*self, ref mut p, imageops::flip_horizontal_in_place(p))
910    }
911
912    #[must_use]
914    pub fn rotate90(&self) -> DynamicImage {
915        dynamic_map!(*self, ref p => imageops::rotate90(p))
916    }
917
918    #[must_use]
922    pub fn rotate180(&self) -> DynamicImage {
923        dynamic_map!(*self, ref p => imageops::rotate180(p))
924    }
925
926    fn rotate180_in_place(&mut self) {
928        dynamic_map!(*self, ref mut p, imageops::rotate180_in_place(p))
929    }
930
931    #[must_use]
933    pub fn rotate270(&self) -> DynamicImage {
934        dynamic_map!(*self, ref p => imageops::rotate270(p))
935    }
936
937    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    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        #[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    pub fn write_with_encoder(&self, encoder: impl ImageEncoder) -> ImageResult<()> {
1014        dynamic_map!(self, ref p, p.write_with_encoder(encoder))
1015    }
1016
1017    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    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>; 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    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
1177fn 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
1242pub fn open<P>(path: P) -> ImageResult<DynamicImage>
1248where
1249    P: AsRef<Path>,
1250{
1251    ImageReader::open(path)?.decode()
1252}
1253
1254pub fn image_dimensions<P>(path: P) -> ImageResult<(u32, u32)>
1260where
1261    P: AsRef<Path>,
1262{
1263    ImageReader::open(path)?.into_dimensions()
1264}
1265
1266pub 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    free_functions::save_buffer_impl(path.as_ref(), buf, width, height, color.into())
1282}
1283
1284pub 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    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
1311pub 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    free_functions::write_buffer_impl(buffered_writer, buf, width, height, color.into(), format)
1328}
1329
1330pub 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#[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        #[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}