1 use num_iter;
2 use std::io;
3 use std::io::Write;
4 use std::path::Path;
5 use std::u32;
6 
7 #[cfg(feature = "bmp")]
8 use bmp;
9 #[cfg(feature = "gif_codec")]
10 use gif;
11 #[cfg(feature = "ico")]
12 use ico;
13 #[cfg(feature = "jpeg")]
14 use jpeg;
15 #[cfg(feature = "png_codec")]
16 use png;
17 #[cfg(feature = "pnm")]
18 use pnm;
19 
20 use buffer::{
21     BgrImage, BgraImage, ConvertBuffer, GrayAlphaImage, GrayImage, ImageBuffer, Pixel, RgbImage,
22     RgbaImage,
23 };
24 use color;
25 use flat::FlatSamples;
26 use image;
27 use image::{
28     GenericImage, GenericImageView, ImageDecoder, ImageFormat, ImageOutputFormat, ImageResult,
29 };
30 use io::free_functions;
31 use imageops;
32 
33 /// A Dynamic Image
34 #[derive(Clone)]
35 pub enum DynamicImage {
36     /// Each pixel in this image is 8-bit Luma
37     ImageLuma8(GrayImage),
38 
39     /// Each pixel in this image is 8-bit Luma with alpha
40     ImageLumaA8(GrayAlphaImage),
41 
42     /// Each pixel in this image is 8-bit Rgb
43     ImageRgb8(RgbImage),
44 
45     /// Each pixel in this image is 8-bit Rgb with alpha
46     ImageRgba8(RgbaImage),
47 
48     /// Each pixel in this image is 8-bit Bgr
49     ImageBgr8(BgrImage),
50 
51     /// Each pixel in this image is 8-bit Bgr with alpha
52     ImageBgra8(BgraImage),
53 }
54 
55 macro_rules! dynamic_map(
56         ($dynimage: expr, ref $image: ident => $action: expr) => (
57                 match $dynimage {
58                         DynamicImage::ImageLuma8(ref $image) => DynamicImage::ImageLuma8($action),
59                         DynamicImage::ImageLumaA8(ref $image) => DynamicImage::ImageLumaA8($action),
60                         DynamicImage::ImageRgb8(ref $image) => DynamicImage::ImageRgb8($action),
61                         DynamicImage::ImageRgba8(ref $image) => DynamicImage::ImageRgba8($action),
62                         DynamicImage::ImageBgr8(ref $image) => DynamicImage::ImageBgr8($action),
63                         DynamicImage::ImageBgra8(ref $image) => DynamicImage::ImageBgra8($action),
64                 }
65         );
66 
67         ($dynimage: expr, ref mut $image: ident => $action: expr) => (
68                 match $dynimage {
69                         DynamicImage::ImageLuma8(ref mut $image) => DynamicImage::ImageLuma8($action),
70                         DynamicImage::ImageLumaA8(ref mut $image) => DynamicImage::ImageLumaA8($action),
71                         DynamicImage::ImageRgb8(ref mut $image) => DynamicImage::ImageRgb8($action),
72                         DynamicImage::ImageRgba8(ref mut $image) => DynamicImage::ImageRgba8($action),
73                         DynamicImage::ImageBgr8(ref mut $image) => DynamicImage::ImageBgr8($action),
74                         DynamicImage::ImageBgra8(ref mut $image) => DynamicImage::ImageBgra8($action),
75                 }
76         );
77 
78         ($dynimage: expr, ref $image: ident -> $action: expr) => (
79                 match $dynimage {
80                         DynamicImage::ImageLuma8(ref $image) => $action,
81                         DynamicImage::ImageLumaA8(ref $image) => $action,
82                         DynamicImage::ImageRgb8(ref $image) => $action,
83                         DynamicImage::ImageRgba8(ref $image) => $action,
84                         DynamicImage::ImageBgr8(ref $image) => $action,
85                         DynamicImage::ImageBgra8(ref $image) => $action,
86                 }
87         );
88 
89         ($dynimage: expr, ref mut $image: ident -> $action: expr) => (
90                 match $dynimage {
91                         DynamicImage::ImageLuma8(ref mut $image) => $action,
92                         DynamicImage::ImageLumaA8(ref mut $image) => $action,
93                         DynamicImage::ImageRgb8(ref mut $image) => $action,
94                         DynamicImage::ImageRgba8(ref mut $image) => $action,
95                         DynamicImage::ImageBgr8(ref mut $image) => $action,
96                         DynamicImage::ImageBgra8(ref mut $image) => $action,
97                 }
98         );
99 );
100 
101 impl DynamicImage {
102     /// Creates a dynamic image backed by a buffer of grey pixels.
new_luma8(w: u32, h: u32) -> DynamicImage103     pub fn new_luma8(w: u32, h: u32) -> DynamicImage {
104         DynamicImage::ImageLuma8(ImageBuffer::new(w, h))
105     }
106 
107     /// Creates a dynamic image backed by a buffer of grey
108     /// pixels with transparency.
new_luma_a8(w: u32, h: u32) -> DynamicImage109     pub fn new_luma_a8(w: u32, h: u32) -> DynamicImage {
110         DynamicImage::ImageLumaA8(ImageBuffer::new(w, h))
111     }
112 
113     /// Creates a dynamic image backed by a buffer of RGB pixels.
new_rgb8(w: u32, h: u32) -> DynamicImage114     pub fn new_rgb8(w: u32, h: u32) -> DynamicImage {
115         DynamicImage::ImageRgb8(ImageBuffer::new(w, h))
116     }
117 
118     /// Creates a dynamic image backed by a buffer of RGBA pixels.
new_rgba8(w: u32, h: u32) -> DynamicImage119     pub fn new_rgba8(w: u32, h: u32) -> DynamicImage {
120         DynamicImage::ImageRgba8(ImageBuffer::new(w, h))
121     }
122 
123     /// Creates a dynamic image backed by a buffer of BGRA pixels.
new_bgra8(w: u32, h: u32) -> DynamicImage124     pub fn new_bgra8(w: u32, h: u32) -> DynamicImage {
125         DynamicImage::ImageBgra8(ImageBuffer::new(w, h))
126     }
127 
128     /// Creates a dynamic image backed by a buffer of BGR pixels.
new_bgr8(w: u32, h: u32) -> DynamicImage129     pub fn new_bgr8(w: u32, h: u32) -> DynamicImage {
130         DynamicImage::ImageBgr8(ImageBuffer::new(w, h))
131     }
132 
133     /// Decodes an encoded image into a dynamic image.
from_decoder<'a>(decoder: impl ImageDecoder<'a>) -> ImageResult<Self>134     pub fn from_decoder<'a>(decoder: impl ImageDecoder<'a>)
135         -> ImageResult<Self>
136     {
137         decoder_to_image(decoder)
138     }
139 
140     /// Returns a copy of this image as an RGB image.
to_rgb(&self) -> RgbImage141     pub fn to_rgb(&self) -> RgbImage {
142         dynamic_map!(*self, ref p -> {
143             p.convert()
144         })
145     }
146 
147     /// Returns a copy of this image as an RGBA image.
to_rgba(&self) -> RgbaImage148     pub fn to_rgba(&self) -> RgbaImage {
149         dynamic_map!(*self, ref p -> {
150             p.convert()
151         })
152     }
153 
154     /// Returns a copy of this image as an BGR image.
to_bgr(&self) -> BgrImage155     pub fn to_bgr(&self) -> BgrImage {
156         dynamic_map!(*self, ref p -> {
157             p.convert()
158         })
159     }
160 
161     /// Returns a copy of this image as an BGRA image.
to_bgra(&self) -> BgraImage162     pub fn to_bgra(&self) -> BgraImage {
163         dynamic_map!(*self, ref p -> {
164             p.convert()
165         })
166     }
167 
168     /// Returns a copy of this image as a Luma image.
to_luma(&self) -> GrayImage169     pub fn to_luma(&self) -> GrayImage {
170         dynamic_map!(*self, ref p -> {
171             p.convert()
172         })
173     }
174 
175     /// Returns a copy of this image as a LumaA image.
to_luma_alpha(&self) -> GrayAlphaImage176     pub fn to_luma_alpha(&self) -> GrayAlphaImage {
177         dynamic_map!(*self, ref p -> {
178             p.convert()
179         })
180     }
181 
182     /// Return a cut out of this image delimited by the bounding rectangle.
crop(&mut self, x: u32, y: u32, width: u32, height: u32) -> DynamicImage183     pub fn crop(&mut self, x: u32, y: u32, width: u32, height: u32) -> DynamicImage {
184         dynamic_map!(*self, ref mut p => imageops::crop(p, x, y, width, height).to_image())
185     }
186 
187     /// Return a reference to an 8bit RGB image
as_rgb8(&self) -> Option<&RgbImage>188     pub fn as_rgb8(&self) -> Option<&RgbImage> {
189         match *self {
190             DynamicImage::ImageRgb8(ref p) => Some(p),
191             _ => None,
192         }
193     }
194 
195     /// Return a mutable reference to an 8bit RGB image
as_mut_rgb8(&mut self) -> Option<&mut RgbImage>196     pub fn as_mut_rgb8(&mut self) -> Option<&mut RgbImage> {
197         match *self {
198             DynamicImage::ImageRgb8(ref mut p) => Some(p),
199             _ => None,
200         }
201     }
202 
203     /// Return a reference to an 8bit BGR image
as_bgr8(&self) -> Option<&BgrImage>204     pub fn as_bgr8(&self) -> Option<&BgrImage> {
205         match *self {
206             DynamicImage::ImageBgr8(ref p) => Some(p),
207             _ => None,
208         }
209     }
210 
211     /// Return a mutable reference to an 8bit BGR image
as_mut_bgr8(&mut self) -> Option<&mut BgrImage>212     pub fn as_mut_bgr8(&mut self) -> Option<&mut BgrImage> {
213         match *self {
214             DynamicImage::ImageBgr8(ref mut p) => Some(p),
215             _ => None,
216         }
217     }
218 
219     /// Return a reference to an 8bit RGBA image
as_rgba8(&self) -> Option<&RgbaImage>220     pub fn as_rgba8(&self) -> Option<&RgbaImage> {
221         match *self {
222             DynamicImage::ImageRgba8(ref p) => Some(p),
223             _ => None,
224         }
225     }
226 
227     /// Return a mutable reference to an 8bit RGBA image
as_mut_rgba8(&mut self) -> Option<&mut RgbaImage>228     pub fn as_mut_rgba8(&mut self) -> Option<&mut RgbaImage> {
229         match *self {
230             DynamicImage::ImageRgba8(ref mut p) => Some(p),
231             _ => None,
232         }
233     }
234 
235     /// Return a reference to an 8bit BGRA image
as_bgra8(&self) -> Option<&BgraImage>236     pub fn as_bgra8(&self) -> Option<&BgraImage> {
237         match *self {
238             DynamicImage::ImageBgra8(ref p) => Some(p),
239             _ => None,
240         }
241     }
242 
243     /// Return a mutable reference to an 8bit RGBA image
as_mut_bgra8(&mut self) -> Option<&mut BgraImage>244     pub fn as_mut_bgra8(&mut self) -> Option<&mut BgraImage> {
245         match *self {
246             DynamicImage::ImageBgra8(ref mut p) => Some(p),
247             _ => None,
248         }
249     }
250 
251     /// Return a reference to an 8bit Grayscale image
as_luma8(&self) -> Option<&GrayImage>252     pub fn as_luma8(&self) -> Option<&GrayImage> {
253         match *self {
254             DynamicImage::ImageLuma8(ref p) => Some(p),
255             _ => None,
256         }
257     }
258 
259     /// Return a mutable reference to an 8bit Grayscale image
as_mut_luma8(&mut self) -> Option<&mut GrayImage>260     pub fn as_mut_luma8(&mut self) -> Option<&mut GrayImage> {
261         match *self {
262             DynamicImage::ImageLuma8(ref mut p) => Some(p),
263             _ => None,
264         }
265     }
266 
267     /// Return a reference to an 8bit Grayscale image with an alpha channel
as_luma_alpha8(&self) -> Option<&GrayAlphaImage>268     pub fn as_luma_alpha8(&self) -> Option<&GrayAlphaImage> {
269         match *self {
270             DynamicImage::ImageLumaA8(ref p) => Some(p),
271             _ => None,
272         }
273     }
274 
275     /// Return a mutable reference to an 8bit Grayscale image with an alpha channel
as_mut_luma_alpha8(&mut self) -> Option<&mut GrayAlphaImage>276     pub fn as_mut_luma_alpha8(&mut self) -> Option<&mut GrayAlphaImage> {
277         match *self {
278             DynamicImage::ImageLumaA8(ref mut p) => Some(p),
279             _ => None,
280         }
281     }
282 
283     /// Return this image's pixels as a byte vector.
raw_pixels(&self) -> Vec<u8>284     pub fn raw_pixels(&self) -> Vec<u8> {
285         image_to_bytes(self)
286     }
287 
288     /// Return a view on the raw sample buffer.
as_flat_samples(&self) -> FlatSamples<&[u8]>289     pub fn as_flat_samples(&self) -> FlatSamples<&[u8]> {
290         dynamic_map!(*self, ref p -> p.as_flat_samples())
291     }
292 
293     /// Return this image's color type.
color(&self) -> color::ColorType294     pub fn color(&self) -> color::ColorType {
295         match *self {
296             DynamicImage::ImageLuma8(_) => color::ColorType::Gray(8),
297             DynamicImage::ImageLumaA8(_) => color::ColorType::GrayA(8),
298             DynamicImage::ImageRgb8(_) => color::ColorType::RGB(8),
299             DynamicImage::ImageRgba8(_) => color::ColorType::RGBA(8),
300             DynamicImage::ImageBgra8(_) => color::ColorType::BGRA(8),
301             DynamicImage::ImageBgr8(_) => color::ColorType::BGR(8),
302         }
303     }
304 
305     /// Return a grayscale version of this image.
grayscale(&self) -> DynamicImage306     pub fn grayscale(&self) -> DynamicImage {
307         match *self {
308             DynamicImage::ImageLuma8(ref p) => DynamicImage::ImageLuma8(p.clone()),
309             DynamicImage::ImageLumaA8(ref p) => DynamicImage::ImageLuma8(imageops::grayscale(p)),
310             DynamicImage::ImageRgb8(ref p) => DynamicImage::ImageLuma8(imageops::grayscale(p)),
311             DynamicImage::ImageRgba8(ref p) => DynamicImage::ImageLuma8(imageops::grayscale(p)),
312             DynamicImage::ImageBgr8(ref p) => DynamicImage::ImageLuma8(imageops::grayscale(p)),
313             DynamicImage::ImageBgra8(ref p) => DynamicImage::ImageLuma8(imageops::grayscale(p)),
314         }
315     }
316 
317     /// Invert the colors of this image.
318     /// This method operates inplace.
invert(&mut self)319     pub fn invert(&mut self) {
320         dynamic_map!(*self, ref mut p -> imageops::invert(p))
321     }
322 
323     /// Resize this image using the specified filter algorithm.
324     /// Returns a new image. The image's aspect ratio is preserved.
325     /// The image is scaled to the maximum possible size that fits
326     /// within the bounds specified by ```nwidth``` and ```nheight```.
resize(&self, nwidth: u32, nheight: u32, filter: imageops::FilterType) -> DynamicImage327     pub fn resize(&self, nwidth: u32, nheight: u32, filter: imageops::FilterType) -> DynamicImage {
328         let (width2, height2) =
329             resize_dimensions(self.width(), self.height(), nwidth, nheight, false);
330 
331         self.resize_exact(width2, height2, filter)
332     }
333 
334     /// Resize this image using the specified filter algorithm.
335     /// Returns a new image. Does not preserve aspect ratio.
336     /// ```nwidth``` and ```nheight``` are the new image's dimensions
resize_exact( &self, nwidth: u32, nheight: u32, filter: imageops::FilterType, ) -> DynamicImage337     pub fn resize_exact(
338         &self,
339         nwidth: u32,
340         nheight: u32,
341         filter: imageops::FilterType,
342     ) -> DynamicImage {
343         dynamic_map!(*self, ref p => imageops::resize(p, nwidth, nheight, filter))
344     }
345 
346     /// Scale this image down to fit within a specific size.
347     /// Returns a new image. The image's aspect ratio is preserved.
348     /// The image is scaled to the maximum possible size that fits
349     /// within the bounds specified by ```nwidth``` and ```nheight```.
350     ///
351     /// This method uses a fast integer algorithm where each source
352     /// pixel contributes to exactly one target pixel.
353     /// May give aliasing artifacts if new size is close to old size.
thumbnail(&self, nwidth: u32, nheight: u32) -> DynamicImage354     pub fn thumbnail(&self, nwidth: u32, nheight: u32) -> DynamicImage {
355         let (width2, height2) =
356             resize_dimensions(self.width(), self.height(), nwidth, nheight, false);
357         self.thumbnail_exact(width2, height2)
358     }
359 
360     /// Scale this image down to a specific size.
361     /// Returns a new image. Does not preserve aspect ratio.
362     /// ```nwidth``` and ```nheight``` are the new image's dimensions.
363     /// This method uses a fast integer algorithm where each source
364     /// pixel contributes to exactly one target pixel.
365     /// May give aliasing artifacts if new size is close to old size.
thumbnail_exact(&self, nwidth: u32, nheight: u32) -> DynamicImage366     pub fn thumbnail_exact(&self, nwidth: u32, nheight: u32) -> DynamicImage {
367         dynamic_map!(*self, ref p => imageops::thumbnail(p, nwidth, nheight))
368     }
369 
370     /// Resize this image using the specified filter algorithm.
371     /// Returns a new image. The image's aspect ratio is preserved.
372     /// The image is scaled to the maximum possible size that fits
373     /// within the larger (relative to aspect ratio) of the bounds
374     /// specified by ```nwidth``` and ```nheight```, then cropped to
375     /// fit within the other bound.
resize_to_fill( &self, nwidth: u32, nheight: u32, filter: imageops::FilterType, ) -> DynamicImage376     pub fn resize_to_fill(
377         &self,
378         nwidth: u32,
379         nheight: u32,
380         filter: imageops::FilterType,
381     ) -> DynamicImage {
382         let (width2, height2) =
383             resize_dimensions(self.width(), self.height(), nwidth, nheight, true);
384 
385         let mut intermediate = self.resize_exact(width2, height2, filter);
386         let (iwidth, iheight) = intermediate.dimensions();
387         let ratio = u64::from(iwidth) * u64::from(nheight);
388         let nratio = u64::from(nwidth) * u64::from(iheight);
389 
390         if nratio > ratio {
391             intermediate.crop(0, (iheight - nheight) / 2, nwidth, nheight)
392         } else {
393             intermediate.crop((iwidth - nwidth) / 2, 0, nwidth, nheight)
394         }
395     }
396 
397     /// Performs a Gaussian blur on this image.
398     /// ```sigma``` is a measure of how much to blur by.
blur(&self, sigma: f32) -> DynamicImage399     pub fn blur(&self, sigma: f32) -> DynamicImage {
400         dynamic_map!(*self, ref p => imageops::blur(p, sigma))
401     }
402 
403     /// Performs an unsharpen mask on this image.
404     /// ```sigma``` is the amount to blur the image by.
405     /// ```threshold``` is a control of how much to sharpen.
406     ///
407     /// See <https://en.wikipedia.org/wiki/Unsharp_masking#Digital_unsharp_masking>
unsharpen(&self, sigma: f32, threshold: i32) -> DynamicImage408     pub fn unsharpen(&self, sigma: f32, threshold: i32) -> DynamicImage {
409         dynamic_map!(*self, ref p => imageops::unsharpen(p, sigma, threshold))
410     }
411 
412     /// Filters this image with the specified 3x3 kernel.
filter3x3(&self, kernel: &[f32]) -> DynamicImage413     pub fn filter3x3(&self, kernel: &[f32]) -> DynamicImage {
414         if kernel.len() != 9 {
415             panic!("filter must be 3 x 3")
416         }
417 
418         dynamic_map!(*self, ref p => imageops::filter3x3(p, kernel))
419     }
420 
421     /// Adjust the contrast of this image.
422     /// ```contrast``` is the amount to adjust the contrast by.
423     /// Negative values decrease the contrast and positive values increase the contrast.
adjust_contrast(&self, c: f32) -> DynamicImage424     pub fn adjust_contrast(&self, c: f32) -> DynamicImage {
425         dynamic_map!(*self, ref p => imageops::contrast(p, c))
426     }
427 
428     /// Brighten the pixels of this image.
429     /// ```value``` is the amount to brighten each pixel by.
430     /// Negative values decrease the brightness and positive values increase it.
brighten(&self, value: i32) -> DynamicImage431     pub fn brighten(&self, value: i32) -> DynamicImage {
432         dynamic_map!(*self, ref p => imageops::brighten(p, value))
433     }
434 
435     /// Hue rotate the supplied image.
436     /// `value` is the degrees to rotate each pixel by.
437     /// 0 and 360 do nothing, the rest rotates by the given degree value.
438     /// just like the css webkit filter hue-rotate(180)
huerotate(&self, value: i32) -> DynamicImage439     pub fn huerotate(&self, value: i32) -> DynamicImage {
440         dynamic_map!(*self, ref p => imageops::huerotate(p, value))
441     }
442 
443     /// Flip this image vertically
flipv(&self) -> DynamicImage444     pub fn flipv(&self) -> DynamicImage {
445         dynamic_map!(*self, ref p => imageops::flip_vertical(p))
446     }
447 
448     /// Flip this image horizontally
fliph(&self) -> DynamicImage449     pub fn fliph(&self) -> DynamicImage {
450         dynamic_map!(*self, ref p => imageops::flip_horizontal(p))
451     }
452 
453     /// Rotate this image 90 degrees clockwise.
rotate90(&self) -> DynamicImage454     pub fn rotate90(&self) -> DynamicImage {
455         dynamic_map!(*self, ref p => imageops::rotate90(p))
456     }
457 
458     /// Rotate this image 180 degrees clockwise.
rotate180(&self) -> DynamicImage459     pub fn rotate180(&self) -> DynamicImage {
460         dynamic_map!(*self, ref p => imageops::rotate180(p))
461     }
462 
463     /// Rotate this image 270 degrees clockwise.
rotate270(&self) -> DynamicImage464     pub fn rotate270(&self) -> DynamicImage {
465         dynamic_map!(*self, ref p => imageops::rotate270(p))
466     }
467 
468     /// Encode this image and write it to ```w```
write_to<W: Write, F: Into<ImageOutputFormat>>( &self, w: &mut W, format: F, ) -> ImageResult<()>469     pub fn write_to<W: Write, F: Into<ImageOutputFormat>>(
470         &self,
471         w: &mut W,
472         format: F,
473     ) -> ImageResult<()> {
474         let mut bytes = self.raw_pixels();
475         let (width, height) = self.dimensions();
476         let mut color = self.color();
477         let format = format.into();
478 
479         #[allow(deprecated)]
480         match format {
481             #[cfg(feature = "png_codec")]
482             image::ImageOutputFormat::PNG => {
483                 let p = png::PNGEncoder::new(w);
484                 match *self {
485                     DynamicImage::ImageBgra8(_) => {
486                         bytes = self.to_rgba().iter().cloned().collect();
487                         color = color::ColorType::RGBA(8);
488                     }
489                     DynamicImage::ImageBgr8(_) => {
490                         bytes = self.to_rgb().iter().cloned().collect();
491                         color = color::ColorType::RGB(8);
492                     }
493                     _ => {}
494                 }
495                 p.encode(&bytes, width, height, color)?;
496                 Ok(())
497             }
498             #[cfg(feature = "pnm")]
499             image::ImageOutputFormat::PNM(subtype) => {
500                 let mut p = pnm::PNMEncoder::new(w).with_subtype(subtype);
501                 match *self {
502                     DynamicImage::ImageBgra8(_) => {
503                         bytes = self.to_rgba().iter().cloned().collect();
504                         color = color::ColorType::RGBA(8);
505                     }
506                     DynamicImage::ImageBgr8(_) => {
507                         bytes = self.to_rgb().iter().cloned().collect();
508                         color = color::ColorType::RGB(8);
509                     }
510                     _ => {}
511                 }
512                 p.encode(&bytes[..], width, height, color)?;
513                 Ok(())
514             }
515             #[cfg(feature = "jpeg")]
516             image::ImageOutputFormat::JPEG(quality) => {
517                 let mut j = jpeg::JPEGEncoder::new_with_quality(w, quality);
518 
519                 j.encode(&bytes, width, height, color)?;
520                 Ok(())
521             }
522 
523             #[cfg(feature = "gif_codec")]
524             image::ImageOutputFormat::GIF => {
525                 let mut g = gif::Encoder::new(w);
526 
527                 g.encode(&gif::Frame::from_rgba(
528                     width as u16,
529                     height as u16,
530                     &mut *self.to_rgba().iter().cloned().collect::<Vec<u8>>(),
531                 ))?;
532                 Ok(())
533             }
534 
535             #[cfg(feature = "ico")]
536             image::ImageOutputFormat::ICO => {
537                 let i = ico::ICOEncoder::new(w);
538 
539                 i.encode(&bytes, width, height, color)?;
540                 Ok(())
541             }
542 
543             #[cfg(feature = "bmp")]
544             image::ImageOutputFormat::BMP => {
545                 let mut b = bmp::BMPEncoder::new(w);
546                 b.encode(&bytes, width, height, color)?;
547                 Ok(())
548             }
549 
550             image::ImageOutputFormat::Unsupported(msg) => {
551                 Err(image::ImageError::UnsupportedError(msg))
552             }
553         }
554     }
555 
556     /// Saves the buffer to a file at the path specified.
557     ///
558     /// The image format is derived from the file extension.
save<Q>(&self, path: Q) -> io::Result<()> where Q: AsRef<Path>,559     pub fn save<Q>(&self, path: Q) -> io::Result<()>
560     where
561         Q: AsRef<Path>,
562     {
563         dynamic_map!(*self, ref p -> {
564             p.save(path)
565         })
566     }
567 
568     /// Saves the buffer to a file at the specified path in
569     /// the specified format.
570     ///
571     /// See [`save_buffer_with_format`](fn.save_buffer_with_format.html) for
572     /// supported types.
save_with_format<Q>(&self, path: Q, format: ImageFormat) -> io::Result<()> where Q: AsRef<Path>,573     pub fn save_with_format<Q>(&self, path: Q, format: ImageFormat) -> io::Result<()>
574     where
575         Q: AsRef<Path>,
576     {
577         dynamic_map!(*self, ref p -> {
578             p.save_with_format(path, format)
579         })
580     }
581 }
582 
583 #[allow(deprecated)]
584 impl GenericImageView for DynamicImage {
585     type Pixel = color::Rgba<u8>;
586     type InnerImageView = Self;
587 
dimensions(&self) -> (u32, u32)588     fn dimensions(&self) -> (u32, u32) {
589         dynamic_map!(*self, ref p -> p.dimensions())
590     }
591 
bounds(&self) -> (u32, u32, u32, u32)592     fn bounds(&self) -> (u32, u32, u32, u32) {
593         dynamic_map!(*self, ref p -> p.bounds())
594     }
595 
get_pixel(&self, x: u32, y: u32) -> color::Rgba<u8>596     fn get_pixel(&self, x: u32, y: u32) -> color::Rgba<u8> {
597         dynamic_map!(*self, ref p -> p.get_pixel(x, y).to_rgba())
598     }
599 
inner(&self) -> &Self::InnerImageView600     fn inner(&self) -> &Self::InnerImageView {
601         self
602     }
603 }
604 
605 #[allow(deprecated)]
606 impl GenericImage for DynamicImage {
607     type InnerImage = DynamicImage;
608 
put_pixel(&mut self, x: u32, y: u32, pixel: color::Rgba<u8>)609     fn put_pixel(&mut self, x: u32, y: u32, pixel: color::Rgba<u8>) {
610         match *self {
611             DynamicImage::ImageLuma8(ref mut p) => p.put_pixel(x, y, pixel.to_luma()),
612             DynamicImage::ImageLumaA8(ref mut p) => p.put_pixel(x, y, pixel.to_luma_alpha()),
613             DynamicImage::ImageRgb8(ref mut p) => p.put_pixel(x, y, pixel.to_rgb()),
614             DynamicImage::ImageRgba8(ref mut p) => p.put_pixel(x, y, pixel),
615             DynamicImage::ImageBgr8(ref mut p) => p.put_pixel(x, y, pixel.to_bgr()),
616             DynamicImage::ImageBgra8(ref mut p) => p.put_pixel(x, y, pixel.to_bgra()),
617         }
618     }
619     /// DEPRECATED: Use iterator `pixels_mut` to blend the pixels directly.
blend_pixel(&mut self, x: u32, y: u32, pixel: color::Rgba<u8>)620     fn blend_pixel(&mut self, x: u32, y: u32, pixel: color::Rgba<u8>) {
621         match *self {
622             DynamicImage::ImageLuma8(ref mut p) => p.blend_pixel(x, y, pixel.to_luma()),
623             DynamicImage::ImageLumaA8(ref mut p) => p.blend_pixel(x, y, pixel.to_luma_alpha()),
624             DynamicImage::ImageRgb8(ref mut p) => p.blend_pixel(x, y, pixel.to_rgb()),
625             DynamicImage::ImageRgba8(ref mut p) => p.blend_pixel(x, y, pixel),
626 
627             DynamicImage::ImageBgr8(ref mut p) => p.blend_pixel(x, y, pixel.to_bgr()),
628             DynamicImage::ImageBgra8(ref mut p) => p.blend_pixel(x, y, pixel.to_bgra()),
629         }
630     }
631 
632     /// DEPRECATED: Do not use is function: It is unimplemented!
get_pixel_mut(&mut self, _: u32, _: u32) -> &mut color::Rgba<u8>633     fn get_pixel_mut(&mut self, _: u32, _: u32) -> &mut color::Rgba<u8> {
634         unimplemented!()
635     }
636 
inner_mut(&mut self) -> &mut Self::InnerImage637     fn inner_mut(&mut self) -> &mut Self::InnerImage {
638         self
639     }
640 }
641 
decoder_to_image<'a, I: ImageDecoder<'a>>(codec: I) -> ImageResult<DynamicImage>642 fn decoder_to_image<'a, I: ImageDecoder<'a>>(codec: I) -> ImageResult<DynamicImage> {
643     let color = codec.colortype();
644     let (w, h) = codec.dimensions();
645     let buf = codec.read_image()?;
646 
647     // TODO: Avoid this cast by having ImageBuffer use u64's
648     assert!(w <= u64::from(u32::max_value()));
649     assert!(h <= u64::from(u32::max_value()));
650     let (w, h) = (w as u32, h as u32);
651 
652     let image = match color {
653         color::ColorType::RGB(8) => ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageRgb8),
654 
655         color::ColorType::RGBA(8) => ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageRgba8),
656 
657         color::ColorType::BGR(8) => ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageBgr8),
658 
659         color::ColorType::BGRA(8) => ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageBgra8),
660 
661         color::ColorType::Gray(8) => ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageLuma8),
662 
663         color::ColorType::GrayA(8) => {
664             ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageLumaA8)
665         }
666         color::ColorType::Gray(bit_depth) if bit_depth == 1 || bit_depth == 2 || bit_depth == 4 => {
667             gray_to_luma8(bit_depth, w, h, &buf).map(DynamicImage::ImageLuma8)
668         }
669         _ => return Err(image::ImageError::UnsupportedColor(color)),
670     };
671     match image {
672         Some(image) => Ok(image),
673         None => Err(image::ImageError::DimensionError),
674     }
675 }
676 
gray_to_luma8(bit_depth: u8, w: u32, h: u32, buf: &[u8]) -> Option<GrayImage>677 fn gray_to_luma8(bit_depth: u8, w: u32, h: u32, buf: &[u8]) -> Option<GrayImage> {
678     // Note: this conversion assumes that the scanlines begin on byte boundaries
679     let mask = (1u8 << bit_depth as usize) - 1;
680     let scaling_factor = 255 / ((1 << bit_depth as usize) - 1);
681     let bit_width = w * u32::from(bit_depth);
682     let skip = if bit_width % 8 == 0 {
683         0
684     } else {
685         (8 - bit_width % 8) / u32::from(bit_depth)
686     };
687     let row_len = w + skip;
688     let mut p = Vec::new();
689     let mut i = 0;
690     for v in buf {
691         for shift in num_iter::range_step_inclusive(8i8 - (bit_depth as i8), 0, -(bit_depth as i8))
692         {
693             // skip the pixels that can be neglected because scanlines should
694             // start at byte boundaries
695             if i % (row_len as usize) < (w as usize) {
696                 let pixel = (v & mask << shift as usize) >> shift as usize;
697                 p.push(pixel * scaling_factor);
698             }
699             i += 1;
700         }
701     }
702     ImageBuffer::from_raw(w, h, p)
703 }
704 
705 #[allow(deprecated)]
image_to_bytes(image: &DynamicImage) -> Vec<u8>706 fn image_to_bytes(image: &DynamicImage) -> Vec<u8> {
707     match *image {
708         // TODO: consider transmuting
709         DynamicImage::ImageLuma8(ref a) => a.iter().cloned().collect(),
710 
711         DynamicImage::ImageLumaA8(ref a) => a.iter().cloned().collect(),
712 
713         DynamicImage::ImageRgb8(ref a) => a.iter().cloned().collect(),
714 
715         DynamicImage::ImageRgba8(ref a) => a.iter().cloned().collect(),
716 
717         DynamicImage::ImageBgr8(ref a) => a.iter().cloned().collect(),
718 
719         DynamicImage::ImageBgra8(ref a) => a.iter().cloned().collect(),
720     }
721 }
722 
723 /// Open the image located at the path specified.
724 /// The image's format is determined from the path's file extension.
725 ///
726 /// Try [`io::Reader`] for more advanced uses, including guessing the format based on the file's
727 /// content before its path.
728 ///
729 /// [`io::Reader`]: io/struct.Reader.html
open<P>(path: P) -> ImageResult<DynamicImage> where P: AsRef<Path>,730 pub fn open<P>(path: P) -> ImageResult<DynamicImage>
731 where
732     P: AsRef<Path>,
733 {
734     // thin wrapper function to strip generics before calling open_impl
735     free_functions::open_impl(path.as_ref())
736 }
737 
738 /// Read the dimensions of the image located at the specified path.
739 /// This is faster than fully loading the image and then getting its dimensions.
740 ///
741 /// Try [`io::Reader`] for more advanced uses, including guessing the format based on the file's
742 /// content before its path or manually supplying the format.
743 ///
744 /// [`io::Reader`]: io/struct.Reader.html
image_dimensions<P>(path: P) -> ImageResult<(u32, u32)> where P: AsRef<Path>,745 pub fn image_dimensions<P>(path: P) -> ImageResult<(u32, u32)>
746 where
747     P: AsRef<Path>,
748 {
749     // thin wrapper function to strip generics before calling open_impl
750     free_functions::image_dimensions_impl(path.as_ref())
751 }
752 
753 /// Saves the supplied buffer to a file at the path specified.
754 ///
755 /// The image format is derived from the file extension. The buffer is assumed to have
756 /// the correct format according to the specified color type.
757 
758 /// This will lead to corrupted files if the buffer contains malformed data. Currently only
759 /// jpeg, png, ico, pnm, bmp and tiff files are supported.
save_buffer<P>( path: P, buf: &[u8], width: u32, height: u32, color: color::ColorType, ) -> io::Result<()> where P: AsRef<Path>,760 pub fn save_buffer<P>(
761     path: P,
762     buf: &[u8],
763     width: u32,
764     height: u32,
765     color: color::ColorType,
766 ) -> io::Result<()>
767 where
768     P: AsRef<Path>,
769 {
770     // thin wrapper function to strip generics before calling save_buffer_impl
771     free_functions::save_buffer_impl(path.as_ref(), buf, width, height, color)
772 }
773 
774 /// Saves the supplied buffer to a file at the path specified
775 /// in the specified format.
776 ///
777 /// The buffer is assumed to have the correct format according
778 /// to the specified color type.
779 /// This will lead to corrupted files if the buffer contains
780 /// malformed data. Currently only jpeg, png, ico, bmp and
781 /// tiff files are supported.
save_buffer_with_format<P>( path: P, buf: &[u8], width: u32, height: u32, color: color::ColorType, format: ImageFormat, ) -> io::Result<()> where P: AsRef<Path>,782 pub fn save_buffer_with_format<P>(
783     path: P,
784     buf: &[u8],
785     width: u32,
786     height: u32,
787     color: color::ColorType,
788     format: ImageFormat,
789 ) -> io::Result<()>
790 where
791     P: AsRef<Path>,
792 {
793     // thin wrapper function to strip generics
794     free_functions::save_buffer_with_format_impl(path.as_ref(), buf, width, height, color, format)
795 }
796 
797 /// Create a new image from a byte slice
798 ///
799 /// Makes an educated guess about the image format.
800 /// TGA is not supported by this function.
801 ///
802 /// Try [`io::Reader`] for more advanced uses.
803 ///
804 /// [`io::Reader`]: io/struct.Reader.html
load_from_memory(buffer: &[u8]) -> ImageResult<DynamicImage>805 pub fn load_from_memory(buffer: &[u8]) -> ImageResult<DynamicImage> {
806     let format = free_functions::guess_format(buffer)?;
807     load_from_memory_with_format(buffer, format)
808 }
809 
810 /// Create a new image from a byte slice
811 ///
812 /// This is just a simple wrapper that constructs an `std::io::Cursor` around the buffer and then
813 /// calls `load` with that reader.
814 ///
815 /// Try [`io::Reader`] for more advanced uses.
816 ///
817 /// [`load`]: fn.load.html
818 /// [`io::Reader`]: io/struct.Reader.html
819 #[inline(always)]
load_from_memory_with_format(buf: &[u8], format: ImageFormat) -> ImageResult<DynamicImage>820 pub fn load_from_memory_with_format(buf: &[u8], format: ImageFormat) -> ImageResult<DynamicImage> {
821     let b = io::Cursor::new(buf);
822     free_functions::load(b, format)
823 }
824 
825 /// Calculates the width and height an image should be resized to.
826 /// This preserves aspect ratio, and based on the `fill` parameter
827 /// will either fill the dimensions to fit inside the smaller constraint
828 /// (will overflow the specified bounds on one axis to preserve
829 /// aspect ratio), or will shrink so that both dimensions are
830 /// completely contained with in the given `width` and `height`,
831 /// with empty space on one axis.
resize_dimensions(width: u32, height: u32, nwidth: u32, nheight: u32, fill: bool) -> (u32, u32)832 fn resize_dimensions(width: u32, height: u32, nwidth: u32, nheight: u32, fill: bool) -> (u32, u32) {
833     let ratio = u64::from(width) * u64::from(nheight);
834     let nratio = u64::from(nwidth) * u64::from(height);
835 
836     let use_width = if fill {
837         nratio > ratio
838     } else {
839         nratio <= ratio
840     };
841     let intermediate = if use_width {
842         u64::from(height) * u64::from(nwidth) / u64::from(width)
843     } else {
844         u64::from(width) * u64::from(nheight) / u64::from(height)
845     };
846     if use_width {
847         if intermediate <= u64::from(::std::u32::MAX) {
848             (nwidth, intermediate as u32)
849         } else {
850             (
851                 (u64::from(nwidth) * u64::from(::std::u32::MAX) / intermediate) as u32,
852                 ::std::u32::MAX,
853             )
854         }
855     } else if intermediate <= u64::from(::std::u32::MAX) {
856         (intermediate as u32, nheight)
857     } else {
858         (
859             ::std::u32::MAX,
860             (u64::from(nheight) * u64::from(::std::u32::MAX) / intermediate) as u32,
861         )
862     }
863 }
864 
865 #[cfg(test)]
866 mod bench {
867     #[cfg(feature = "benchmarks")]
868     use test;
869 
870     #[bench]
871     #[cfg(feature = "benchmarks")]
bench_conversion(b: &mut test::Bencher)872     fn bench_conversion(b: &mut test::Bencher) {
873         let a = super::DynamicImage::ImageRgb8(::ImageBuffer::new(1000, 1000));
874         b.iter(|| a.to_luma());
875         b.bytes = 1000 * 1000 * 3
876     }
877 }
878 
879 #[cfg(test)]
880 mod test {
881     #[test]
test_empty_file()882     fn test_empty_file() {
883         assert!(super::load_from_memory(b"").is_err());
884     }
885 
886     quickcheck! {
887         fn resize_bounds_correctly_width(old_w: u32, new_w: u32) -> bool {
888             if old_w == 0 || new_w == 0 { return true; }
889             let result = super::resize_dimensions(old_w, 400, new_w, ::std::u32::MAX, false);
890             result.0 == new_w && result.1 == (400 as f64 * new_w as f64 / old_w as f64) as u32
891         }
892     }
893 
894     quickcheck! {
895         fn resize_bounds_correctly_height(old_h: u32, new_h: u32) -> bool {
896             if old_h == 0 || new_h == 0 { return true; }
897             let result = super::resize_dimensions(400, old_h, ::std::u32::MAX, new_h, false);
898             result.1 == new_h && result.0 == (400 as f64 * new_h as f64 / old_h as f64) as u32
899         }
900     }
901 
902     #[test]
resize_handles_fill()903     fn resize_handles_fill() {
904         let result = super::resize_dimensions(100, 200, 200, 500, true);
905         assert!(result.0 == 250);
906         assert!(result.1 == 500);
907 
908         let result = super::resize_dimensions(200, 100, 500, 200, true);
909         assert!(result.0 == 500);
910         assert!(result.1 == 250);
911     }
912 
913     #[test]
resize_handles_overflow()914     fn resize_handles_overflow() {
915         let result = super::resize_dimensions(100, ::std::u32::MAX, 200, ::std::u32::MAX, true);
916         assert!(result.0 == 100);
917         assert!(result.1 == ::std::u32::MAX);
918 
919         let result = super::resize_dimensions(::std::u32::MAX, 100, ::std::u32::MAX, 200, true);
920         assert!(result.0 == ::std::u32::MAX);
921         assert!(result.1 == 100);
922     }
923 
924     #[test]
925     #[rustfmt::skip]
gray_to_luma8_skip()926     fn gray_to_luma8_skip() {
927         let check = |bit_depth, w, h, from, to| {
928             assert_eq!(
929                 super::gray_to_luma8(bit_depth, w, h, from).map(super::GrayImage::into_raw),
930                 Some(to)
931             );
932         };
933         // Bit depth 1, skip is more than half a byte
934         check(
935             1,
936             10,
937             2,
938             &[0b11110000, 0b11000000, 0b00001111, 0b11000000],
939             vec![
940                 255, 255, 255, 255,   0,
941                   0,   0,   0, 255, 255,
942                   0,   0,   0,   0, 255,
943                 255, 255, 255, 255, 255,
944             ],
945         );
946         // Bit depth 2, skip is more than half a byte
947         check(
948             2,
949             5,
950             2,
951             &[0b11110000, 0b11000000, 0b00001111, 0b11000000],
952             vec![255, 255, 0, 0, 255, 0, 0, 255, 255, 255],
953         );
954         // Bit depth 2, skip is 0
955         check(
956             2,
957             4,
958             2,
959             &[0b11110000, 0b00001111],
960             vec![255, 255, 0, 0, 0, 0, 255, 255],
961         );
962         // Bit depth 4, skip is half a byte
963         check(4, 1, 2, &[0b11110011, 0b00001100], vec![255, 0]);
964     }
965 
966     #[cfg(feature = "jpeg")]
967     #[test]
image_dimensions()968     fn image_dimensions() {
969         let im_path = "./tests/images/jpg/progressive/cat.jpg";
970         let dims = super::image_dimensions(im_path).unwrap();
971         assert_eq!(dims, (320, 240));
972     }
973 }
974