@@ -888,6 +888,25 @@ where
888888 color_hint : None , // TODO: the pixel type might contain P::COLOR_TYPE if it satisfies PixelWithColorType
889889 }
890890 }
891+
892+ /// Extract the alpha channel as a Luma image.
893+ ///
894+ /// If the pixel does not have an alpha channel, the value is filled with a fully opaque mask
895+ /// using the maximum value of the corresponding subpixel type.
896+ pub fn to_alpha_mask ( & self ) -> ImageBuffer < Luma < P :: Subpixel > , Vec < P :: Subpixel > > {
897+ let pixels = self . inner_pixels ( ) . chunks_exact ( P :: CHANNEL_COUNT . into ( ) ) ;
898+ let mut mask = vec ! [ <P :: Subpixel as crate :: Primitive >:: DEFAULT_MAX_VALUE ; pixels. len( ) ] ;
899+
900+ if P :: HAS_ALPHA {
901+ for ( p, alpha) in pixels. zip ( mask. iter_mut ( ) ) {
902+ // If the pixel has an alpha channel, use it.
903+ * alpha = * p. last ( ) . unwrap ( ) ;
904+ }
905+ }
906+
907+ ImageBuffer :: from_vec ( self . width , self . height , mask)
908+ . expect ( "used the right pixel and channel count" )
909+ }
891910}
892911
893912impl < P , Container > ImageBuffer < P , Container >
@@ -989,6 +1008,42 @@ where
9891008 pub fn put_pixel ( & mut self , x : u32 , y : u32 , pixel : P ) {
9901009 * self . get_pixel_mut ( x, y) = pixel;
9911010 }
1011+
1012+ /// Fill the alpha channel of this image from a Luma mask.
1013+ ///
1014+ /// Returns an [`ImageError::Parameter`] if the mask dimensions do not match the image
1015+ /// dimensions. Otherwise, if the pixel type does not have an alpha channel this is a no-op.
1016+ pub fn apply_alpha_mask < RhsContainer > (
1017+ & mut self ,
1018+ mask : & ImageBuffer < Luma < P :: Subpixel > , RhsContainer > ,
1019+ ) -> ImageResult < ( ) >
1020+ where
1021+ RhsContainer : Deref < Target = [ P :: Subpixel ] > ,
1022+ {
1023+ if ( self . width , self . height ) != ( mask. width ( ) , mask. height ( ) ) {
1024+ return Err ( ImageError :: Parameter ( ParameterError :: from_kind (
1025+ ParameterErrorKind :: DimensionMismatch ,
1026+ ) ) ) ;
1027+ }
1028+
1029+ if !P :: HAS_ALPHA {
1030+ return Err ( ImageError :: Parameter ( ParameterError :: from_kind (
1031+ ParameterErrorKind :: NoAlphaChannel ,
1032+ ) ) ) ;
1033+ }
1034+
1035+ let pixels = self
1036+ . inner_pixels_mut ( )
1037+ . chunks_exact_mut ( P :: CHANNEL_COUNT . into ( ) ) ;
1038+
1039+ let mask = mask. inner_pixels ( ) ;
1040+ for ( p, alpha) in pixels. zip ( mask. iter ( ) ) {
1041+ // If the pixel has an alpha channel, use it.
1042+ * p. last_mut ( ) . unwrap ( ) = * alpha;
1043+ }
1044+
1045+ Ok ( ( ) )
1046+ }
9921047}
9931048
9941049impl < P : Pixel , Container > ImageBuffer < P , Container > {
@@ -2114,6 +2169,27 @@ mod test {
21142169 let result = target. copy_from_color_space ( & source, options) ;
21152170 assert ! ( matches!( result, Err ( crate :: ImageError :: Parameter ( _) ) ) ) ;
21162171 }
2172+
2173+ #[ test]
2174+ fn alpha_mask_of_gray ( ) {
2175+ let image: GrayImage = ImageBuffer :: new ( 4 , 4 ) ;
2176+ let mask = image. to_alpha_mask ( ) ;
2177+ assert_eq ! ( mask. as_raw( ) , & [ 255 ; 16 ] ) ;
2178+ }
2179+
2180+ #[ test]
2181+ #[ rustfmt:: skip]
2182+ fn alpha_mask_extraction ( ) {
2183+ let image: ImageBuffer < LumaA < u8 > , _ > = ImageBuffer :: from_raw ( 4 , 4 , vec ! [
2184+ 0 , 1 , 0 , 2 , 0 , 3 , 0 , 4 ,
2185+ 0 , 5 , 0 , 6 , 0 , 7 , 0 , 8 ,
2186+ 0 , 9 , 0 , 10 , 0 , 11 , 0 , 12 ,
2187+ 0 , 13 , 0 , 14 , 0 , 15 , 0 , 16 ,
2188+ ] ) . unwrap ( ) ;
2189+
2190+ let mask = image. to_alpha_mask ( ) ;
2191+ assert_eq ! ( mask. as_raw( ) , & ( 1u8 ..17 ) . collect:: <Vec <_>>( ) ) ;
2192+ }
21172193}
21182194
21192195#[ cfg( test) ]
0 commit comments