@@ -388,6 +388,15 @@ enum FormatFullBytes {
388388 Format888 ,
389389}
390390
391+ /// Compression type for bitfield-based formats.
392+ #[ derive( PartialEq , Copy , Clone ) ]
393+ enum BitfieldCompression {
394+ /// BI_BITFIELDS: RGB masks only (3 masks, 12 bytes after header).
395+ Rgb ,
396+ /// BI_ALPHABITFIELDS: RGBA masks (4 masks, 16 bytes after header).
397+ Rgba ,
398+ }
399+
391400enum Chunker < ' a > {
392401 FromTop ( ChunksExactMut < ' a , u8 > ) ,
393402 FromBottom ( Rev < ChunksExactMut < ' a , u8 > > ) ,
@@ -1126,12 +1135,11 @@ impl<R: BufRead + Seek> BmpDecoder<R> {
11261135 /// Read BITMAPINFOHEADER <https://msdn.microsoft.com/en-us/library/vs/alm/dd183376(v=vs.85).aspx>
11271136 /// or BITMAPV{2|3|4|5}HEADER.
11281137 ///
1129- /// returns Err if any of the values are invalid.
1130- fn read_bitmap_info_header ( & mut self ) -> ImageResult < ( ) > {
1138+ /// Returns the bitfield compression type or Err if any of the values are invalid.
1139+ fn read_bitmap_info_header ( & mut self ) -> ImageResult < BitfieldCompression > {
11311140 // Info header (after size field): 36 bytes minimum
11321141 let mut buffer = [ 0u8 ; 36 ] ;
11331142 self . reader . read_exact ( & mut buffer) ?;
1134-
11351143 let parsed = ParsedInfoHeader :: parse ( & buffer) ?;
11361144
11371145 self . width = parsed. width ;
@@ -1147,15 +1155,21 @@ impl<R: BufRead + Seek> BmpDecoder<R> {
11471155
11481156 check_for_overflow ( self . width , self . height , self . num_channels ( ) ) ?;
11491157
1150- Ok ( ( ) )
1158+ let compression = match parsed. compression {
1159+ BI_ALPHABITFIELDS => BitfieldCompression :: Rgba ,
1160+ _ => BitfieldCompression :: Rgb ,
1161+ } ;
1162+ Ok ( compression)
11511163 }
11521164
1153- fn read_bitmasks ( & mut self ) -> ImageResult < ( ) > {
1154- // Determine if we need to read alpha mask
1165+ fn read_bitmasks ( & mut self , compression : BitfieldCompression ) -> ImageResult < ( ) > {
1166+ // Determine if we need to read alpha mask:
1167+ // - V3/V4/V5 headers have the alpha mask embedded in the header
1168+ // - BI_ALPHABITFIELDS compression has a 4th mask after the header
11551169 let has_alpha = matches ! (
11561170 self . bmp_header_type,
11571171 BMPHeaderType :: V3 | BMPHeaderType :: V4 | BMPHeaderType :: V5
1158- ) ;
1172+ ) || compression == BitfieldCompression :: Rgba ;
11591173
11601174 // Read bitfield masks into buffer
11611175 let buffer_size = if has_alpha { 16 } else { 12 } ;
@@ -1337,35 +1351,40 @@ impl<R: BufRead + Seek> BmpDecoder<R> {
13371351 }
13381352 } ;
13391353
1340- match self . bmp_header_type {
1354+ let bitfield_compression = match self . bmp_header_type {
13411355 BMPHeaderType :: Core => {
13421356 self . read_bitmap_core_header ( ) ?;
1357+ BitfieldCompression :: Rgb
13431358 }
13441359 BMPHeaderType :: Info
13451360 | BMPHeaderType :: V2
13461361 | BMPHeaderType :: V3
13471362 | BMPHeaderType :: V4
1348- | BMPHeaderType :: V5 => {
1349- self . read_bitmap_info_header ( ) ?;
1350- }
1351- }
1363+ | BMPHeaderType :: V5 => self . read_bitmap_info_header ( ) ?,
1364+ } ;
13521365
13531366 let mut bitmask_bytes_offset = 0 ;
1354- if self . image_type == ImageType :: Bitfields16 || self . image_type == ImageType :: Bitfields32 {
1355- self . read_bitmasks ( ) ?;
1367+ if matches ! (
1368+ self . image_type,
1369+ ImageType :: Bitfields16 | ImageType :: Bitfields32
1370+ ) {
1371+ self . read_bitmasks ( bitfield_compression) ?;
13561372
13571373 // Per https://learn.microsoft.com/en-us/windows/win32/gdi/bitmap-header-types, bitmaps
13581374 // using the `BITMAPINFOHEADER`, `BITMAPV4HEADER`, or `BITMAPV5HEADER` structures with
1359- // an image type of `BI_BITFIELD` contain RGB bitfield masks immediately after the header.
1375+ // an image type of `BI_BITFIELD` or `BI_ALPHABITFIELDS` contain bitfield masks
1376+ // immediately after the header.
13601377 //
13611378 // `read_bitmasks` correctly reads these from earlier in the header itself but we must
13621379 // ensure the reader starts on the image data itself, not these extra mask bytes.
13631380 if matches ! (
13641381 self . bmp_header_type,
13651382 BMPHeaderType :: Info | BMPHeaderType :: V4 | BMPHeaderType :: V5
13661383 ) {
1367- // This is `size_of::<u32>() * 3` (a red, green, and blue mask), but with less noise.
1368- bitmask_bytes_offset = 12 ;
1384+ bitmask_bytes_offset = match bitfield_compression {
1385+ BitfieldCompression :: Rgba => 16 , // 4 masks * 4 bytes
1386+ BitfieldCompression :: Rgb => 12 , // 3 masks * 4 bytes
1387+ } ;
13691388 }
13701389 } ;
13711390
0 commit comments