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);