aboutsummaryrefslogtreecommitdiff
path: root/vendor/image/src/buffer.rs
diff options
context:
space:
mode:
authorValentin Popov <valentin@popov.link>2024-01-08 00:21:28 +0300
committerValentin Popov <valentin@popov.link>2024-01-08 00:21:28 +0300
commit1b6a04ca5504955c571d1c97504fb45ea0befee4 (patch)
tree7579f518b23313e8a9748a88ab6173d5e030b227 /vendor/image/src/buffer.rs
parent5ecd8cf2cba827454317368b68571df0d13d7842 (diff)
downloadfparkan-1b6a04ca5504955c571d1c97504fb45ea0befee4.tar.xz
fparkan-1b6a04ca5504955c571d1c97504fb45ea0befee4.zip
Initial vendor packages
Signed-off-by: Valentin Popov <valentin@popov.link>
Diffstat (limited to 'vendor/image/src/buffer.rs')
-rw-r--r--vendor/image/src/buffer.rs1768
1 files changed, 1768 insertions, 0 deletions
diff --git a/vendor/image/src/buffer.rs b/vendor/image/src/buffer.rs
new file mode 100644
index 0000000..765a9de
--- /dev/null
+++ b/vendor/image/src/buffer.rs
@@ -0,0 +1,1768 @@
+//! Contains the generic `ImageBuffer` struct.
+use num_traits::Zero;
+use std::fmt;
+use std::marker::PhantomData;
+use std::ops::{Deref, DerefMut, Index, IndexMut, Range};
+use std::path::Path;
+use std::slice::{ChunksExact, ChunksExactMut};
+
+use crate::color::{FromColor, Luma, LumaA, Rgb, Rgba};
+use crate::dynimage::{save_buffer, save_buffer_with_format, write_buffer_with_format};
+use crate::error::ImageResult;
+use crate::flat::{FlatSamples, SampleLayout};
+use crate::image::{GenericImage, GenericImageView, ImageEncoder, ImageFormat, ImageOutputFormat};
+use crate::math::Rect;
+use crate::traits::{EncodableLayout, Pixel, PixelWithColorType};
+use crate::utils::expand_packed;
+
+/// Iterate over pixel refs.
+pub struct Pixels<'a, P: Pixel + 'a>
+where
+ P::Subpixel: 'a,
+{
+ chunks: ChunksExact<'a, P::Subpixel>,
+}
+
+impl<'a, P: Pixel + 'a> Iterator for Pixels<'a, P>
+where
+ P::Subpixel: 'a,
+{
+ type Item = &'a P;
+
+ #[inline(always)]
+ fn next(&mut self) -> Option<&'a P> {
+ self.chunks.next().map(|v| <P as Pixel>::from_slice(v))
+ }
+
+ #[inline(always)]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let len = self.len();
+ (len, Some(len))
+ }
+}
+
+impl<'a, P: Pixel + 'a> ExactSizeIterator for Pixels<'a, P>
+where
+ P::Subpixel: 'a,
+{
+ fn len(&self) -> usize {
+ self.chunks.len()
+ }
+}
+
+impl<'a, P: Pixel + 'a> DoubleEndedIterator for Pixels<'a, P>
+where
+ P::Subpixel: 'a,
+{
+ #[inline(always)]
+ fn next_back(&mut self) -> Option<&'a P> {
+ self.chunks.next_back().map(|v| <P as Pixel>::from_slice(v))
+ }
+}
+
+impl<P: Pixel> Clone for Pixels<'_, P> {
+ fn clone(&self) -> Self {
+ Pixels {
+ chunks: self.chunks.clone(),
+ }
+ }
+}
+
+impl<P: Pixel> fmt::Debug for Pixels<'_, P>
+where
+ P::Subpixel: fmt::Debug,
+{
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("Pixels")
+ .field("chunks", &self.chunks)
+ .finish()
+ }
+}
+
+/// Iterate over mutable pixel refs.
+pub struct PixelsMut<'a, P: Pixel + 'a>
+where
+ P::Subpixel: 'a,
+{
+ chunks: ChunksExactMut<'a, P::Subpixel>,
+}
+
+impl<'a, P: Pixel + 'a> Iterator for PixelsMut<'a, P>
+where
+ P::Subpixel: 'a,
+{
+ type Item = &'a mut P;
+
+ #[inline(always)]
+ fn next(&mut self) -> Option<&'a mut P> {
+ self.chunks.next().map(|v| <P as Pixel>::from_slice_mut(v))
+ }
+
+ #[inline(always)]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let len = self.len();
+ (len, Some(len))
+ }
+}
+
+impl<'a, P: Pixel + 'a> ExactSizeIterator for PixelsMut<'a, P>
+where
+ P::Subpixel: 'a,
+{
+ fn len(&self) -> usize {
+ self.chunks.len()
+ }
+}
+
+impl<'a, P: Pixel + 'a> DoubleEndedIterator for PixelsMut<'a, P>
+where
+ P::Subpixel: 'a,
+{
+ #[inline(always)]
+ fn next_back(&mut self) -> Option<&'a mut P> {
+ self.chunks
+ .next_back()
+ .map(|v| <P as Pixel>::from_slice_mut(v))
+ }
+}
+
+impl<P: Pixel> fmt::Debug for PixelsMut<'_, P>
+where
+ P::Subpixel: fmt::Debug,
+{
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("PixelsMut")
+ .field("chunks", &self.chunks)
+ .finish()
+ }
+}
+
+/// Iterate over rows of an image
+///
+/// This iterator is created with [`ImageBuffer::rows`]. See its document for details.
+///
+/// [`ImageBuffer::rows`]: ../struct.ImageBuffer.html#method.rows
+pub struct Rows<'a, P: Pixel + 'a>
+where
+ <P as Pixel>::Subpixel: 'a,
+{
+ pixels: ChunksExact<'a, P::Subpixel>,
+}
+
+impl<'a, P: Pixel + 'a> Rows<'a, P> {
+ /// Construct the iterator from image pixels. This is not public since it has a (hidden) panic
+ /// condition. The `pixels` slice must be large enough so that all pixels are addressable.
+ fn with_image(pixels: &'a [P::Subpixel], width: u32, height: u32) -> Self {
+ let row_len = (width as usize) * usize::from(<P as Pixel>::CHANNEL_COUNT);
+ if row_len == 0 {
+ Rows {
+ pixels: [].chunks_exact(1),
+ }
+ } else {
+ let pixels = pixels
+ .get(..row_len * height as usize)
+ .expect("Pixel buffer has too few subpixels");
+ // Rows are physically present. In particular, height is smaller than `usize::MAX` as
+ // all subpixels can be indexed.
+ Rows {
+ pixels: pixels.chunks_exact(row_len),
+ }
+ }
+ }
+}
+
+impl<'a, P: Pixel + 'a> Iterator for Rows<'a, P>
+where
+ P::Subpixel: 'a,
+{
+ type Item = Pixels<'a, P>;
+
+ #[inline(always)]
+ fn next(&mut self) -> Option<Pixels<'a, P>> {
+ let row = self.pixels.next()?;
+ Some(Pixels {
+ // Note: this is not reached when CHANNEL_COUNT is 0.
+ chunks: row.chunks_exact(<P as Pixel>::CHANNEL_COUNT as usize),
+ })
+ }
+
+ #[inline(always)]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let len = self.len();
+ (len, Some(len))
+ }
+}
+
+impl<'a, P: Pixel + 'a> ExactSizeIterator for Rows<'a, P>
+where
+ P::Subpixel: 'a,
+{
+ fn len(&self) -> usize {
+ self.pixels.len()
+ }
+}
+
+impl<'a, P: Pixel + 'a> DoubleEndedIterator for Rows<'a, P>
+where
+ P::Subpixel: 'a,
+{
+ #[inline(always)]
+ fn next_back(&mut self) -> Option<Pixels<'a, P>> {
+ let row = self.pixels.next_back()?;
+ Some(Pixels {
+ // Note: this is not reached when CHANNEL_COUNT is 0.
+ chunks: row.chunks_exact(<P as Pixel>::CHANNEL_COUNT as usize),
+ })
+ }
+}
+
+impl<P: Pixel> Clone for Rows<'_, P> {
+ fn clone(&self) -> Self {
+ Rows {
+ pixels: self.pixels.clone(),
+ }
+ }
+}
+
+impl<P: Pixel> fmt::Debug for Rows<'_, P>
+where
+ P::Subpixel: fmt::Debug,
+{
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("Rows")
+ .field("pixels", &self.pixels)
+ .finish()
+ }
+}
+
+/// Iterate over mutable rows of an image
+///
+/// This iterator is created with [`ImageBuffer::rows_mut`]. See its document for details.
+///
+/// [`ImageBuffer::rows_mut`]: ../struct.ImageBuffer.html#method.rows_mut
+pub struct RowsMut<'a, P: Pixel + 'a>
+where
+ <P as Pixel>::Subpixel: 'a,
+{
+ pixels: ChunksExactMut<'a, P::Subpixel>,
+}
+
+impl<'a, P: Pixel + 'a> RowsMut<'a, P> {
+ /// Construct the iterator from image pixels. This is not public since it has a (hidden) panic
+ /// condition. The `pixels` slice must be large enough so that all pixels are addressable.
+ fn with_image(pixels: &'a mut [P::Subpixel], width: u32, height: u32) -> Self {
+ let row_len = (width as usize) * usize::from(<P as Pixel>::CHANNEL_COUNT);
+ if row_len == 0 {
+ RowsMut {
+ pixels: [].chunks_exact_mut(1),
+ }
+ } else {
+ let pixels = pixels
+ .get_mut(..row_len * height as usize)
+ .expect("Pixel buffer has too few subpixels");
+ // Rows are physically present. In particular, height is smaller than `usize::MAX` as
+ // all subpixels can be indexed.
+ RowsMut {
+ pixels: pixels.chunks_exact_mut(row_len),
+ }
+ }
+ }
+}
+
+impl<'a, P: Pixel + 'a> Iterator for RowsMut<'a, P>
+where
+ P::Subpixel: 'a,
+{
+ type Item = PixelsMut<'a, P>;
+
+ #[inline(always)]
+ fn next(&mut self) -> Option<PixelsMut<'a, P>> {
+ let row = self.pixels.next()?;
+ Some(PixelsMut {
+ // Note: this is not reached when CHANNEL_COUNT is 0.
+ chunks: row.chunks_exact_mut(<P as Pixel>::CHANNEL_COUNT as usize),
+ })
+ }
+
+ #[inline(always)]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let len = self.len();
+ (len, Some(len))
+ }
+}
+
+impl<'a, P: Pixel + 'a> ExactSizeIterator for RowsMut<'a, P>
+where
+ P::Subpixel: 'a,
+{
+ fn len(&self) -> usize {
+ self.pixels.len()
+ }
+}
+
+impl<'a, P: Pixel + 'a> DoubleEndedIterator for RowsMut<'a, P>
+where
+ P::Subpixel: 'a,
+{
+ #[inline(always)]
+ fn next_back(&mut self) -> Option<PixelsMut<'a, P>> {
+ let row = self.pixels.next_back()?;
+ Some(PixelsMut {
+ // Note: this is not reached when CHANNEL_COUNT is 0.
+ chunks: row.chunks_exact_mut(<P as Pixel>::CHANNEL_COUNT as usize),
+ })
+ }
+}
+
+impl<P: Pixel> fmt::Debug for RowsMut<'_, P>
+where
+ P::Subpixel: fmt::Debug,
+{
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("RowsMut")
+ .field("pixels", &self.pixels)
+ .finish()
+ }
+}
+
+/// Enumerate the pixels of an image.
+pub struct EnumeratePixels<'a, P: Pixel + 'a>
+where
+ <P as Pixel>::Subpixel: 'a,
+{
+ pixels: Pixels<'a, P>,
+ x: u32,
+ y: u32,
+ width: u32,
+}
+
+impl<'a, P: Pixel + 'a> Iterator for EnumeratePixels<'a, P>
+where
+ P::Subpixel: 'a,
+{
+ type Item = (u32, u32, &'a P);
+
+ #[inline(always)]
+ fn next(&mut self) -> Option<(u32, u32, &'a P)> {
+ if self.x >= self.width {
+ self.x = 0;
+ self.y += 1;
+ }
+ let (x, y) = (self.x, self.y);
+ self.x += 1;
+ self.pixels.next().map(|p| (x, y, p))
+ }
+
+ #[inline(always)]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let len = self.len();
+ (len, Some(len))
+ }
+}
+
+impl<'a, P: Pixel + 'a> ExactSizeIterator for EnumeratePixels<'a, P>
+where
+ P::Subpixel: 'a,
+{
+ fn len(&self) -> usize {
+ self.pixels.len()
+ }
+}
+
+impl<P: Pixel> Clone for EnumeratePixels<'_, P> {
+ fn clone(&self) -> Self {
+ EnumeratePixels {
+ pixels: self.pixels.clone(),
+ ..*self
+ }
+ }
+}
+
+impl<P: Pixel> fmt::Debug for EnumeratePixels<'_, P>
+where
+ P::Subpixel: fmt::Debug,
+{
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("EnumeratePixels")
+ .field("pixels", &self.pixels)
+ .field("x", &self.x)
+ .field("y", &self.y)
+ .field("width", &self.width)
+ .finish()
+ }
+}
+
+/// Enumerate the rows of an image.
+pub struct EnumerateRows<'a, P: Pixel + 'a>
+where
+ <P as Pixel>::Subpixel: 'a,
+{
+ rows: Rows<'a, P>,
+ y: u32,
+ width: u32,
+}
+
+impl<'a, P: Pixel + 'a> Iterator for EnumerateRows<'a, P>
+where
+ P::Subpixel: 'a,
+{
+ type Item = (u32, EnumeratePixels<'a, P>);
+
+ #[inline(always)]
+ fn next(&mut self) -> Option<(u32, EnumeratePixels<'a, P>)> {
+ let y = self.y;
+ self.y += 1;
+ self.rows.next().map(|r| {
+ (
+ y,
+ EnumeratePixels {
+ x: 0,
+ y,
+ width: self.width,
+ pixels: r,
+ },
+ )
+ })
+ }
+
+ #[inline(always)]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let len = self.len();
+ (len, Some(len))
+ }
+}
+
+impl<'a, P: Pixel + 'a> ExactSizeIterator for EnumerateRows<'a, P>
+where
+ P::Subpixel: 'a,
+{
+ fn len(&self) -> usize {
+ self.rows.len()
+ }
+}
+
+impl<P: Pixel> Clone for EnumerateRows<'_, P> {
+ fn clone(&self) -> Self {
+ EnumerateRows {
+ rows: self.rows.clone(),
+ ..*self
+ }
+ }
+}
+
+impl<P: Pixel> fmt::Debug for EnumerateRows<'_, P>
+where
+ P::Subpixel: fmt::Debug,
+{
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("EnumerateRows")
+ .field("rows", &self.rows)
+ .field("y", &self.y)
+ .field("width", &self.width)
+ .finish()
+ }
+}
+
+/// Enumerate the pixels of an image.
+pub struct EnumeratePixelsMut<'a, P: Pixel + 'a>
+where
+ <P as Pixel>::Subpixel: 'a,
+{
+ pixels: PixelsMut<'a, P>,
+ x: u32,
+ y: u32,
+ width: u32,
+}
+
+impl<'a, P: Pixel + 'a> Iterator for EnumeratePixelsMut<'a, P>
+where
+ P::Subpixel: 'a,
+{
+ type Item = (u32, u32, &'a mut P);
+
+ #[inline(always)]
+ fn next(&mut self) -> Option<(u32, u32, &'a mut P)> {
+ if self.x >= self.width {
+ self.x = 0;
+ self.y += 1;
+ }
+ let (x, y) = (self.x, self.y);
+ self.x += 1;
+ self.pixels.next().map(|p| (x, y, p))
+ }
+
+ #[inline(always)]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let len = self.len();
+ (len, Some(len))
+ }
+}
+
+impl<'a, P: Pixel + 'a> ExactSizeIterator for EnumeratePixelsMut<'a, P>
+where
+ P::Subpixel: 'a,
+{
+ fn len(&self) -> usize {
+ self.pixels.len()
+ }
+}
+
+impl<P: Pixel> fmt::Debug for EnumeratePixelsMut<'_, P>
+where
+ P::Subpixel: fmt::Debug,
+{
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("EnumeratePixelsMut")
+ .field("pixels", &self.pixels)
+ .field("x", &self.x)
+ .field("y", &self.y)
+ .field("width", &self.width)
+ .finish()
+ }
+}
+
+/// Enumerate the rows of an image.
+pub struct EnumerateRowsMut<'a, P: Pixel + 'a>
+where
+ <P as Pixel>::Subpixel: 'a,
+{
+ rows: RowsMut<'a, P>,
+ y: u32,
+ width: u32,
+}
+
+impl<'a, P: Pixel + 'a> Iterator for EnumerateRowsMut<'a, P>
+where
+ P::Subpixel: 'a,
+{
+ type Item = (u32, EnumeratePixelsMut<'a, P>);
+
+ #[inline(always)]
+ fn next(&mut self) -> Option<(u32, EnumeratePixelsMut<'a, P>)> {
+ let y = self.y;
+ self.y += 1;
+ self.rows.next().map(|r| {
+ (
+ y,
+ EnumeratePixelsMut {
+ x: 0,
+ y,
+ width: self.width,
+ pixels: r,
+ },
+ )
+ })
+ }
+
+ #[inline(always)]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let len = self.len();
+ (len, Some(len))
+ }
+}
+
+impl<'a, P: Pixel + 'a> ExactSizeIterator for EnumerateRowsMut<'a, P>
+where
+ P::Subpixel: 'a,
+{
+ fn len(&self) -> usize {
+ self.rows.len()
+ }
+}
+
+impl<P: Pixel> fmt::Debug for EnumerateRowsMut<'_, P>
+where
+ P::Subpixel: fmt::Debug,
+{
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("EnumerateRowsMut")
+ .field("rows", &self.rows)
+ .field("y", &self.y)
+ .field("width", &self.width)
+ .finish()
+ }
+}
+
+/// Generic image buffer
+///
+/// This is an image parameterised by its Pixel types, represented by a width and height and a
+/// container of channel data. It provides direct access to its pixels and implements the
+/// [`GenericImageView`] and [`GenericImage`] traits. In many ways, this is the standard buffer
+/// implementing those traits. Using this concrete type instead of a generic type parameter has
+/// been shown to improve performance.
+///
+/// The crate defines a few type aliases with regularly used pixel types for your convenience, such
+/// as [`RgbImage`], [`GrayImage`] etc.
+///
+/// [`GenericImage`]: trait.GenericImage.html
+/// [`GenericImageView`]: trait.GenericImageView.html
+/// [`RgbImage`]: type.RgbImage.html
+/// [`GrayImage`]: type.GrayImage.html
+///
+/// To convert between images of different Pixel types use [`DynamicImage`].
+///
+/// You can retrieve a complete description of the buffer's layout and contents through
+/// [`as_flat_samples`] and [`as_flat_samples_mut`]. This can be handy to also use the contents in
+/// a foreign language, map it as a GPU host buffer or other similar tasks.
+///
+/// [`DynamicImage`]: enum.DynamicImage.html
+/// [`as_flat_samples`]: #method.as_flat_samples
+/// [`as_flat_samples_mut`]: #method.as_flat_samples_mut
+///
+/// ## Examples
+///
+/// Create a simple canvas and paint a small cross.
+///
+/// ```
+/// use image::{RgbImage, Rgb};
+///
+/// let mut img = RgbImage::new(32, 32);
+///
+/// for x in 15..=17 {
+/// for y in 8..24 {
+/// img.put_pixel(x, y, Rgb([255, 0, 0]));
+/// img.put_pixel(y, x, Rgb([255, 0, 0]));
+/// }
+/// }
+/// ```
+///
+/// Overlays an image on top of a larger background raster.
+///
+/// ```no_run
+/// use image::{GenericImage, GenericImageView, ImageBuffer, open};
+///
+/// let on_top = open("path/to/some.png").unwrap().into_rgb8();
+/// let mut img = ImageBuffer::from_fn(512, 512, |x, y| {
+/// if (x + y) % 2 == 0 {
+/// image::Rgb([0, 0, 0])
+/// } else {
+/// image::Rgb([255, 255, 255])
+/// }
+/// });
+///
+/// image::imageops::overlay(&mut img, &on_top, 128, 128);
+/// ```
+///
+/// Convert an RgbaImage to a GrayImage.
+///
+/// ```no_run
+/// use image::{open, DynamicImage};
+///
+/// let rgba = open("path/to/some.png").unwrap().into_rgba8();
+/// let gray = DynamicImage::ImageRgba8(rgba).into_luma8();
+/// ```
+#[derive(Debug, Hash, PartialEq, Eq)]
+pub struct ImageBuffer<P: Pixel, Container> {
+ width: u32,
+ height: u32,
+ _phantom: PhantomData<P>,
+ data: Container,
+}
+
+// generic implementation, shared along all image buffers
+impl<P, Container> ImageBuffer<P, Container>
+where
+ P: Pixel,
+ Container: Deref<Target = [P::Subpixel]>,
+{
+ /// Constructs a buffer from a generic container
+ /// (for example a `Vec` or a slice)
+ ///
+ /// Returns `None` if the container is not big enough (including when the image dimensions
+ /// necessitate an allocation of more bytes than supported by the container).
+ pub fn from_raw(width: u32, height: u32, buf: Container) -> Option<ImageBuffer<P, Container>> {
+ if Self::check_image_fits(width, height, buf.len()) {
+ Some(ImageBuffer {
+ data: buf,
+ width,
+ height,
+ _phantom: PhantomData,
+ })
+ } else {
+ None
+ }
+ }
+
+ /// Returns the underlying raw buffer
+ pub fn into_raw(self) -> Container {
+ self.data
+ }
+
+ /// Returns the underlying raw buffer
+ pub fn as_raw(&self) -> &Container {
+ &self.data
+ }
+
+ /// The width and height of this image.
+ pub fn dimensions(&self) -> (u32, u32) {
+ (self.width, self.height)
+ }
+
+ /// The width of this image.
+ pub fn width(&self) -> u32 {
+ self.width
+ }
+
+ /// The height of this image.
+ pub fn height(&self) -> u32 {
+ self.height
+ }
+
+ // TODO: choose name under which to expose.
+ pub(crate) fn inner_pixels(&self) -> &[P::Subpixel] {
+ let len = Self::image_buffer_len(self.width, self.height).unwrap();
+ &self.data[..len]
+ }
+
+ /// Returns an iterator over the pixels of this image.
+ /// The iteration order is x = 0 to width then y = 0 to height
+ pub fn pixels(&self) -> Pixels<P> {
+ Pixels {
+ chunks: self
+ .inner_pixels()
+ .chunks_exact(<P as Pixel>::CHANNEL_COUNT as usize),
+ }
+ }
+
+ /// Returns an iterator over the rows of this image.
+ ///
+ /// Only non-empty rows can be iterated in this manner. In particular the iterator will not
+ /// yield any item when the width of the image is `0` or a pixel type without any channels is
+ /// used. This ensures that its length can always be represented by `usize`.
+ pub fn rows(&self) -> Rows<P> {
+ Rows::with_image(&self.data, self.width, self.height)
+ }
+
+ /// Enumerates over the pixels of the image.
+ /// The iterator yields the coordinates of each pixel
+ /// along with a reference to them.
+ /// The iteration order is x = 0 to width then y = 0 to height
+ /// Starting from the top left.
+ pub fn enumerate_pixels(&self) -> EnumeratePixels<P> {
+ EnumeratePixels {
+ pixels: self.pixels(),
+ x: 0,
+ y: 0,
+ width: self.width,
+ }
+ }
+
+ /// Enumerates over the rows of the image.
+ /// The iterator yields the y-coordinate of each row
+ /// along with a reference to them.
+ pub fn enumerate_rows(&self) -> EnumerateRows<P> {
+ EnumerateRows {
+ rows: self.rows(),
+ y: 0,
+ width: self.width,
+ }
+ }
+
+ /// Gets a reference to the pixel at location `(x, y)`
+ ///
+ /// # Panics
+ ///
+ /// Panics if `(x, y)` is out of the bounds `(width, height)`.
+ #[inline]
+ #[track_caller]
+ pub fn get_pixel(&self, x: u32, y: u32) -> &P {
+ match self.pixel_indices(x, y) {
+ None => panic!(
+ "Image index {:?} out of bounds {:?}",
+ (x, y),
+ (self.width, self.height)
+ ),
+ Some(pixel_indices) => <P as Pixel>::from_slice(&self.data[pixel_indices]),
+ }
+ }
+
+ /// Gets a reference to the pixel at location `(x, y)` or returns `None` if
+ /// the index is out of the bounds `(width, height)`.
+ pub fn get_pixel_checked(&self, x: u32, y: u32) -> Option<&P> {
+ if x >= self.width {
+ return None;
+ }
+ let num_channels = <P as Pixel>::CHANNEL_COUNT as usize;
+ let i = (y as usize)
+ .saturating_mul(self.width as usize)
+ .saturating_add(x as usize)
+ .saturating_mul(num_channels);
+
+ self.data
+ .get(i..i + num_channels)
+ .map(|pixel_indices| <P as Pixel>::from_slice(pixel_indices))
+ }
+
+ /// Test that the image fits inside the buffer.
+ ///
+ /// Verifies that the maximum image of pixels inside the bounds is smaller than the provided
+ /// length. Note that as a corrolary we also have that the index calculation of pixels inside
+ /// the bounds will not overflow.
+ fn check_image_fits(width: u32, height: u32, len: usize) -> bool {
+ let checked_len = Self::image_buffer_len(width, height);
+ checked_len.map(|min_len| min_len <= len).unwrap_or(false)
+ }
+
+ fn image_buffer_len(width: u32, height: u32) -> Option<usize> {
+ Some(<P as Pixel>::CHANNEL_COUNT as usize)
+ .and_then(|size| size.checked_mul(width as usize))
+ .and_then(|size| size.checked_mul(height as usize))
+ }
+
+ #[inline(always)]
+ fn pixel_indices(&self, x: u32, y: u32) -> Option<Range<usize>> {
+ if x >= self.width || y >= self.height {
+ return None;
+ }
+
+ Some(self.pixel_indices_unchecked(x, y))
+ }
+
+ #[inline(always)]
+ fn pixel_indices_unchecked(&self, x: u32, y: u32) -> Range<usize> {
+ let no_channels = <P as Pixel>::CHANNEL_COUNT as usize;
+ // If in bounds, this can't overflow as we have tested that at construction!
+ let min_index = (y as usize * self.width as usize + x as usize) * no_channels;
+ min_index..min_index + no_channels
+ }
+
+ /// Get the format of the buffer when viewed as a matrix of samples.
+ pub fn sample_layout(&self) -> SampleLayout {
+ // None of these can overflow, as all our memory is addressable.
+ SampleLayout::row_major_packed(<P as Pixel>::CHANNEL_COUNT, self.width, self.height)
+ }
+
+ /// Return the raw sample buffer with its stride an dimension information.
+ ///
+ /// The returned buffer is guaranteed to be well formed in all cases. It is laid out by
+ /// colors, width then height, meaning `channel_stride <= width_stride <= height_stride`. All
+ /// strides are in numbers of elements but those are mostly `u8` in which case the strides are
+ /// also byte strides.
+ pub fn into_flat_samples(self) -> FlatSamples<Container>
+ where
+ Container: AsRef<[P::Subpixel]>,
+ {
+ // None of these can overflow, as all our memory is addressable.
+ let layout = self.sample_layout();
+ FlatSamples {
+ samples: self.data,
+ layout,
+ color_hint: None, // TODO: the pixel type might contain P::COLOR_TYPE if it satisfies PixelWithColorType
+ }
+ }
+
+ /// Return a view on the raw sample buffer.
+ ///
+ /// See [`into_flat_samples`](#method.into_flat_samples) for more details.
+ pub fn as_flat_samples(&self) -> FlatSamples<&[P::Subpixel]>
+ where
+ Container: AsRef<[P::Subpixel]>,
+ {
+ let layout = self.sample_layout();
+ FlatSamples {
+ samples: self.data.as_ref(),
+ layout,
+ color_hint: None, // TODO: the pixel type might contain P::COLOR_TYPE if it satisfies PixelWithColorType
+ }
+ }
+
+ /// Return a mutable view on the raw sample buffer.
+ ///
+ /// See [`into_flat_samples`](#method.into_flat_samples) for more details.
+ pub fn as_flat_samples_mut(&mut self) -> FlatSamples<&mut [P::Subpixel]>
+ where
+ Container: AsMut<[P::Subpixel]>,
+ {
+ let layout = self.sample_layout();
+ FlatSamples {
+ samples: self.data.as_mut(),
+ layout,
+ color_hint: None, // TODO: the pixel type might contain P::COLOR_TYPE if it satisfies PixelWithColorType
+ }
+ }
+}
+
+impl<P, Container> ImageBuffer<P, Container>
+where
+ P: Pixel,
+ Container: Deref<Target = [P::Subpixel]> + DerefMut,
+{
+ // TODO: choose name under which to expose.
+ fn inner_pixels_mut(&mut self) -> &mut [P::Subpixel] {
+ let len = Self::image_buffer_len(self.width, self.height).unwrap();
+ &mut self.data[..len]
+ }
+
+ /// Returns an iterator over the mutable pixels of this image.
+ pub fn pixels_mut(&mut self) -> PixelsMut<P> {
+ PixelsMut {
+ chunks: self
+ .inner_pixels_mut()
+ .chunks_exact_mut(<P as Pixel>::CHANNEL_COUNT as usize),
+ }
+ }
+
+ /// Returns an iterator over the mutable rows of this image.
+ ///
+ /// Only non-empty rows can be iterated in this manner. In particular the iterator will not
+ /// yield any item when the width of the image is `0` or a pixel type without any channels is
+ /// used. This ensures that its length can always be represented by `usize`.
+ pub fn rows_mut(&mut self) -> RowsMut<P> {
+ RowsMut::with_image(&mut self.data, self.width, self.height)
+ }
+
+ /// Enumerates over the pixels of the image.
+ /// The iterator yields the coordinates of each pixel
+ /// along with a mutable reference to them.
+ pub fn enumerate_pixels_mut(&mut self) -> EnumeratePixelsMut<P> {
+ let width = self.width;
+ EnumeratePixelsMut {
+ pixels: self.pixels_mut(),
+ x: 0,
+ y: 0,
+ width,
+ }
+ }
+
+ /// Enumerates over the rows of the image.
+ /// The iterator yields the y-coordinate of each row
+ /// along with a mutable reference to them.
+ pub fn enumerate_rows_mut(&mut self) -> EnumerateRowsMut<P> {
+ let width = self.width;
+ EnumerateRowsMut {
+ rows: self.rows_mut(),
+ y: 0,
+ width,
+ }
+ }
+
+ /// Gets a reference to the mutable pixel at location `(x, y)`
+ ///
+ /// # Panics
+ ///
+ /// Panics if `(x, y)` is out of the bounds `(width, height)`.
+ #[inline]
+ #[track_caller]
+ pub fn get_pixel_mut(&mut self, x: u32, y: u32) -> &mut P {
+ match self.pixel_indices(x, y) {
+ None => panic!(
+ "Image index {:?} out of bounds {:?}",
+ (x, y),
+ (self.width, self.height)
+ ),
+ Some(pixel_indices) => <P as Pixel>::from_slice_mut(&mut self.data[pixel_indices]),
+ }
+ }
+
+ /// Gets a reference to the mutable pixel at location `(x, y)` or returns
+ /// `None` if the index is out of the bounds `(width, height)`.
+ pub fn get_pixel_mut_checked(&mut self, x: u32, y: u32) -> Option<&mut P> {
+ if x >= self.width {
+ return None;
+ }
+ let num_channels = <P as Pixel>::CHANNEL_COUNT as usize;
+ let i = (y as usize)
+ .saturating_mul(self.width as usize)
+ .saturating_add(x as usize)
+ .saturating_mul(num_channels);
+
+ self.data
+ .get_mut(i..i + num_channels)
+ .map(|pixel_indices| <P as Pixel>::from_slice_mut(pixel_indices))
+ }
+
+ /// Puts a pixel at location `(x, y)`
+ ///
+ /// # Panics
+ ///
+ /// Panics if `(x, y)` is out of the bounds `(width, height)`.
+ #[inline]
+ #[track_caller]
+ pub fn put_pixel(&mut self, x: u32, y: u32, pixel: P) {
+ *self.get_pixel_mut(x, y) = pixel
+ }
+}
+
+impl<P, Container> ImageBuffer<P, Container>
+where
+ P: Pixel,
+ [P::Subpixel]: EncodableLayout,
+ Container: Deref<Target = [P::Subpixel]>,
+{
+ /// 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>,
+ P: PixelWithColorType,
+ {
+ save_buffer(
+ path,
+ self.inner_pixels().as_bytes(),
+ self.width(),
+ self.height(),
+ <P as PixelWithColorType>::COLOR_TYPE,
+ )
+ }
+}
+
+impl<P, Container> ImageBuffer<P, Container>
+where
+ P: Pixel,
+ [P::Subpixel]: EncodableLayout,
+ Container: Deref<Target = [P::Subpixel]>,
+{
+ /// 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>,
+ P: PixelWithColorType,
+ {
+ // This is valid as the subpixel is u8.
+ save_buffer_with_format(
+ path,
+ self.inner_pixels().as_bytes(),
+ self.width(),
+ self.height(),
+ <P as PixelWithColorType>::COLOR_TYPE,
+ format,
+ )
+ }
+}
+
+impl<P, Container> ImageBuffer<P, Container>
+where
+ P: Pixel,
+ [P::Subpixel]: EncodableLayout,
+ Container: Deref<Target = [P::Subpixel]>,
+{
+ /// Writes the buffer to a writer in the specified format.
+ ///
+ /// Assumes the writer is buffered. In most cases,
+ /// you should wrap your writer in a `BufWriter` for best performance.
+ ///
+ /// See [`ImageOutputFormat`](enum.ImageOutputFormat.html) for
+ /// supported types.
+ pub fn write_to<W, F>(&self, writer: &mut W, format: F) -> ImageResult<()>
+ where
+ W: std::io::Write + std::io::Seek,
+ F: Into<ImageOutputFormat>,
+ P: PixelWithColorType,
+ {
+ // This is valid as the subpixel is u8.
+ write_buffer_with_format(
+ writer,
+ self.inner_pixels().as_bytes(),
+ self.width(),
+ self.height(),
+ <P as PixelWithColorType>::COLOR_TYPE,
+ format,
+ )
+ }
+}
+
+impl<P, Container> ImageBuffer<P, Container>
+where
+ P: Pixel,
+ [P::Subpixel]: EncodableLayout,
+ Container: Deref<Target = [P::Subpixel]>,
+{
+ /// Writes the buffer with the given encoder.
+ pub fn write_with_encoder<E>(&self, encoder: E) -> ImageResult<()>
+ where
+ E: ImageEncoder,
+ P: PixelWithColorType,
+ {
+ // This is valid as the subpixel is u8.
+ encoder.write_image(
+ self.inner_pixels().as_bytes(),
+ self.width(),
+ self.height(),
+ <P as PixelWithColorType>::COLOR_TYPE,
+ )
+ }
+}
+
+impl<P, Container> Default for ImageBuffer<P, Container>
+where
+ P: Pixel,
+ Container: Default,
+{
+ fn default() -> Self {
+ Self {
+ width: 0,
+ height: 0,
+ _phantom: PhantomData,
+ data: Default::default(),
+ }
+ }
+}
+
+impl<P, Container> Deref for ImageBuffer<P, Container>
+where
+ P: Pixel,
+ Container: Deref<Target = [P::Subpixel]>,
+{
+ type Target = [P::Subpixel];
+
+ fn deref(&self) -> &<Self as Deref>::Target {
+ &self.data
+ }
+}
+
+impl<P, Container> DerefMut for ImageBuffer<P, Container>
+where
+ P: Pixel,
+ Container: Deref<Target = [P::Subpixel]> + DerefMut,
+{
+ fn deref_mut(&mut self) -> &mut <Self as Deref>::Target {
+ &mut self.data
+ }
+}
+
+impl<P, Container> Index<(u32, u32)> for ImageBuffer<P, Container>
+where
+ P: Pixel,
+ Container: Deref<Target = [P::Subpixel]>,
+{
+ type Output = P;
+
+ fn index(&self, (x, y): (u32, u32)) -> &P {
+ self.get_pixel(x, y)
+ }
+}
+
+impl<P, Container> IndexMut<(u32, u32)> for ImageBuffer<P, Container>
+where
+ P: Pixel,
+ Container: Deref<Target = [P::Subpixel]> + DerefMut,
+{
+ fn index_mut(&mut self, (x, y): (u32, u32)) -> &mut P {
+ self.get_pixel_mut(x, y)
+ }
+}
+
+impl<P, Container> Clone for ImageBuffer<P, Container>
+where
+ P: Pixel,
+ Container: Deref<Target = [P::Subpixel]> + Clone,
+{
+ fn clone(&self) -> ImageBuffer<P, Container> {
+ ImageBuffer {
+ data: self.data.clone(),
+ width: self.width,
+ height: self.height,
+ _phantom: PhantomData,
+ }
+ }
+}
+
+impl<P, Container> GenericImageView for ImageBuffer<P, Container>
+where
+ P: Pixel,
+ Container: Deref<Target = [P::Subpixel]> + Deref,
+{
+ type Pixel = P;
+
+ fn dimensions(&self) -> (u32, u32) {
+ self.dimensions()
+ }
+
+ fn bounds(&self) -> (u32, u32, u32, u32) {
+ (0, 0, self.width, self.height)
+ }
+
+ fn get_pixel(&self, x: u32, y: u32) -> P {
+ *self.get_pixel(x, y)
+ }
+
+ /// Returns the pixel located at (x, y), ignoring bounds checking.
+ #[inline(always)]
+ unsafe fn unsafe_get_pixel(&self, x: u32, y: u32) -> P {
+ let indices = self.pixel_indices_unchecked(x, y);
+ *<P as Pixel>::from_slice(self.data.get_unchecked(indices))
+ }
+}
+
+impl<P, Container> GenericImage for ImageBuffer<P, Container>
+where
+ P: Pixel,
+ Container: Deref<Target = [P::Subpixel]> + DerefMut,
+{
+ fn get_pixel_mut(&mut self, x: u32, y: u32) -> &mut P {
+ self.get_pixel_mut(x, y)
+ }
+
+ fn put_pixel(&mut self, x: u32, y: u32, pixel: P) {
+ *self.get_pixel_mut(x, y) = pixel
+ }
+
+ /// Puts a pixel at location (x, y), ignoring bounds checking.
+ #[inline(always)]
+ unsafe fn unsafe_put_pixel(&mut self, x: u32, y: u32, pixel: P) {
+ let indices = self.pixel_indices_unchecked(x, y);
+ let p = <P as Pixel>::from_slice_mut(self.data.get_unchecked_mut(indices));
+ *p = pixel
+ }
+
+ /// Put a pixel at location (x, y), taking into account alpha channels
+ ///
+ /// DEPRECATED: This method will be removed. Blend the pixel directly instead.
+ fn blend_pixel(&mut self, x: u32, y: u32, p: P) {
+ self.get_pixel_mut(x, y).blend(&p)
+ }
+
+ fn copy_within(&mut self, source: Rect, x: u32, y: u32) -> bool {
+ let Rect {
+ x: sx,
+ y: sy,
+ width,
+ height,
+ } = source;
+ let dx = x;
+ let dy = y;
+ assert!(sx < self.width() && dx < self.width());
+ assert!(sy < self.height() && dy < self.height());
+ if self.width() - dx.max(sx) < width || self.height() - dy.max(sy) < height {
+ return false;
+ }
+
+ if sy < dy {
+ for y in (0..height).rev() {
+ let sy = sy + y;
+ let dy = dy + y;
+ let Range { start, .. } = self.pixel_indices_unchecked(sx, sy);
+ let Range { end, .. } = self.pixel_indices_unchecked(sx + width - 1, sy);
+ let dst = self.pixel_indices_unchecked(dx, dy).start;
+ self.data.copy_within(start..end, dst);
+ }
+ } else {
+ for y in 0..height {
+ let sy = sy + y;
+ let dy = dy + y;
+ let Range { start, .. } = self.pixel_indices_unchecked(sx, sy);
+ let Range { end, .. } = self.pixel_indices_unchecked(sx + width - 1, sy);
+ let dst = self.pixel_indices_unchecked(dx, dy).start;
+ self.data.copy_within(start..end, dst);
+ }
+ }
+ true
+ }
+}
+
+// concrete implementation for `Vec`-backed buffers
+// TODO: I think that rustc does not "see" this impl any more: the impl with
+// Container meets the same requirements. At least, I got compile errors that
+// there is no such function as `into_vec`, whereas `into_raw` did work, and
+// `into_vec` is redundant anyway, because `into_raw` will give you the vector,
+// and it is more generic.
+impl<P: Pixel> ImageBuffer<P, Vec<P::Subpixel>> {
+ /// Creates a new image buffer based on a `Vec<P::Subpixel>`.
+ ///
+ /// # Panics
+ ///
+ /// Panics when the resulting image is larger the the maximum size of a vector.
+ pub fn new(width: u32, height: u32) -> ImageBuffer<P, Vec<P::Subpixel>> {
+ let size = Self::image_buffer_len(width, height)
+ .expect("Buffer length in `ImageBuffer::new` overflows usize");
+ ImageBuffer {
+ data: vec![Zero::zero(); size],
+ width,
+ height,
+ _phantom: PhantomData,
+ }
+ }
+
+ /// Constructs a new ImageBuffer by copying a pixel
+ ///
+ /// # Panics
+ ///
+ /// Panics when the resulting image is larger the the maximum size of a vector.
+ pub fn from_pixel(width: u32, height: u32, pixel: P) -> ImageBuffer<P, Vec<P::Subpixel>> {
+ let mut buf = ImageBuffer::new(width, height);
+ for p in buf.pixels_mut() {
+ *p = pixel
+ }
+ buf
+ }
+
+ /// Constructs a new ImageBuffer by repeated application of the supplied function.
+ ///
+ /// The arguments to the function are the pixel's x and y coordinates.
+ ///
+ /// # Panics
+ ///
+ /// Panics when the resulting image is larger the the maximum size of a vector.
+ pub fn from_fn<F>(width: u32, height: u32, mut f: F) -> ImageBuffer<P, Vec<P::Subpixel>>
+ where
+ F: FnMut(u32, u32) -> P,
+ {
+ let mut buf = ImageBuffer::new(width, height);
+ for (x, y, p) in buf.enumerate_pixels_mut() {
+ *p = f(x, y)
+ }
+ buf
+ }
+
+ /// Creates an image buffer out of an existing buffer.
+ /// Returns None if the buffer is not big enough.
+ pub fn from_vec(
+ width: u32,
+ height: u32,
+ buf: Vec<P::Subpixel>,
+ ) -> Option<ImageBuffer<P, Vec<P::Subpixel>>> {
+ ImageBuffer::from_raw(width, height, buf)
+ }
+
+ /// Consumes the image buffer and returns the underlying data
+ /// as an owned buffer
+ pub fn into_vec(self) -> Vec<P::Subpixel> {
+ self.into_raw()
+ }
+}
+
+/// Provides color conversions for whole image buffers.
+pub trait ConvertBuffer<T> {
+ /// Converts `self` to a buffer of type T
+ ///
+ /// A generic implementation is provided to convert any image buffer to a image buffer
+ /// based on a `Vec<T>`.
+ fn convert(&self) -> T;
+}
+
+// concrete implementation Luma -> Rgba
+impl GrayImage {
+ /// Expands a color palette by re-using the existing buffer.
+ /// Assumes 8 bit per pixel. Uses an optionally transparent index to
+ /// adjust it's alpha value accordingly.
+ pub fn expand_palette(
+ self,
+ palette: &[(u8, u8, u8)],
+ transparent_idx: Option<u8>,
+ ) -> RgbaImage {
+ let (width, height) = self.dimensions();
+ let mut data = self.into_raw();
+ let entries = data.len();
+ data.resize(entries.checked_mul(4).unwrap(), 0);
+ let mut buffer = ImageBuffer::from_vec(width, height, data).unwrap();
+ expand_packed(&mut buffer, 4, 8, |idx, pixel| {
+ let (r, g, b) = palette[idx as usize];
+ let a = if let Some(t_idx) = transparent_idx {
+ if t_idx == idx {
+ 0
+ } else {
+ 255
+ }
+ } else {
+ 255
+ };
+ pixel[0] = r;
+ pixel[1] = g;
+ pixel[2] = b;
+ pixel[3] = a;
+ });
+ buffer
+ }
+}
+
+// TODO: Equality constraints are not yet supported in where clauses, when they
+// are, the T parameter should be removed in favor of ToType::Subpixel, which
+// will then be FromType::Subpixel.
+impl<Container, FromType: Pixel, ToType: Pixel>
+ ConvertBuffer<ImageBuffer<ToType, Vec<ToType::Subpixel>>> for ImageBuffer<FromType, Container>
+where
+ Container: Deref<Target = [FromType::Subpixel]>,
+ ToType: FromColor<FromType>,
+{
+ /// # Examples
+ /// Convert RGB image to gray image.
+ /// ```no_run
+ /// use image::buffer::ConvertBuffer;
+ /// use image::GrayImage;
+ ///
+ /// let image_path = "examples/fractal.png";
+ /// let image = image::open(&image_path)
+ /// .expect("Open file failed")
+ /// .to_rgba8();
+ ///
+ /// let gray_image: GrayImage = image.convert();
+ /// ```
+ fn convert(&self) -> ImageBuffer<ToType, Vec<ToType::Subpixel>> {
+ let mut buffer: ImageBuffer<ToType, Vec<ToType::Subpixel>> =
+ ImageBuffer::new(self.width, self.height);
+ for (to, from) in buffer.pixels_mut().zip(self.pixels()) {
+ to.from_color(from)
+ }
+ buffer
+ }
+}
+
+/// Sendable Rgb image buffer
+pub type RgbImage = ImageBuffer<Rgb<u8>, Vec<u8>>;
+/// Sendable Rgb + alpha channel image buffer
+pub type RgbaImage = ImageBuffer<Rgba<u8>, Vec<u8>>;
+/// Sendable grayscale image buffer
+pub type GrayImage = ImageBuffer<Luma<u8>, Vec<u8>>;
+/// Sendable grayscale + alpha channel image buffer
+pub type GrayAlphaImage = ImageBuffer<LumaA<u8>, Vec<u8>>;
+/// Sendable 16-bit Rgb image buffer
+pub(crate) type Rgb16Image = ImageBuffer<Rgb<u16>, Vec<u16>>;
+/// Sendable 16-bit Rgb + alpha channel image buffer
+pub(crate) type Rgba16Image = ImageBuffer<Rgba<u16>, Vec<u16>>;
+/// Sendable 16-bit grayscale image buffer
+pub(crate) type Gray16Image = ImageBuffer<Luma<u16>, Vec<u16>>;
+/// Sendable 16-bit grayscale + alpha channel image buffer
+pub(crate) type GrayAlpha16Image = ImageBuffer<LumaA<u16>, Vec<u16>>;
+
+/// An image buffer for 32-bit float RGB pixels,
+/// where the backing container is a flattened vector of floats.
+pub type Rgb32FImage = ImageBuffer<Rgb<f32>, Vec<f32>>;
+
+/// An image buffer for 32-bit float RGBA pixels,
+/// where the backing container is a flattened vector of floats.
+pub type Rgba32FImage = ImageBuffer<Rgba<f32>, Vec<f32>>;
+
+#[cfg(test)]
+mod test {
+ use super::{GrayImage, ImageBuffer, ImageOutputFormat, RgbImage};
+ use crate::math::Rect;
+ use crate::GenericImage as _;
+ use crate::{color, Rgb};
+
+ #[test]
+ /// Tests if image buffers from slices work
+ fn slice_buffer() {
+ let data = [0; 9];
+ let buf: ImageBuffer<color::Luma<u8>, _> = ImageBuffer::from_raw(3, 3, &data[..]).unwrap();
+ assert_eq!(&*buf, &data[..])
+ }
+
+ #[test]
+ fn get_pixel() {
+ let mut a: RgbImage = ImageBuffer::new(10, 10);
+ {
+ let b = a.get_mut(3 * 10).unwrap();
+ *b = 255;
+ }
+ assert_eq!(a.get_pixel(0, 1)[0], 255)
+ }
+
+ #[test]
+ fn get_pixel_checked() {
+ let mut a: RgbImage = ImageBuffer::new(10, 10);
+ a.get_pixel_mut_checked(0, 1).map(|b| b[0] = 255);
+
+ assert_eq!(a.get_pixel_checked(0, 1), Some(&Rgb([255, 0, 0])));
+ assert_eq!(a.get_pixel_checked(0, 1).unwrap(), a.get_pixel(0, 1));
+ assert_eq!(a.get_pixel_checked(10, 0), None);
+ assert_eq!(a.get_pixel_checked(0, 10), None);
+ assert_eq!(a.get_pixel_mut_checked(10, 0), None);
+ assert_eq!(a.get_pixel_mut_checked(0, 10), None);
+
+ // From image/issues/1672
+ const WHITE: Rgb<u8> = Rgb([255_u8, 255, 255]);
+ let mut a = RgbImage::new(2, 1);
+ a.put_pixel(1, 0, WHITE);
+
+ assert_eq!(a.get_pixel_checked(1, 0), Some(&WHITE));
+ assert_eq!(a.get_pixel_checked(1, 0).unwrap(), a.get_pixel(1, 0));
+ }
+
+ #[test]
+ fn mut_iter() {
+ let mut a: RgbImage = ImageBuffer::new(10, 10);
+ {
+ let val = a.pixels_mut().next().unwrap();
+ *val = Rgb([42, 0, 0]);
+ }
+ assert_eq!(a.data[0], 42)
+ }
+
+ #[test]
+ fn zero_width_zero_height() {
+ let mut image = RgbImage::new(0, 0);
+
+ assert_eq!(image.rows_mut().count(), 0);
+ assert_eq!(image.pixels_mut().count(), 0);
+ assert_eq!(image.rows().count(), 0);
+ assert_eq!(image.pixels().count(), 0);
+ }
+
+ #[test]
+ fn zero_width_nonzero_height() {
+ let mut image = RgbImage::new(0, 2);
+
+ assert_eq!(image.rows_mut().count(), 0);
+ assert_eq!(image.pixels_mut().count(), 0);
+ assert_eq!(image.rows().count(), 0);
+ assert_eq!(image.pixels().count(), 0);
+ }
+
+ #[test]
+ fn nonzero_width_zero_height() {
+ let mut image = RgbImage::new(2, 0);
+
+ assert_eq!(image.rows_mut().count(), 0);
+ assert_eq!(image.pixels_mut().count(), 0);
+ assert_eq!(image.rows().count(), 0);
+ assert_eq!(image.pixels().count(), 0);
+ }
+
+ #[test]
+ fn pixels_on_large_buffer() {
+ let mut image = RgbImage::from_raw(1, 1, vec![0; 6]).unwrap();
+
+ assert_eq!(image.pixels().count(), 1);
+ assert_eq!(image.enumerate_pixels().count(), 1);
+ assert_eq!(image.pixels_mut().count(), 1);
+ assert_eq!(image.enumerate_pixels_mut().count(), 1);
+
+ assert_eq!(image.rows().count(), 1);
+ assert_eq!(image.rows_mut().count(), 1);
+ }
+
+ #[test]
+ fn default() {
+ let image = ImageBuffer::<Rgb<u8>, Vec<u8>>::default();
+ assert_eq!(image.dimensions(), (0, 0));
+ }
+
+ #[test]
+ #[rustfmt::skip]
+ fn test_image_buffer_copy_within_oob() {
+ let mut image: GrayImage = ImageBuffer::from_raw(4, 4, vec![0u8; 16]).unwrap();
+ assert!(!image.copy_within(Rect { x: 0, y: 0, width: 5, height: 4 }, 0, 0));
+ assert!(!image.copy_within(Rect { x: 0, y: 0, width: 4, height: 5 }, 0, 0));
+ assert!(!image.copy_within(Rect { x: 1, y: 0, width: 4, height: 4 }, 0, 0));
+ assert!(!image.copy_within(Rect { x: 0, y: 0, width: 4, height: 4 }, 1, 0));
+ assert!(!image.copy_within(Rect { x: 0, y: 1, width: 4, height: 4 }, 0, 0));
+ assert!(!image.copy_within(Rect { x: 0, y: 0, width: 4, height: 4 }, 0, 1));
+ assert!(!image.copy_within(Rect { x: 1, y: 1, width: 4, height: 4 }, 0, 0));
+ }
+
+ #[test]
+ fn test_image_buffer_copy_within_tl() {
+ let data = &[
+ 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, 15,
+ ];
+ let expected = [
+ 00, 01, 02, 03, 04, 00, 01, 02, 08, 04, 05, 06, 12, 08, 09, 10,
+ ];
+ let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap();
+ assert!(image.copy_within(
+ Rect {
+ x: 0,
+ y: 0,
+ width: 3,
+ height: 3
+ },
+ 1,
+ 1
+ ));
+ assert_eq!(&image.into_raw(), &expected);
+ }
+
+ #[test]
+ fn test_image_buffer_copy_within_tr() {
+ let data = &[
+ 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, 15,
+ ];
+ let expected = [
+ 00, 01, 02, 03, 01, 02, 03, 07, 05, 06, 07, 11, 09, 10, 11, 15,
+ ];
+ let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap();
+ assert!(image.copy_within(
+ Rect {
+ x: 1,
+ y: 0,
+ width: 3,
+ height: 3
+ },
+ 0,
+ 1
+ ));
+ assert_eq!(&image.into_raw(), &expected);
+ }
+
+ #[test]
+ fn test_image_buffer_copy_within_bl() {
+ let data = &[
+ 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, 15,
+ ];
+ let expected = [
+ 00, 04, 05, 06, 04, 08, 09, 10, 08, 12, 13, 14, 12, 13, 14, 15,
+ ];
+ let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap();
+ assert!(image.copy_within(
+ Rect {
+ x: 0,
+ y: 1,
+ width: 3,
+ height: 3
+ },
+ 1,
+ 0
+ ));
+ assert_eq!(&image.into_raw(), &expected);
+ }
+
+ #[test]
+ fn test_image_buffer_copy_within_br() {
+ let data = &[
+ 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, 15,
+ ];
+ let expected = [
+ 05, 06, 07, 03, 09, 10, 11, 07, 13, 14, 15, 11, 12, 13, 14, 15,
+ ];
+ let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap();
+ assert!(image.copy_within(
+ Rect {
+ x: 1,
+ y: 1,
+ width: 3,
+ height: 3
+ },
+ 0,
+ 0
+ ));
+ assert_eq!(&image.into_raw(), &expected);
+ }
+
+ #[test]
+ #[cfg(feature = "png")]
+ fn write_to_with_large_buffer() {
+ // A buffer of 1 pixel, padded to 4 bytes as would be common in, e.g. BMP.
+ let img: GrayImage = ImageBuffer::from_raw(1, 1, vec![0u8; 4]).unwrap();
+ let mut buffer = std::io::Cursor::new(vec![]);
+ assert!(img.write_to(&mut buffer, ImageOutputFormat::Png).is_ok());
+ }
+
+ #[test]
+ fn exact_size_iter_size_hint() {
+ // The docs for `std::iter::ExactSizeIterator` requires that the implementation of
+ // `size_hint` on the iterator returns the same value as the `len` implementation.
+
+ // This test should work for any size image.
+ const N: u32 = 10;
+
+ let mut image = RgbImage::from_raw(N, N, vec![0; (N * N * 3) as usize]).unwrap();
+
+ let iter = image.pixels();
+ let exact_len = ExactSizeIterator::len(&iter);
+ assert_eq!(iter.size_hint(), (exact_len, Some(exact_len)));
+
+ let iter = image.pixels_mut();
+ let exact_len = ExactSizeIterator::len(&iter);
+ assert_eq!(iter.size_hint(), (exact_len, Some(exact_len)));
+
+ let iter = image.rows();
+ let exact_len = ExactSizeIterator::len(&iter);
+ assert_eq!(iter.size_hint(), (exact_len, Some(exact_len)));
+
+ let iter = image.rows_mut();
+ let exact_len = ExactSizeIterator::len(&iter);
+ assert_eq!(iter.size_hint(), (exact_len, Some(exact_len)));
+
+ let iter = image.enumerate_pixels();
+ let exact_len = ExactSizeIterator::len(&iter);
+ assert_eq!(iter.size_hint(), (exact_len, Some(exact_len)));
+
+ let iter = image.enumerate_rows();
+ let exact_len = ExactSizeIterator::len(&iter);
+ assert_eq!(iter.size_hint(), (exact_len, Some(exact_len)));
+
+ let iter = image.enumerate_pixels_mut();
+ let exact_len = ExactSizeIterator::len(&iter);
+ assert_eq!(iter.size_hint(), (exact_len, Some(exact_len)));
+
+ let iter = image.enumerate_rows_mut();
+ let exact_len = ExactSizeIterator::len(&iter);
+ assert_eq!(iter.size_hint(), (exact_len, Some(exact_len)));
+ }
+}
+
+#[cfg(test)]
+#[cfg(feature = "benchmarks")]
+mod benchmarks {
+ use super::{ConvertBuffer, GrayImage, ImageBuffer, Pixel, RgbImage};
+ use crate::GenericImage;
+ use test;
+
+ #[bench]
+ fn conversion(b: &mut test::Bencher) {
+ let mut a: RgbImage = ImageBuffer::new(1000, 1000);
+ for p in a.pixels_mut() {
+ let rgb = p.channels_mut();
+ rgb[0] = 255;
+ rgb[1] = 23;
+ rgb[2] = 42;
+ }
+ assert!(a.data[0] != 0);
+ b.iter(|| {
+ let b: GrayImage = a.convert();
+ assert!(0 != b.data[0]);
+ assert!(a.data[0] != b.data[0]);
+ test::black_box(b);
+ });
+ b.bytes = 1000 * 1000 * 3
+ }
+
+ #[bench]
+ fn image_access_row_by_row(b: &mut test::Bencher) {
+ let mut a: RgbImage = ImageBuffer::new(1000, 1000);
+ for p in a.pixels_mut() {
+ let rgb = p.channels_mut();
+ rgb[0] = 255;
+ rgb[1] = 23;
+ rgb[2] = 42;
+ }
+
+ b.iter(move || {
+ let image: &RgbImage = test::black_box(&a);
+ let mut sum: usize = 0;
+ for y in 0..1000 {
+ for x in 0..1000 {
+ let pixel = image.get_pixel(x, y);
+ sum = sum.wrapping_add(pixel[0] as usize);
+ sum = sum.wrapping_add(pixel[1] as usize);
+ sum = sum.wrapping_add(pixel[2] as usize);
+ }
+ }
+ test::black_box(sum)
+ });
+
+ b.bytes = 1000 * 1000 * 3;
+ }
+
+ #[bench]
+ fn image_access_col_by_col(b: &mut test::Bencher) {
+ let mut a: RgbImage = ImageBuffer::new(1000, 1000);
+ for p in a.pixels_mut() {
+ let rgb = p.channels_mut();
+ rgb[0] = 255;
+ rgb[1] = 23;
+ rgb[2] = 42;
+ }
+
+ b.iter(move || {
+ let image: &RgbImage = test::black_box(&a);
+ let mut sum: usize = 0;
+ for x in 0..1000 {
+ for y in 0..1000 {
+ let pixel = image.get_pixel(x, y);
+ sum = sum.wrapping_add(pixel[0] as usize);
+ sum = sum.wrapping_add(pixel[1] as usize);
+ sum = sum.wrapping_add(pixel[2] as usize);
+ }
+ }
+ test::black_box(sum)
+ });
+
+ b.bytes = 1000 * 1000 * 3;
+ }
+}