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}