summaryrefslogtreecommitdiffstats
path: root/third_party/rust/image/src/dynimage.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/image/src/dynimage.rs')
-rw-r--r--third_party/rust/image/src/dynimage.rs1157
1 files changed, 1157 insertions, 0 deletions
diff --git a/third_party/rust/image/src/dynimage.rs b/third_party/rust/image/src/dynimage.rs
new file mode 100644
index 0000000000..141de48563
--- /dev/null
+++ b/third_party/rust/image/src/dynimage.rs
@@ -0,0 +1,1157 @@
+use std::io;
+use std::io::Write;
+use std::path::Path;
+use std::u32;
+
+#[cfg(feature = "bmp")]
+use crate::bmp;
+#[cfg(feature = "gif")]
+use crate::gif;
+#[cfg(feature = "ico")]
+use crate::ico;
+#[cfg(feature = "jpeg")]
+use crate::jpeg;
+#[cfg(feature = "png")]
+use crate::png;
+#[cfg(feature = "pnm")]
+use crate::pnm;
+
+use crate::buffer::{
+ BgrImage, BgraImage, ConvertBuffer, GrayAlphaImage, GrayAlpha16Image,
+ GrayImage, Gray16Image, ImageBuffer, Pixel, RgbImage, Rgb16Image,
+ RgbaImage, Rgba16Image,
+};
+use crate::color::{self, IntoColor};
+use crate::error::{ImageError, ImageResult};
+use crate::flat::FlatSamples;
+use crate::image;
+use crate::image::{GenericImage, GenericImageView, ImageDecoder, ImageFormat, ImageOutputFormat};
+use crate::io::free_functions;
+use crate::imageops;
+
+/// A Dynamic Image
+#[derive(Clone)]
+pub enum DynamicImage {
+ /// Each pixel in this image is 8-bit Luma
+ ImageLuma8(GrayImage),
+
+ /// Each pixel in this image is 8-bit Luma with alpha
+ ImageLumaA8(GrayAlphaImage),
+
+ /// Each pixel in this image is 8-bit Rgb
+ ImageRgb8(RgbImage),
+
+ /// Each pixel in this image is 8-bit Rgb with alpha
+ ImageRgba8(RgbaImage),
+
+ /// Each pixel in this image is 8-bit Bgr
+ ImageBgr8(BgrImage),
+
+ /// Each pixel in this image is 8-bit Bgr with alpha
+ ImageBgra8(BgraImage),
+
+ /// Each pixel in this image is 16-bit Luma
+ ImageLuma16(Gray16Image),
+
+ /// Each pixel in this image is 16-bit Luma with alpha
+ ImageLumaA16(GrayAlpha16Image),
+
+ /// Each pixel in this image is 16-bit Rgb
+ ImageRgb16(Rgb16Image),
+
+ /// Each pixel in this image is 16-bit Rgb with alpha
+ ImageRgba16(Rgba16Image),
+}
+
+macro_rules! dynamic_map(
+ ($dynimage: expr, ref $image: ident => $action: expr) => (
+ match $dynimage {
+ DynamicImage::ImageLuma8(ref $image) => DynamicImage::ImageLuma8($action),
+ DynamicImage::ImageLumaA8(ref $image) => DynamicImage::ImageLumaA8($action),
+ DynamicImage::ImageRgb8(ref $image) => DynamicImage::ImageRgb8($action),
+ DynamicImage::ImageRgba8(ref $image) => DynamicImage::ImageRgba8($action),
+ DynamicImage::ImageBgr8(ref $image) => DynamicImage::ImageBgr8($action),
+ DynamicImage::ImageBgra8(ref $image) => DynamicImage::ImageBgra8($action),
+ DynamicImage::ImageLuma16(ref $image) => DynamicImage::ImageLuma16($action),
+ DynamicImage::ImageLumaA16(ref $image) => DynamicImage::ImageLumaA16($action),
+ DynamicImage::ImageRgb16(ref $image) => DynamicImage::ImageRgb16($action),
+ DynamicImage::ImageRgba16(ref $image) => DynamicImage::ImageRgba16($action),
+ }
+ );
+
+ ($dynimage: expr, ref mut $image: ident => $action: expr) => (
+ match $dynimage {
+ DynamicImage::ImageLuma8(ref mut $image) => DynamicImage::ImageLuma8($action),
+ DynamicImage::ImageLumaA8(ref mut $image) => DynamicImage::ImageLumaA8($action),
+ DynamicImage::ImageRgb8(ref mut $image) => DynamicImage::ImageRgb8($action),
+ DynamicImage::ImageRgba8(ref mut $image) => DynamicImage::ImageRgba8($action),
+ DynamicImage::ImageBgr8(ref mut $image) => DynamicImage::ImageBgr8($action),
+ DynamicImage::ImageBgra8(ref mut $image) => DynamicImage::ImageBgra8($action),
+ DynamicImage::ImageLuma16(ref mut $image) => DynamicImage::ImageLuma16($action),
+ DynamicImage::ImageLumaA16(ref mut $image) => DynamicImage::ImageLumaA16($action),
+ DynamicImage::ImageRgb16(ref mut $image) => DynamicImage::ImageRgb16($action),
+ DynamicImage::ImageRgba16(ref mut $image) => DynamicImage::ImageRgba16($action),
+ }
+ );
+
+ ($dynimage: expr, ref $image: ident -> $action: expr) => (
+ match $dynimage {
+ DynamicImage::ImageLuma8(ref $image) => $action,
+ DynamicImage::ImageLumaA8(ref $image) => $action,
+ DynamicImage::ImageRgb8(ref $image) => $action,
+ DynamicImage::ImageRgba8(ref $image) => $action,
+ DynamicImage::ImageBgr8(ref $image) => $action,
+ DynamicImage::ImageBgra8(ref $image) => $action,
+ DynamicImage::ImageLuma16(ref $image) => $action,
+ DynamicImage::ImageLumaA16(ref $image) => $action,
+ DynamicImage::ImageRgb16(ref $image) => $action,
+ DynamicImage::ImageRgba16(ref $image) => $action,
+ }
+ );
+
+ ($dynimage: expr, ref mut $image: ident -> $action: expr) => (
+ match $dynimage {
+ DynamicImage::ImageLuma8(ref mut $image) => $action,
+ DynamicImage::ImageLumaA8(ref mut $image) => $action,
+ DynamicImage::ImageRgb8(ref mut $image) => $action,
+ DynamicImage::ImageRgba8(ref mut $image) => $action,
+ DynamicImage::ImageBgr8(ref mut $image) => $action,
+ DynamicImage::ImageBgra8(ref mut $image) => $action,
+ DynamicImage::ImageLuma16(ref mut $image) => $action,
+ DynamicImage::ImageLumaA16(ref mut $image) => $action,
+ DynamicImage::ImageRgb16(ref mut $image) => $action,
+ DynamicImage::ImageRgba16(ref mut $image) => $action,
+ }
+ );
+);
+
+impl DynamicImage {
+ /// Creates a dynamic image backed by a buffer of grey pixels.
+ pub fn new_luma8(w: u32, h: u32) -> DynamicImage {
+ DynamicImage::ImageLuma8(ImageBuffer::new(w, h))
+ }
+
+ /// Creates a dynamic image backed by a buffer of grey
+ /// pixels with transparency.
+ pub fn new_luma_a8(w: u32, h: u32) -> DynamicImage {
+ DynamicImage::ImageLumaA8(ImageBuffer::new(w, h))
+ }
+
+ /// Creates a dynamic image backed by a buffer of RGB pixels.
+ pub fn new_rgb8(w: u32, h: u32) -> DynamicImage {
+ DynamicImage::ImageRgb8(ImageBuffer::new(w, h))
+ }
+
+ /// Creates a dynamic image backed by a buffer of RGBA pixels.
+ pub fn new_rgba8(w: u32, h: u32) -> DynamicImage {
+ DynamicImage::ImageRgba8(ImageBuffer::new(w, h))
+ }
+
+ /// Creates a dynamic image backed by a buffer of BGRA pixels.
+ pub fn new_bgra8(w: u32, h: u32) -> DynamicImage {
+ DynamicImage::ImageBgra8(ImageBuffer::new(w, h))
+ }
+
+ /// Creates a dynamic image backed by a buffer of BGR pixels.
+ pub fn new_bgr8(w: u32, h: u32) -> DynamicImage {
+ DynamicImage::ImageBgr8(ImageBuffer::new(w, h))
+ }
+
+ /// Creates a dynamic image backed by a buffer of grey pixels.
+ pub fn new_luma16(w: u32, h: u32) -> DynamicImage {
+ DynamicImage::ImageLuma16(ImageBuffer::new(w, h))
+ }
+
+ /// Creates a dynamic image backed by a buffer of grey
+ /// pixels with transparency.
+ pub fn new_luma_a16(w: u32, h: u32) -> DynamicImage {
+ DynamicImage::ImageLumaA16(ImageBuffer::new(w, h))
+ }
+
+ /// Creates a dynamic image backed by a buffer of RGB pixels.
+ pub fn new_rgb16(w: u32, h: u32) -> DynamicImage {
+ DynamicImage::ImageRgb16(ImageBuffer::new(w, h))
+ }
+
+ /// Creates a dynamic image backed by a buffer of RGBA pixels.
+ pub fn new_rgba16(w: u32, h: u32) -> DynamicImage {
+ DynamicImage::ImageRgba16(ImageBuffer::new(w, h))
+ }
+
+ /// Decodes an encoded image into a dynamic image.
+ pub fn from_decoder<'a>(decoder: impl ImageDecoder<'a>)
+ -> ImageResult<Self>
+ {
+ decoder_to_image(decoder)
+ }
+
+ /// Returns a copy of this image as an RGB image.
+ pub fn to_rgb(&self) -> RgbImage {
+ dynamic_map!(*self, ref p -> {
+ p.convert()
+ })
+ }
+
+ /// Returns a copy of this image as an RGBA image.
+ pub fn to_rgba(&self) -> RgbaImage {
+ dynamic_map!(*self, ref p -> {
+ p.convert()
+ })
+ }
+
+ /// Returns a copy of this image as an BGR image.
+ pub fn to_bgr(&self) -> BgrImage {
+ dynamic_map!(*self, ref p -> {
+ p.convert()
+ })
+ }
+
+ /// Returns a copy of this image as an BGRA image.
+ pub fn to_bgra(&self) -> BgraImage {
+ dynamic_map!(*self, ref p -> {
+ p.convert()
+ })
+ }
+
+ /// Returns a copy of this image as a Luma image.
+ pub fn to_luma(&self) -> GrayImage {
+ dynamic_map!(*self, ref p -> {
+ p.convert()
+ })
+ }
+
+ /// Returns a copy of this image as a LumaA image.
+ pub fn to_luma_alpha(&self) -> GrayAlphaImage {
+ dynamic_map!(*self, ref p -> {
+ p.convert()
+ })
+ }
+
+ /// Consume the image and returns a RGB image.
+ ///
+ /// If the image was already the correct format, it is returned as is.
+ /// Otherwise, a copy is created.
+ pub fn into_rgb(self) -> RgbImage {
+ match self {
+ DynamicImage::ImageRgb8(x) => x,
+ x => x.to_rgb(),
+ }
+ }
+
+ /// Consume the image and returns a RGBA image.
+ ///
+ /// If the image was already the correct format, it is returned as is.
+ /// Otherwise, a copy is created.
+ pub fn into_rgba(self) -> RgbaImage {
+ match self {
+ DynamicImage::ImageRgba8(x) => x,
+ x => x.to_rgba(),
+ }
+ }
+
+ /// Consume the image and returns a BGR image.
+ ///
+ /// If the image was already the correct format, it is returned as is.
+ /// Otherwise, a copy is created.
+ pub fn into_bgr(self) -> BgrImage {
+ match self {
+ DynamicImage::ImageBgr8(x) => x,
+ x => x.to_bgr(),
+ }
+ }
+
+ /// Consume the image and returns a BGRA image.
+ ///
+ /// If the image was already the correct format, it is returned as is.
+ /// Otherwise, a copy is created.
+ pub fn into_bgra(self) -> BgraImage {
+ match self {
+ DynamicImage::ImageBgra8(x) => x,
+ x => x.to_bgra(),
+ }
+ }
+
+ /// Consume the image and returns a Luma image.
+ ///
+ /// If the image was already the correct format, it is returned as is.
+ /// Otherwise, a copy is created.
+ pub fn into_luma(self) -> GrayImage {
+ match self {
+ DynamicImage::ImageLuma8(x) => x,
+ x => x.to_luma(),
+ }
+ }
+
+ /// Consume the image and returns a LumaA image.
+ ///
+ /// If the image was already the correct format, it is returned as is.
+ /// Otherwise, a copy is created.
+ pub fn into_luma_alpha(self) -> GrayAlphaImage {
+ match self {
+ DynamicImage::ImageLumaA8(x) => x,
+ x => x.to_luma_alpha(),
+ }
+ }
+
+ /// Return a cut out of this image delimited by the bounding rectangle.
+ pub fn crop(&mut self, x: u32, y: u32, width: u32, height: u32) -> DynamicImage {
+ dynamic_map!(*self, ref mut p => imageops::crop(p, x, y, width, height).to_image())
+ }
+
+ /// Return a reference to an 8bit RGB image
+ pub fn as_rgb8(&self) -> Option<&RgbImage> {
+ match *self {
+ DynamicImage::ImageRgb8(ref p) => Some(p),
+ _ => None,
+ }
+ }
+
+ /// Return a mutable reference to an 8bit RGB image
+ pub fn as_mut_rgb8(&mut self) -> Option<&mut RgbImage> {
+ match *self {
+ DynamicImage::ImageRgb8(ref mut p) => Some(p),
+ _ => None,
+ }
+ }
+
+ /// Return a reference to an 8bit BGR image
+ pub fn as_bgr8(&self) -> Option<&BgrImage> {
+ match *self {
+ DynamicImage::ImageBgr8(ref p) => Some(p),
+ _ => None,
+ }
+ }
+
+ /// Return a mutable reference to an 8bit BGR image
+ pub fn as_mut_bgr8(&mut self) -> Option<&mut BgrImage> {
+ match *self {
+ DynamicImage::ImageBgr8(ref mut p) => Some(p),
+ _ => None,
+ }
+ }
+
+ /// Return a reference to an 8bit RGBA image
+ pub fn as_rgba8(&self) -> Option<&RgbaImage> {
+ match *self {
+ DynamicImage::ImageRgba8(ref p) => Some(p),
+ _ => None,
+ }
+ }
+
+ /// Return a mutable reference to an 8bit RGBA image
+ pub fn as_mut_rgba8(&mut self) -> Option<&mut RgbaImage> {
+ match *self {
+ DynamicImage::ImageRgba8(ref mut p) => Some(p),
+ _ => None,
+ }
+ }
+
+ /// Return a reference to an 8bit BGRA image
+ pub fn as_bgra8(&self) -> Option<&BgraImage> {
+ match *self {
+ DynamicImage::ImageBgra8(ref p) => Some(p),
+ _ => None,
+ }
+ }
+
+ /// Return a mutable reference to an 8bit RGBA image
+ pub fn as_mut_bgra8(&mut self) -> Option<&mut BgraImage> {
+ match *self {
+ DynamicImage::ImageBgra8(ref mut p) => Some(p),
+ _ => None,
+ }
+ }
+
+ /// Return a reference to an 8bit Grayscale image
+ pub fn as_luma8(&self) -> Option<&GrayImage> {
+ match *self {
+ DynamicImage::ImageLuma8(ref p) => Some(p),
+ _ => None,
+ }
+ }
+
+ /// Return a mutable reference to an 8bit Grayscale image
+ pub fn as_mut_luma8(&mut self) -> Option<&mut GrayImage> {
+ match *self {
+ DynamicImage::ImageLuma8(ref mut p) => Some(p),
+ _ => None,
+ }
+ }
+
+ /// Return a reference to an 8bit Grayscale image with an alpha channel
+ pub fn as_luma_alpha8(&self) -> Option<&GrayAlphaImage> {
+ match *self {
+ DynamicImage::ImageLumaA8(ref p) => Some(p),
+ _ => None,
+ }
+ }
+
+ /// Return a mutable reference to an 8bit Grayscale image with an alpha channel
+ pub fn as_mut_luma_alpha8(&mut self) -> Option<&mut GrayAlphaImage> {
+ match *self {
+ DynamicImage::ImageLumaA8(ref mut p) => Some(p),
+ _ => None,
+ }
+ }
+
+ /// Return a reference to an 16bit RGB image
+ pub fn as_rgb16(&self) -> Option<&Rgb16Image> {
+ match *self {
+ DynamicImage::ImageRgb16(ref p) => Some(p),
+ _ => None,
+ }
+ }
+
+ /// Return a mutable reference to an 16bit RGB image
+ pub fn as_mut_rgb16(&mut self) -> Option<&mut Rgb16Image> {
+ match *self {
+ DynamicImage::ImageRgb16(ref mut p) => Some(p),
+ _ => None,
+ }
+ }
+
+ /// Return a reference to an 16bit RGBA image
+ pub fn as_rgba16(&self) -> Option<&Rgba16Image> {
+ match *self {
+ DynamicImage::ImageRgba16(ref p) => Some(p),
+ _ => None,
+ }
+ }
+
+ /// Return a mutable reference to an 16bit RGBA image
+ pub fn as_mut_rgba16(&mut self) -> Option<&mut Rgba16Image> {
+ match *self {
+ DynamicImage::ImageRgba16(ref mut p) => Some(p),
+ _ => None,
+ }
+ }
+
+ /// Return a reference to an 16bit Grayscale image
+ pub fn as_luma16(&self) -> Option<&Gray16Image> {
+ match *self {
+ DynamicImage::ImageLuma16(ref p) => Some(p),
+ _ => None,
+ }
+ }
+
+ /// Return a mutable reference to an 16bit Grayscale image
+ pub fn as_mut_luma16(&mut self) -> Option<&mut Gray16Image> {
+ match *self {
+ DynamicImage::ImageLuma16(ref mut p) => Some(p),
+ _ => None,
+ }
+ }
+
+ /// Return a reference to an 16bit Grayscale image with an alpha channel
+ pub fn as_luma_alpha16(&self) -> Option<&GrayAlpha16Image> {
+ match *self {
+ DynamicImage::ImageLumaA16(ref p) => Some(p),
+ _ => None,
+ }
+ }
+
+ /// Return a mutable reference to an 16bit Grayscale image with an alpha channel
+ pub fn as_mut_luma_alpha16(&mut self) -> Option<&mut GrayAlpha16Image> {
+ match *self {
+ DynamicImage::ImageLumaA16(ref mut p) => Some(p),
+ _ => None,
+ }
+ }
+
+ /// Return a view on the raw sample buffer for 8 bit per channel images.
+ pub fn as_flat_samples_u8(&self) -> Option<FlatSamples<&[u8]>> {
+ match *self {
+ DynamicImage::ImageLuma8(ref p) => Some(p.as_flat_samples()),
+ DynamicImage::ImageLumaA8(ref p) => Some(p.as_flat_samples()),
+ DynamicImage::ImageRgb8(ref p) => Some(p.as_flat_samples()),
+ DynamicImage::ImageRgba8(ref p) => Some(p.as_flat_samples()),
+ DynamicImage::ImageBgr8(ref p) => Some(p.as_flat_samples()),
+ DynamicImage::ImageBgra8(ref p) => Some(p.as_flat_samples()),
+ _ => None,
+ }
+ }
+
+ /// Return a view on the raw sample buffer for 16 bit per channel images.
+ pub fn as_flat_samples_u16(&self) -> Option<FlatSamples<&[u16]>> {
+ match *self {
+ DynamicImage::ImageLuma16(ref p) => Some(p.as_flat_samples()),
+ DynamicImage::ImageLumaA16(ref p) => Some(p.as_flat_samples()),
+ DynamicImage::ImageRgb16(ref p) => Some(p.as_flat_samples()),
+ DynamicImage::ImageRgba16(ref p) => Some(p.as_flat_samples()),
+ _ => None,
+ }
+ }
+
+ /// Return this image's pixels as a byte vector.
+ pub fn to_bytes(&self) -> Vec<u8> {
+ image_to_bytes(self)
+ }
+
+ /// Return this image's color type.
+ pub fn color(&self) -> color::ColorType {
+ match *self {
+ DynamicImage::ImageLuma8(_) => color::ColorType::L8,
+ DynamicImage::ImageLumaA8(_) => color::ColorType::La8,
+ DynamicImage::ImageRgb8(_) => color::ColorType::Rgb8,
+ DynamicImage::ImageRgba8(_) => color::ColorType::Rgba8,
+ DynamicImage::ImageBgra8(_) => color::ColorType::Bgra8,
+ DynamicImage::ImageBgr8(_) => color::ColorType::Bgr8,
+ DynamicImage::ImageLuma16(_) => color::ColorType::L16,
+ DynamicImage::ImageLumaA16(_) => color::ColorType::La16,
+ DynamicImage::ImageRgb16(_) => color::ColorType::Rgb16,
+ DynamicImage::ImageRgba16(_) => color::ColorType::Rgba16,
+ }
+ }
+
+ /// Return a grayscale version of this image.
+ pub fn grayscale(&self) -> DynamicImage {
+ match *self {
+ DynamicImage::ImageLuma8(ref p) => DynamicImage::ImageLuma8(p.clone()),
+ DynamicImage::ImageLumaA8(ref p) => DynamicImage::ImageLuma8(imageops::grayscale(p)),
+ DynamicImage::ImageRgb8(ref p) => DynamicImage::ImageLuma8(imageops::grayscale(p)),
+ DynamicImage::ImageRgba8(ref p) => DynamicImage::ImageLuma8(imageops::grayscale(p)),
+ DynamicImage::ImageBgr8(ref p) => DynamicImage::ImageLuma8(imageops::grayscale(p)),
+ DynamicImage::ImageBgra8(ref p) => DynamicImage::ImageLuma8(imageops::grayscale(p)),
+ DynamicImage::ImageLuma16(ref p) => DynamicImage::ImageLuma16(p.clone()),
+ DynamicImage::ImageLumaA16(ref p) => DynamicImage::ImageLuma16(imageops::grayscale(p)),
+ DynamicImage::ImageRgb16(ref p) => DynamicImage::ImageLuma16(imageops::grayscale(p)),
+ DynamicImage::ImageRgba16(ref p) => DynamicImage::ImageLuma16(imageops::grayscale(p)),
+ }
+ }
+
+ /// Invert the colors of this image.
+ /// This method operates inplace.
+ pub fn invert(&mut self) {
+ dynamic_map!(*self, ref mut p -> imageops::invert(p))
+ }
+
+ /// Resize this image using the specified filter algorithm.
+ /// Returns a new image. The image's aspect ratio is preserved.
+ /// The image is scaled to the maximum possible size that fits
+ /// within the bounds specified by ```nwidth``` and ```nheight```.
+ pub fn resize(&self, nwidth: u32, nheight: u32, filter: imageops::FilterType) -> DynamicImage {
+ let (width2, height2) =
+ resize_dimensions(self.width(), self.height(), nwidth, nheight, false);
+
+ self.resize_exact(width2, height2, filter)
+ }
+
+ /// Resize this image using the specified filter algorithm.
+ /// Returns a new image. Does not preserve aspect ratio.
+ /// ```nwidth``` and ```nheight``` are the new image's dimensions
+ pub fn resize_exact(
+ &self,
+ nwidth: u32,
+ nheight: u32,
+ filter: imageops::FilterType,
+ ) -> DynamicImage {
+ dynamic_map!(*self, ref p => imageops::resize(p, nwidth, nheight, filter))
+ }
+
+ /// Scale this image down to fit within a specific size.
+ /// Returns a new image. The image's aspect ratio is preserved.
+ /// The image is scaled to the maximum possible size that fits
+ /// within the bounds specified by ```nwidth``` and ```nheight```.
+ ///
+ /// This method uses a fast integer algorithm where each source
+ /// pixel contributes to exactly one target pixel.
+ /// May give aliasing artifacts if new size is close to old size.
+ pub fn thumbnail(&self, nwidth: u32, nheight: u32) -> DynamicImage {
+ let (width2, height2) =
+ resize_dimensions(self.width(), self.height(), nwidth, nheight, false);
+ self.thumbnail_exact(width2, height2)
+ }
+
+ /// Scale this image down to a specific size.
+ /// Returns a new image. Does not preserve aspect ratio.
+ /// ```nwidth``` and ```nheight``` are the new image's dimensions.
+ /// This method uses a fast integer algorithm where each source
+ /// pixel contributes to exactly one target pixel.
+ /// May give aliasing artifacts if new size is close to old size.
+ pub fn thumbnail_exact(&self, nwidth: u32, nheight: u32) -> DynamicImage {
+ dynamic_map!(*self, ref p => imageops::thumbnail(p, nwidth, nheight))
+ }
+
+ /// Resize this image using the specified filter algorithm.
+ /// Returns a new image. The image's aspect ratio is preserved.
+ /// The image is scaled to the maximum possible size that fits
+ /// within the larger (relative to aspect ratio) of the bounds
+ /// specified by ```nwidth``` and ```nheight```, then cropped to
+ /// fit within the other bound.
+ pub fn resize_to_fill(
+ &self,
+ nwidth: u32,
+ nheight: u32,
+ filter: imageops::FilterType,
+ ) -> DynamicImage {
+ let (width2, height2) =
+ resize_dimensions(self.width(), self.height(), nwidth, nheight, true);
+
+ let mut intermediate = self.resize_exact(width2, height2, filter);
+ let (iwidth, iheight) = intermediate.dimensions();
+ let ratio = u64::from(iwidth) * u64::from(nheight);
+ let nratio = u64::from(nwidth) * u64::from(iheight);
+
+ if nratio > ratio {
+ intermediate.crop(0, (iheight - nheight) / 2, nwidth, nheight)
+ } else {
+ intermediate.crop((iwidth - nwidth) / 2, 0, nwidth, nheight)
+ }
+ }
+
+ /// Performs a Gaussian blur on this image.
+ /// ```sigma``` is a measure of how much to blur by.
+ pub fn blur(&self, sigma: f32) -> DynamicImage {
+ dynamic_map!(*self, ref p => imageops::blur(p, sigma))
+ }
+
+ /// Performs an unsharpen mask on this image.
+ /// ```sigma``` is the amount to blur the image by.
+ /// ```threshold``` is a control of how much to sharpen.
+ ///
+ /// See <https://en.wikipedia.org/wiki/Unsharp_masking#Digital_unsharp_masking>
+ pub fn unsharpen(&self, sigma: f32, threshold: i32) -> DynamicImage {
+ dynamic_map!(*self, ref p => imageops::unsharpen(p, sigma, threshold))
+ }
+
+ /// Filters this image with the specified 3x3 kernel.
+ pub fn filter3x3(&self, kernel: &[f32]) -> DynamicImage {
+ if kernel.len() != 9 {
+ panic!("filter must be 3 x 3")
+ }
+
+ dynamic_map!(*self, ref p => imageops::filter3x3(p, kernel))
+ }
+
+ /// Adjust the contrast of this image.
+ /// ```contrast``` is the amount to adjust the contrast by.
+ /// Negative values decrease the contrast and positive values increase the contrast.
+ pub fn adjust_contrast(&self, c: f32) -> DynamicImage {
+ dynamic_map!(*self, ref p => imageops::contrast(p, c))
+ }
+
+ /// Brighten the pixels of this image.
+ /// ```value``` is the amount to brighten each pixel by.
+ /// Negative values decrease the brightness and positive values increase it.
+ pub fn brighten(&self, value: i32) -> DynamicImage {
+ dynamic_map!(*self, ref p => imageops::brighten(p, value))
+ }
+
+ /// Hue rotate the supplied image.
+ /// `value` is the degrees to rotate each pixel by.
+ /// 0 and 360 do nothing, the rest rotates by the given degree value.
+ /// just like the css webkit filter hue-rotate(180)
+ pub fn huerotate(&self, value: i32) -> DynamicImage {
+ dynamic_map!(*self, ref p => imageops::huerotate(p, value))
+ }
+
+ /// Flip this image vertically
+ pub fn flipv(&self) -> DynamicImage {
+ dynamic_map!(*self, ref p => imageops::flip_vertical(p))
+ }
+
+ /// Flip this image horizontally
+ pub fn fliph(&self) -> DynamicImage {
+ dynamic_map!(*self, ref p => imageops::flip_horizontal(p))
+ }
+
+ /// Rotate this image 90 degrees clockwise.
+ pub fn rotate90(&self) -> DynamicImage {
+ dynamic_map!(*self, ref p => imageops::rotate90(p))
+ }
+
+ /// Rotate this image 180 degrees clockwise.
+ pub fn rotate180(&self) -> DynamicImage {
+ dynamic_map!(*self, ref p => imageops::rotate180(p))
+ }
+
+ /// Rotate this image 270 degrees clockwise.
+ pub fn rotate270(&self) -> DynamicImage {
+ dynamic_map!(*self, ref p => imageops::rotate270(p))
+ }
+
+ /// Encode this image and write it to ```w```
+ pub fn write_to<W: Write, F: Into<ImageOutputFormat>>(
+ &self,
+ w: &mut W,
+ format: F,
+ ) -> ImageResult<()> {
+ let mut bytes = self.to_bytes();
+ let (width, height) = self.dimensions();
+ let mut color = self.color();
+ let format = format.into();
+
+ #[allow(deprecated)]
+ match format {
+ #[cfg(feature = "png")]
+ image::ImageOutputFormat::Png => {
+ let p = png::PNGEncoder::new(w);
+ match *self {
+ DynamicImage::ImageBgra8(_) => {
+ bytes = self.to_rgba().iter().cloned().collect();
+ color = color::ColorType::Rgba8;
+ }
+ DynamicImage::ImageBgr8(_) => {
+ bytes = self.to_rgb().iter().cloned().collect();
+ color = color::ColorType::Rgb8;
+ }
+ _ => {}
+ }
+ p.encode(&bytes, width, height, color)?;
+ Ok(())
+ }
+ #[cfg(feature = "pnm")]
+ image::ImageOutputFormat::Pnm(subtype) => {
+ let mut p = pnm::PNMEncoder::new(w).with_subtype(subtype);
+ match *self {
+ DynamicImage::ImageBgra8(_) => {
+ bytes = self.to_rgba().iter().cloned().collect();
+ color = color::ColorType::Rgba8;
+ }
+ DynamicImage::ImageBgr8(_) => {
+ bytes = self.to_rgb().iter().cloned().collect();
+ color = color::ColorType::Rgb8;
+ }
+ _ => {}
+ }
+ p.encode(&bytes[..], width, height, color)?;
+ Ok(())
+ }
+ #[cfg(feature = "jpeg")]
+ image::ImageOutputFormat::Jpeg(quality) => {
+ let mut j = jpeg::JPEGEncoder::new_with_quality(w, quality);
+
+ j.encode(&bytes, width, height, color)?;
+ Ok(())
+ }
+
+ #[cfg(feature = "gif")]
+ image::ImageOutputFormat::Gif => {
+ let mut g = gif::Encoder::new(w);
+ g.encode_frame(crate::animation::Frame::new(self.to_rgba()))?;
+ Ok(())
+ }
+
+ #[cfg(feature = "ico")]
+ image::ImageOutputFormat::Ico => {
+ let i = ico::ICOEncoder::new(w);
+
+ i.encode(&bytes, width, height, color)?;
+ Ok(())
+ }
+
+ #[cfg(feature = "bmp")]
+ image::ImageOutputFormat::Bmp => {
+ let mut b = bmp::BMPEncoder::new(w);
+ b.encode(&bytes, width, height, color)?;
+ Ok(())
+ }
+
+ image::ImageOutputFormat::Unsupported(msg) => {
+ Err(ImageError::UnsupportedError(msg))
+ },
+
+ image::ImageOutputFormat::__NonExhaustive(marker) => match marker._private {},
+ }
+ }
+
+ /// Saves the buffer to a file at the path specified.
+ ///
+ /// The image format is derived from the file extension.
+ pub fn save<Q>(&self, path: Q) -> ImageResult<()>
+ where
+ Q: AsRef<Path>,
+ {
+ dynamic_map!(*self, ref p -> {
+ p.save(path)
+ })
+ }
+
+ /// Saves the buffer to a file at the specified path in
+ /// the specified format.
+ ///
+ /// See [`save_buffer_with_format`](fn.save_buffer_with_format.html) for
+ /// supported types.
+ pub fn save_with_format<Q>(&self, path: Q, format: ImageFormat) -> ImageResult<()>
+ where
+ Q: AsRef<Path>,
+ {
+ dynamic_map!(*self, ref p -> {
+ p.save_with_format(path, format)
+ })
+ }
+}
+
+#[allow(deprecated)]
+impl GenericImageView for DynamicImage {
+ type Pixel = color::Rgba<u8>;
+ type InnerImageView = Self;
+
+ fn dimensions(&self) -> (u32, u32) {
+ dynamic_map!(*self, ref p -> p.dimensions())
+ }
+
+ fn bounds(&self) -> (u32, u32, u32, u32) {
+ dynamic_map!(*self, ref p -> p.bounds())
+ }
+
+ fn get_pixel(&self, x: u32, y: u32) -> color::Rgba<u8> {
+ dynamic_map!(*self, ref p -> p.get_pixel(x, y).to_rgba().into_color())
+ }
+
+ fn inner(&self) -> &Self::InnerImageView {
+ self
+ }
+}
+
+#[allow(deprecated)]
+impl GenericImage for DynamicImage {
+ type InnerImage = DynamicImage;
+
+ fn put_pixel(&mut self, x: u32, y: u32, pixel: color::Rgba<u8>) {
+ match *self {
+ DynamicImage::ImageLuma8(ref mut p) => p.put_pixel(x, y, pixel.to_luma()),
+ DynamicImage::ImageLumaA8(ref mut p) => p.put_pixel(x, y, pixel.to_luma_alpha()),
+ DynamicImage::ImageRgb8(ref mut p) => p.put_pixel(x, y, pixel.to_rgb()),
+ DynamicImage::ImageRgba8(ref mut p) => p.put_pixel(x, y, pixel),
+ DynamicImage::ImageBgr8(ref mut p) => p.put_pixel(x, y, pixel.to_bgr()),
+ DynamicImage::ImageBgra8(ref mut p) => p.put_pixel(x, y, pixel.to_bgra()),
+ DynamicImage::ImageLuma16(ref mut p) => p.put_pixel(x, y, pixel.to_luma().into_color()),
+ DynamicImage::ImageLumaA16(ref mut p) => p.put_pixel(x, y, pixel.to_luma_alpha().into_color()),
+ DynamicImage::ImageRgb16(ref mut p) => p.put_pixel(x, y, pixel.to_rgb().into_color()),
+ DynamicImage::ImageRgba16(ref mut p) => p.put_pixel(x, y, pixel.into_color()),
+ }
+ }
+ /// DEPRECATED: Use iterator `pixels_mut` to blend the pixels directly.
+ fn blend_pixel(&mut self, x: u32, y: u32, pixel: color::Rgba<u8>) {
+ match *self {
+ DynamicImage::ImageLuma8(ref mut p) => p.blend_pixel(x, y, pixel.to_luma()),
+ DynamicImage::ImageLumaA8(ref mut p) => p.blend_pixel(x, y, pixel.to_luma_alpha()),
+ DynamicImage::ImageRgb8(ref mut p) => p.blend_pixel(x, y, pixel.to_rgb()),
+ DynamicImage::ImageRgba8(ref mut p) => p.blend_pixel(x, y, pixel),
+ DynamicImage::ImageBgr8(ref mut p) => p.blend_pixel(x, y, pixel.to_bgr()),
+ DynamicImage::ImageBgra8(ref mut p) => p.blend_pixel(x, y, pixel.to_bgra()),
+ DynamicImage::ImageLuma16(ref mut p) => p.blend_pixel(x, y, pixel.to_luma().into_color()),
+ DynamicImage::ImageLumaA16(ref mut p) => p.blend_pixel(x, y, pixel.to_luma_alpha().into_color()),
+ DynamicImage::ImageRgb16(ref mut p) => p.blend_pixel(x, y, pixel.to_rgb().into_color()),
+ DynamicImage::ImageRgba16(ref mut p) => p.blend_pixel(x, y, pixel.into_color()),
+ }
+ }
+
+ /// DEPRECATED: Do not use is function: It is unimplemented!
+ fn get_pixel_mut(&mut self, _: u32, _: u32) -> &mut color::Rgba<u8> {
+ unimplemented!()
+ }
+
+ fn inner_mut(&mut self) -> &mut Self::InnerImage {
+ self
+ }
+}
+
+/// Decodes an image and stores it into a dynamic image
+fn decoder_to_image<'a, I: ImageDecoder<'a>>(decoder: I) -> ImageResult<DynamicImage> {
+ let (w, h) = decoder.dimensions();
+ let color_type = decoder.color_type();
+
+ let image = match color_type {
+ color::ColorType::Rgb8 => {
+ let buf = image::decoder_to_vec(decoder)?;
+ ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageRgb8)
+ }
+
+ color::ColorType::Rgba8 => {
+ let buf = image::decoder_to_vec(decoder)?;
+ ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageRgba8)
+ }
+
+ color::ColorType::Bgr8 => {
+ let buf = image::decoder_to_vec(decoder)?;
+ ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageBgr8)
+ }
+
+ color::ColorType::Bgra8 => {
+ let buf = image::decoder_to_vec(decoder)?;
+ ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageBgra8)
+ }
+
+ color::ColorType::L8 => {
+ let buf = image::decoder_to_vec(decoder)?;
+ ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageLuma8)
+ }
+
+ color::ColorType::La8 => {
+ let buf = image::decoder_to_vec(decoder)?;
+ ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageLumaA8)
+ }
+
+ color::ColorType::Rgb16 => {
+ let buf = image::decoder_to_vec(decoder)?;
+ ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageRgb16)
+ }
+
+ color::ColorType::Rgba16 => {
+ let buf = image::decoder_to_vec(decoder)?;
+ ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageRgba16)
+ }
+
+ color::ColorType::L16 => {
+ let buf = image::decoder_to_vec(decoder)?;
+ ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageLuma16)
+ }
+ color::ColorType::La16 => {
+ let buf = image::decoder_to_vec(decoder)?;
+ ImageBuffer::from_raw(w, h, buf).map(DynamicImage::ImageLumaA16)
+ }
+ _ => return Err(ImageError::UnsupportedColor(color_type.into())),
+ };
+ match image {
+ Some(image) => Ok(image),
+ None => Err(ImageError::DimensionError),
+ }
+}
+
+#[allow(deprecated)]
+fn image_to_bytes(image: &DynamicImage) -> Vec<u8> {
+ use crate::traits::EncodableLayout;
+
+ match *image {
+ // TODO: consider transmuting
+ DynamicImage::ImageLuma8(ref a) => a.iter().cloned().collect(),
+
+ DynamicImage::ImageLumaA8(ref a) => a.iter().cloned().collect(),
+
+ DynamicImage::ImageRgb8(ref a) => a.iter().cloned().collect(),
+
+ DynamicImage::ImageRgba8(ref a) => a.iter().cloned().collect(),
+
+ DynamicImage::ImageBgr8(ref a) => a.iter().cloned().collect(),
+
+ DynamicImage::ImageBgra8(ref a) => a.iter().cloned().collect(),
+
+ DynamicImage::ImageLuma16(ref a) => a.as_bytes().to_vec(),
+
+ DynamicImage::ImageLumaA16(ref a) => a.as_bytes().to_vec(),
+
+ DynamicImage::ImageRgb16(ref a) => a.as_bytes().to_vec(),
+
+ DynamicImage::ImageRgba16(ref a) => a.as_bytes().to_vec(),
+ }
+}
+
+/// Open the image located at the path specified.
+/// The image's format is determined from the path's file extension.
+///
+/// Try [`io::Reader`] for more advanced uses, including guessing the format based on the file's
+/// content before its path.
+///
+/// [`io::Reader`]: io/struct.Reader.html
+pub fn open<P>(path: P) -> ImageResult<DynamicImage>
+where
+ P: AsRef<Path>,
+{
+ // thin wrapper function to strip generics before calling open_impl
+ free_functions::open_impl(path.as_ref())
+}
+
+/// Read the dimensions of the image located at the specified path.
+/// This is faster than fully loading the image and then getting its dimensions.
+///
+/// Try [`io::Reader`] for more advanced uses, including guessing the format based on the file's
+/// content before its path or manually supplying the format.
+///
+/// [`io::Reader`]: io/struct.Reader.html
+pub fn image_dimensions<P>(path: P) -> ImageResult<(u32, u32)>
+where
+ P: AsRef<Path>,
+{
+ // thin wrapper function to strip generics before calling open_impl
+ free_functions::image_dimensions_impl(path.as_ref())
+}
+
+/// Saves the supplied buffer to a file at the path specified.
+///
+/// The image format is derived from the file extension. The buffer is assumed to have
+/// the correct format according to the specified color type.
+
+/// This will lead to corrupted files if the buffer contains malformed data. Currently only
+/// jpeg, png, ico, pnm, bmp and tiff files are supported.
+pub fn save_buffer<P>(
+ path: P,
+ buf: &[u8],
+ width: u32,
+ height: u32,
+ color: color::ColorType,
+) -> ImageResult<()>
+where
+ P: AsRef<Path>,
+{
+ // thin wrapper function to strip generics before calling save_buffer_impl
+ free_functions::save_buffer_impl(path.as_ref(), buf, width, height, color)
+}
+
+/// Saves the supplied buffer to a file at the path specified
+/// in the specified format.
+///
+/// The buffer is assumed to have the correct format according
+/// to the specified color type.
+/// This will lead to corrupted files if the buffer contains
+/// malformed data. Currently only jpeg, png, ico, bmp and
+/// tiff files are supported.
+pub fn save_buffer_with_format<P>(
+ path: P,
+ buf: &[u8],
+ width: u32,
+ height: u32,
+ color: color::ColorType,
+ format: ImageFormat,
+) -> ImageResult<()>
+where
+ P: AsRef<Path>,
+{
+ // thin wrapper function to strip generics
+ free_functions::save_buffer_with_format_impl(path.as_ref(), buf, width, height, color, format)
+}
+
+/// Create a new image from a byte slice
+///
+/// Makes an educated guess about the image format.
+/// TGA is not supported by this function.
+///
+/// Try [`io::Reader`] for more advanced uses.
+///
+/// [`io::Reader`]: io/struct.Reader.html
+pub fn load_from_memory(buffer: &[u8]) -> ImageResult<DynamicImage> {
+ let format = free_functions::guess_format(buffer)?;
+ load_from_memory_with_format(buffer, format)
+}
+
+/// Create a new image from a byte slice
+///
+/// This is just a simple wrapper that constructs an `std::io::Cursor` around the buffer and then
+/// calls `load` with that reader.
+///
+/// Try [`io::Reader`] for more advanced uses.
+///
+/// [`load`]: fn.load.html
+/// [`io::Reader`]: io/struct.Reader.html
+#[inline(always)]
+pub fn load_from_memory_with_format(buf: &[u8], format: ImageFormat) -> ImageResult<DynamicImage> {
+ let b = io::Cursor::new(buf);
+ free_functions::load(b, format)
+}
+
+/// Calculates the width and height an image should be resized to.
+/// This preserves aspect ratio, and based on the `fill` parameter
+/// will either fill the dimensions to fit inside the smaller constraint
+/// (will overflow the specified bounds on one axis to preserve
+/// aspect ratio), or will shrink so that both dimensions are
+/// completely contained with in the given `width` and `height`,
+/// with empty space on one axis.
+fn resize_dimensions(width: u32, height: u32, nwidth: u32, nheight: u32, fill: bool) -> (u32, u32) {
+ let ratio = u64::from(width) * u64::from(nheight);
+ let nratio = u64::from(nwidth) * u64::from(height);
+
+ let use_width = if fill {
+ nratio > ratio
+ } else {
+ nratio <= ratio
+ };
+ let intermediate = if use_width {
+ u64::from(height) * u64::from(nwidth) / u64::from(width)
+ } else {
+ u64::from(width) * u64::from(nheight) / u64::from(height)
+ };
+ if use_width {
+ if intermediate <= u64::from(::std::u32::MAX) {
+ (nwidth, intermediate as u32)
+ } else {
+ (
+ (u64::from(nwidth) * u64::from(::std::u32::MAX) / intermediate) as u32,
+ ::std::u32::MAX,
+ )
+ }
+ } else if intermediate <= u64::from(::std::u32::MAX) {
+ (intermediate as u32, nheight)
+ } else {
+ (
+ ::std::u32::MAX,
+ (u64::from(nheight) * u64::from(::std::u32::MAX) / intermediate) as u32,
+ )
+ }
+}
+
+#[cfg(test)]
+mod bench {
+ #[cfg(feature = "benchmarks")]
+ use test;
+
+ #[bench]
+ #[cfg(feature = "benchmarks")]
+ fn bench_conversion(b: &mut test::Bencher) {
+ let a = super::DynamicImage::ImageRgb8(crate::ImageBuffer::new(1000, 1000));
+ b.iter(|| a.to_luma());
+ b.bytes = 1000 * 1000 * 3
+ }
+}
+
+#[cfg(test)]
+mod test {
+ #[test]
+ fn test_empty_file() {
+ assert!(super::load_from_memory(b"").is_err());
+ }
+
+ quickcheck! {
+ fn resize_bounds_correctly_width(old_w: u32, new_w: u32) -> bool {
+ if old_w == 0 || new_w == 0 { return true; }
+ let result = super::resize_dimensions(old_w, 400, new_w, ::std::u32::MAX, false);
+ result.0 == new_w && result.1 == (400 as f64 * new_w as f64 / old_w as f64) as u32
+ }
+ }
+
+ quickcheck! {
+ fn resize_bounds_correctly_height(old_h: u32, new_h: u32) -> bool {
+ if old_h == 0 || new_h == 0 { return true; }
+ let result = super::resize_dimensions(400, old_h, ::std::u32::MAX, new_h, false);
+ result.1 == new_h && result.0 == (400 as f64 * new_h as f64 / old_h as f64) as u32
+ }
+ }
+
+ #[test]
+ fn resize_handles_fill() {
+ let result = super::resize_dimensions(100, 200, 200, 500, true);
+ assert!(result.0 == 250);
+ assert!(result.1 == 500);
+
+ let result = super::resize_dimensions(200, 100, 500, 200, true);
+ assert!(result.0 == 500);
+ assert!(result.1 == 250);
+ }
+
+ #[test]
+ fn resize_handles_overflow() {
+ let result = super::resize_dimensions(100, ::std::u32::MAX, 200, ::std::u32::MAX, true);
+ assert!(result.0 == 100);
+ assert!(result.1 == ::std::u32::MAX);
+
+ let result = super::resize_dimensions(::std::u32::MAX, 100, ::std::u32::MAX, 200, true);
+ assert!(result.0 == ::std::u32::MAX);
+ assert!(result.1 == 100);
+ }
+
+ #[cfg(feature = "jpeg")]
+ #[test]
+ fn image_dimensions() {
+ let im_path = "./tests/images/jpg/progressive/cat.jpg";
+ let dims = super::image_dimensions(im_path).unwrap();
+ assert_eq!(dims, (320, 240));
+ }
+
+ #[cfg(feature = "png")]
+ #[test]
+ fn open_16bpc_png() {
+ let im_path = "./tests/images/png/16bpc/basn6a16.png";
+ let image = super::open(im_path).unwrap();
+ assert_eq!(image.color(), super::color::ColorType::Rgba16);
+ }
+}