image_merger/
core.rs

1use std::ops::{Deref, DerefMut};
2
3use image::{ImageBuffer, ImageFormat, Luma, LumaA, Pixel, Rgb, Rgba};
4
5/// Represents an image that can be passed to the merger. This is a wrapper around an image crate's GenericImage
6/// and adds some additional functionality for the merger.
7/// # Type Parameters
8/// * `P` - The pixel type of the underlying image.
9/// * `U` - The underlying image type.
10/// # Example
11/// ```
12/// use image_merger::{Image, Rgba};
13/// use image::ImageBuffer;
14///
15/// let image: Image<Rgba<u8>, ImageBuffer<Rgba<u8>, Vec<u8>>> = Image::new(100, 100);
16/// assert_eq!(image.capacity(), 100 * 100 * 4);
17/// ```
18/// Note that this is for example, in practicality, you should use the [BufferedImage](crate::BufferedImage) type alias.
19#[derive(Debug, Hash, PartialEq, Eq)]
20pub struct Image<P: Pixel, U: image::GenericImage<Pixel = P>> {
21    underlying: U,
22}
23
24impl<P: Pixel, U: image::GenericImage<Pixel = P>> Image<P, U> {
25    /// Returns the capacity of the underlying image's data buffer.
26    pub fn capacity(&self) -> usize {
27        return self.underlying.pixels().count() * <P as Pixel>::CHANNEL_COUNT as usize;
28    }
29
30    /// Consumes the image and returns the underlying image buffer.
31    pub fn into_buffer(self) -> U {
32        self.underlying
33    }
34}
35
36impl<P, Container> Image<P, ImageBuffer<P, Container>>
37where
38    P: Pixel,
39    Container: DerefMut<Target = [P::Subpixel]>,
40{
41    /// Creates a new image from a raw buffer. The buffer must be large enough to fit the image. Normally, you should use the
42    /// `new` method to create a new image, as it is more idiomatic, unless you need to manually create an image from a raw buffer.
43    ///
44    /// # Arguments
45    /// * `width` - The width of the image.
46    /// * `height` - The height of the image.
47    /// * `container` - The raw buffer to create the image from.
48    ///
49    /// # Returns
50    /// An [Image](Image) with the given pixel and buffer type. Will return None if the buffer is not large enough to fit the image.
51    pub fn new_from_raw(width: u32, height: u32, container: Container) -> Option<Self> {
52        ImageBuffer::from_raw(width, height, container).map(|image| Self { underlying: image })
53    }
54}
55
56impl<P: Pixel> Image<P, ImageBuffer<P, Vec<P::Subpixel>>> {
57    /// Creates a new image with the given width and height.
58    pub fn new(width: u32, height: u32) -> Self {
59        Self {
60            underlying: ImageBuffer::new(width, height),
61        }
62    }
63
64    // Creates a new image from a given pixel, where the generated image will have the given width and height,
65    // and the image will have the color of the pixel.
66    pub fn new_from_pixel(width: u32, height: u32, pixel: P) -> Self {
67        Self {
68            underlying: ImageBuffer::from_pixel(width, height, pixel),
69        }
70    }
71}
72
73/// Dereferences to the underlying image.
74///
75/// # Type Parameters
76/// * `P` - The pixel type of the underlying image.
77/// * `U` - The underlying image type.
78///
79/// # Example
80/// ```
81/// use image_merger::{Image, Rgba, BufferedImage};
82/// use image::ImageBuffer;
83///
84/// let image: BufferedImage<Rgba<u8>> = BufferedImage::new(100, 100);
85/// let underlying: &ImageBuffer<Rgba<u8>, Vec<u8>> = &*image;
86/// ```
87impl<P: Pixel, U: image::GenericImage<Pixel = P>> Deref for Image<P, U> {
88    type Target = U;
89
90    fn deref(&self) -> &Self::Target {
91        &self.underlying
92    }
93}
94
95impl<P: Pixel, U: image::GenericImage<Pixel = P>> DerefMut for Image<P, U> {
96    fn deref_mut(&mut self) -> &mut Self::Target {
97        &mut self.underlying
98    }
99}
100
101/// A trait that allows the creation of an [Image](Image) from a preexisting [image::ImageBuffer](image::ImageBuffer).
102///
103/// # Type Parameters
104/// * `P` - The pixel type of the underlying image.
105/// * `Container` - The underlying image buffer type. This must be dereferenceable to a slice of the underlying image's subpixels.
106///
107/// # Example
108/// ```
109/// use image_merger::{Image, Rgba, BufferedImage};
110/// use image::ImageBuffer;
111///
112/// let buf: ImageBuffer<Rgba<u8>, Vec<u8>> = ImageBuffer::new(100, 100);
113/// let image: BufferedImage<Rgba<u8>> = BufferedImage::from(buf);
114/// ```
115impl<P, Container> From<ImageBuffer<P, Container>> for Image<P, ImageBuffer<P, Container>>
116where
117    P: Pixel,
118    Container: DerefMut<Target = [P::Subpixel]>,
119{
120    /// Creates a new Image from a preexisting ImageBuffer.
121    /// # Arguments
122    /// * `image` - The ImageBuffer to create an Image from.
123    fn from(image: ImageBuffer<P, Container>) -> Self {
124        Self { underlying: image }
125    }
126}
127
128/// A trait that allows the creation of an Image from a container of bytes using a specified image format.
129/// # Type Parameters
130/// * `Container` - The container type. This must be dereferenceable to a slice of bytes.
131pub trait FromWithFormat<Container>
132where
133    Container: Deref<Target = [u8]>,
134{
135    /// Transforms the given container and image format into an Image.
136    /// # Arguments
137    /// * `container` - The container to transform into an Image.
138    /// * `format` - The format of the image.
139    /// # Returns
140    /// An [Image](Image) with the given pixel and buffer type.
141    /// # Panics
142    /// This function will panic if the given container cannot be transformed into an image with the given format.
143    /// # Example
144    /// ```no_run
145    /// use image_merger::{FromWithFormat, Image, Rgba, BufferedImage};
146    /// use image::ImageBuffer;
147    ///
148    /// let container = vec![0, 0, 0, 255, 255, 255, 255, 255];
149    /// let image: BufferedImage<Rgba<u8>> = BufferedImage::from_with_format(container, image::ImageFormat::Png);
150    /// ```
151    fn from_with_format(container: Container, format: ImageFormat) -> Self;
152}
153
154macro_rules! impl_from_with_format {
155    ($px_type:ident, $channel_type:ty, $to_fn:ident) => {
156        #[doc = concat!(
157            r#"Implementation of [`FromWithFormat`](FromWithFormat) for an [`Image`](Image) with a pixel type of [`"#,
158            stringify!($px_type),
159            "`](image::",
160            stringify!($px_type),
161            "), holding a subpixel type of [`",
162            stringify!($channel_type),
163            r#"`]("#
164            , stringify!($channel_type),
165            r#") and an underlying [`ImageBuffer`](image::ImageBuffer) buffer that holds `Vec<"#,
166            stringify!($channel_type),
167            r#">`'s.
168        "#)]
169        impl<Container> FromWithFormat<Container>
170            for Image<
171                $px_type<$channel_type>,
172                ImageBuffer<$px_type<$channel_type>, Vec<$channel_type>>,
173            >
174        where
175            Container: Deref<Target = [u8]>,
176        {
177            fn from_with_format(container: Container, format: ImageFormat) -> Self {
178                let dyn_image = image::load_from_memory_with_format(&container, format).unwrap();
179                let img = dyn_image.$to_fn();
180
181                Self::from(img)
182            }
183        }
184    };
185}
186
187impl_from_with_format!(Rgb, u8, into_rgb8);
188impl_from_with_format!(Rgb, u16, into_rgb16);
189impl_from_with_format!(Rgb, f32, into_rgb32f);
190
191impl_from_with_format!(Rgba, u8, into_rgba8);
192impl_from_with_format!(Rgba, u16, into_rgba16);
193impl_from_with_format!(Rgba, f32, into_rgba32f);
194
195impl_from_with_format!(Luma, u8, into_luma8);
196impl_from_with_format!(Luma, u16, into_luma16);
197
198impl_from_with_format!(LumaA, u8, into_luma_alpha8);
199impl_from_with_format!(LumaA, u16, into_luma_alpha16);