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 32bit 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}
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy