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: &mut ImageBuffer, Vec<…>>), Self::ImageLuma8(p2: &ImageBuffer, Vec<…>>)) => p1.clone_from(source:p2),
124 (Self::ImageLumaA8(p1: &mut ImageBuffer, Vec<…>>), Self::ImageLumaA8(p2: &ImageBuffer, Vec<…>>)) => p1.clone_from(source:p2),
125 (Self::ImageRgb8(p1: &mut ImageBuffer, Vec<…>>), Self::ImageRgb8(p2: &ImageBuffer, Vec<…>>)) => p1.clone_from(source:p2),
126 (Self::ImageRgba8(p1: &mut ImageBuffer, Vec<…>>), Self::ImageRgba8(p2: &ImageBuffer, Vec<…>>)) => p1.clone_from(source:p2),
127 (Self::ImageLuma16(p1: &mut ImageBuffer, Vec<…>>), Self::ImageLuma16(p2: &ImageBuffer, Vec<…>>)) => p1.clone_from(source:p2),
128 (Self::ImageLumaA16(p1: &mut ImageBuffer, Vec<…>>), Self::ImageLumaA16(p2: &ImageBuffer, Vec<…>>)) => p1.clone_from(source:p2),
129 (Self::ImageRgb16(p1: &mut ImageBuffer, Vec<…>>), Self::ImageRgb16(p2: &ImageBuffer, Vec<…>>)) => p1.clone_from(source:p2),
130 (Self::ImageRgba16(p1: &mut ImageBuffer, Vec<…>>), Self::ImageRgba16(p2: &ImageBuffer, Vec<…>>)) => p1.clone_from(source:p2),
131 (Self::ImageRgb32F(p1: &mut ImageBuffer, Vec<…>>), Self::ImageRgb32F(p2: &ImageBuffer, Vec<…>>)) => p1.clone_from(source:p2),
132 (Self::ImageRgba32F(p1: &mut ImageBuffer, Vec<…>>), Self::ImageRgba32F(p2: &ImageBuffer, Vec<…>>)) => p1.clone_from(source:p2),
133 (this: &mut DynamicImage, source: &DynamicImage) => *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_write: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: ImageFormat = free_functions::guess_format(buffer)?;
1338 load_from_memory_with_format(buf: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: Cursor<&[u8]> = io::Cursor::new(inner:buf);
1352 free_functions::load(r: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}
1498

Provided by KDAB

Privacy Policy