image_blend/alpha_ops.rs
1use std::{iter::zip, ops::{Deref, DerefMut}};
2
3use image::{ImageBuffer, Pixel};
4use num_traits::{Bounded, NumCast};
5
6use crate::{blend_ops::{dims_match, type_max}, enums::ColorStructure, error::Error};
7
8pub trait BufferGetAlpha<P, Container>
9where
10 P: Pixel,
11 Container: DerefMut<Target = [P::Subpixel]> + AsRef<[<P as Pixel>::Subpixel]>
12{
13 /**
14 Get the alpha channel of this image as a grayscale with the same number of channels as the input image. (i.e a 4 channel rgba image will return a 3 channel rgba grayscale image)
15
16 The alpha channel of the returned image is set to the maximum value of the input type.
17
18 If the image does not have an alpha channel, return None.
19
20
21 # Examples
22
23 ```
24 use image::open;
25 use image_blend::{BufferGetAlpha, BufferSetAlpha};
26
27 // Load an image and get its alpha channel
28 let img1_dynamic = open("test_data/1.png").unwrap();
29 let img1_buffer = img1_dynamic.as_rgba8().unwrap();
30 let img1_alpha = img1_buffer.get_alpha().unwrap();
31 img1_alpha.clone().save("tests_out/doctest_buffer_getalpha_alpha.png").unwrap();
32
33 // Load another image and set its alpha channel to the first image's alpha channel, using the copied alpha channel
34 let mut img2_dynamic = open("test_data/2.png").unwrap();
35 let mut img2_buffer = img2_dynamic.to_rgba16();
36 img2_buffer.set_alpha(&img1_alpha).unwrap();
37 img2_buffer.save("tests_out/doctest_buffer_getalpha_result.png").unwrap();
38
39 ```
40 */
41 fn get_alpha(
42 &self
43 ) -> Option<Self> where Self: std::marker::Sized;
44}
45impl<P, Container> BufferGetAlpha<P, Container> for ImageBuffer<P, Container>
46where
47 P: Pixel,
48 Container: DerefMut<Target = [P::Subpixel]> + AsRef<[<P as Pixel>::Subpixel]> + Clone
49{
50 fn get_alpha(
51 &self,
52 ) -> Option<Self> {
53 let color_structure: ColorStructure = self.sample_layout().try_into().ok()?;
54 if !color_structure.alpha() {
55 return None;
56 }
57 let color_channels = if color_structure.rgb() {
58 vec![0, 1, 2]
59 } else {
60 vec![0]
61 };
62 let alpha_channel = color_structure.alpha_channel().unwrap();
63 let mut alpha = self.clone();
64
65 let max: <P as Pixel>::Subpixel = NumCast::from(type_max::<P>()).unwrap();
66 zip(alpha.pixels_mut(), self.pixels()).for_each(|(px_luma, px)| {
67 // Don't need to cast here because we know the types are the same
68 let alpha_val = px.channels()[alpha_channel];
69 let px_channels = px_luma.channels_mut();
70 for ch in color_channels.clone() {
71 px_channels[ch] = alpha_val;
72 }
73 px_channels[alpha_channel] = max;
74 });
75 Some(alpha)
76 }
77}
78pub trait BufferSetAlpha<P, Container>
79where
80 P: Pixel,
81 Container: Deref<Target = [P::Subpixel]> + AsRef<[P::Subpixel]>,
82{
83 /**
84 Set an image's alpha channel using the grascale color of another image.
85
86 Handles type conversion and alpha channel detection and placement automatically.
87
88 WARNING: `other` can be of any type, but only the first channel will be used to set the alpha channel. In a grayscale image this will be the luma channel, in an rgb image the red channel. Consider converting to grayscale if this matters. In a grayscale image this will be the luma channel, in an rgb image the red channel.
89
90 # Errors
91 `NoAlphaChannel`: `self` does not have an alpha channel
92
93 `DimensionMismatch`: `self` and `other` have different dimensions
94
95
96 # Examples
97
98 ```
99 use image::open;
100 use image_blend::{BufferGetAlpha, BufferSetAlpha};
101
102 // Load an image and get its alpha channel
103 let img1_dynamic = open("test_data/1.png").unwrap();
104 let img1_buffer = img1_dynamic.as_rgba8().unwrap();
105 let img1_alpha = img1_buffer.get_alpha().unwrap();
106 img1_alpha.clone().save("tests_out/doctest_buffer_setalpha_alpha.png").unwrap();
107
108 // Load another image and set its alpha channel to the first image's alpha channel, using the copied alpha channel
109 let mut img2_dynamic = open("test_data/2.png").unwrap();
110 let mut img2_buffer = img2_dynamic.to_rgba16();
111 img2_buffer.set_alpha(&img1_alpha).unwrap();
112 img2_buffer.save("tests_out/doctest_buffer_setalpha_result.png").unwrap();
113
114 ```
115 */
116 fn set_alpha(
117 &mut self,
118 other: &ImageBuffer<P, Container>
119 ) -> Result<(), Error>;
120
121 /**
122 Set an image's alpha channel from another images alpha channel.
123
124 Handles type conversion and alpha channel placement automatically.
125
126 # Errors
127 `NoAlphaChannel`: `self` or `other` does not have an alpha channel
128
129 `DimensionMismatch`: `self` and `other` have different dimensions
130
131
132 # Examples
133
134 ```
135 use image::open;
136 use image_blend::{BufferGetAlpha, BufferSetAlpha};
137
138 // Load an image that has an alpha channel
139 let img1_dynamic = open("test_data/1.png").unwrap();
140 let img1_buffer = img1_dynamic.as_rgba8().unwrap();
141
142 // Load another image and set its alpha channel to a copy of the first image's alpha channel.
143 let mut img2_dynamic = open("test_data/2.png").unwrap();
144 let mut img2_buffer = img2_dynamic.to_rgba16();
145 img2_buffer.transplant_alpha(&img1_buffer).unwrap();
146 img2_buffer.save("tests_out/doctest_buffer_transplantalpha_result.png").unwrap();
147 ```
148 */
149 fn transplant_alpha(
150 &mut self,
151 other: &ImageBuffer<P, Container>
152 ) -> Result<(), Error>;
153}
154impl<P, Pmut, Container, ContainerMut> BufferSetAlpha<P, Container> for ImageBuffer<Pmut, ContainerMut>
155where
156 Pmut: Pixel,
157 P: Pixel,
158 Container: Deref<Target = [P::Subpixel]> + AsRef<[<P as Pixel>::Subpixel]>,
159 ContainerMut: DerefMut<Target = [Pmut::Subpixel]>
160 + DerefMut<Target = [Pmut::Subpixel]>
161 + AsMut<[<Pmut as Pixel>::Subpixel]>
162{
163 fn set_alpha(
164 &mut self,
165 other: &ImageBuffer<P, Container>,
166 ) -> Result<(), Error> {
167 dims_match(self, other)?;
168 let structure_a: ColorStructure = self.sample_layout().try_into()?;
169 let alpha_channel = structure_a.alpha_channel().ok_or(Error::NoAlphaChannel)?;
170
171 let a_max = type_max::<Pmut>();
172 let b_max = type_max::<P>();
173
174 zip(self.pixels_mut(), other.pixels()).for_each(|(px, px_luma)| {
175 // Need to cast here because there is no guarantee P and Pmut are the same type
176 let px_luma_64: f64 = <f64 as NumCast>::from(px_luma.channels()[0]).unwrap() / b_max;
177 let alpha: <Pmut as Pixel>::Subpixel = NumCast::from(px_luma_64 * a_max).unwrap();
178 px.channels_mut()[alpha_channel] = alpha;
179 });
180 Ok(())
181 }
182 fn transplant_alpha(
183 &mut self,
184 other: &ImageBuffer<P, Container>
185 ) -> Result<(), Error> {
186 dims_match(self, other)?;
187 let structure_a: ColorStructure = self.sample_layout().try_into()?;
188 let structure_b: ColorStructure = other.sample_layout().try_into()?;
189
190 let alpha_a = structure_a.alpha_channel().ok_or(Error::NoAlphaChannel)?;
191 let alpha_b = structure_b.alpha_channel().ok_or(Error::NoAlphaChannel)?;
192
193 let a_max = type_max::<Pmut>();
194 let b_max = type_max::<P>();
195
196 zip(self.pixels_mut(), other.pixels()).for_each(|(pxa, pxb)| {
197 // Need to cast here because there is no guarantee P and Pmut are the same type
198 let float_b: f64 = <f64 as NumCast>::from(pxb.channels()[alpha_b]).unwrap() / b_max;
199 let alpha: <Pmut as Pixel>::Subpixel = NumCast::from(float_b * a_max).unwrap();
200 pxa.channels_mut()[alpha_a] = alpha;
201 });
202 Ok(())
203 }
204}
205pub trait BufferStripAlpha<Pmut, ContainerMut>
206where
207 Pmut: Pixel,
208 ContainerMut: DerefMut<Target = [Pmut::Subpixel]>
209 + AsMut<[<Pmut as Pixel>::Subpixel]>
210
211{
212 /**
213 Remove this images alpha channel by setting it to the maximum value for every pixel.
214
215 Does not modify the underlying type.
216
217
218 # Errors
219 `NoAlphaChannel`: `self` does not have an alpha channel
220
221
222 # Examples
223
224 ```
225 use image::open;
226 use image_blend::{BufferStripAlpha};
227
228 // Load an image and remove its alpha channel
229 let mut img2_dynamic = open("test_data/2.png").unwrap();
230 let mut img2_buffer = img2_dynamic.to_rgba16();
231 img2_buffer.strip_alpha().unwrap();
232 img2_buffer.save("tests_out/doctest_buffer_stripalpha_result.png").unwrap();
233 ```
234 */
235 fn strip_alpha(
236 &mut self
237 ) -> Result<(), Error>;
238}
239impl <Pmut, ContainerMut> BufferStripAlpha<Pmut, ContainerMut> for ImageBuffer<Pmut, ContainerMut>
240where
241 Pmut: Pixel,
242 ContainerMut: DerefMut<Target = [Pmut::Subpixel]>
243 + AsMut<[<Pmut as Pixel>::Subpixel]>
244{
245 fn strip_alpha(
246 &mut self
247 ) -> Result<(), Error> {
248 let structure: ColorStructure = self.sample_layout().try_into()?;
249 let alpha_channel = structure.alpha_channel().ok_or(Error::NoAlphaChannel)?;
250 let max = <Pmut as Pixel>::Subpixel::max_value();
251 self.pixels_mut().for_each(|px| {
252 px.channels_mut()[alpha_channel] = max;
253 });
254 Ok(())
255 }
256}