diff --git a/src/codecs/bmp/decoder.rs b/src/codecs/bmp/decoder.rs index 7cefbebae5..7d09996f1c 100644 --- a/src/codecs/bmp/decoder.rs +++ b/src/codecs/bmp/decoder.rs @@ -1234,6 +1234,10 @@ impl BmpDecoder { pub(crate) fn reader(&mut self) -> &mut R { &mut self.reader } + #[cfg(feature = "ico")] + pub(crate) fn bit_count(&self) -> u16 { + self.bit_count + } fn read_file_header(&mut self) -> ImageResult<()> { if self.no_file_header { diff --git a/src/codecs/ico/decoder.rs b/src/codecs/ico/decoder.rs index a738632d82..6ede7cfd12 100644 --- a/src/codecs/ico/decoder.rs +++ b/src/codecs/ico/decoder.rs @@ -371,6 +371,12 @@ impl ImageDecoder for IcoDecoder { decoder.read_image_data(buf)?; + // For further processing, use the bits per pixel from the BMP. + // The data in the ICON dir entry is not generally trustworthy, but the data from + // the BMP header just correctly decoded an image. Using the data from the BMP + // header also eliminates any mismatches between the BMP header and the ICON dir entry. + let bit_count = decoder.bit_count(); + let r = decoder.reader(); let image_end = r.stream_position()?; let data_end = self.reader_offset @@ -395,7 +401,7 @@ impl ImageDecoder for IcoDecoder { // 32bpp BMPs already have a native alpha channel, so the // AND mask is ignored. // For lower bit depths, read and apply the AND mask. - if self.selected_entry.bits_per_pixel < 32 { + if bit_count < 32 { let rgba = buf.as_chunks_mut::<4>().0; let rows = rgba.chunks_exact_mut(width as usize); @@ -431,9 +437,7 @@ impl ImageDecoder for IcoDecoder { } else if data_end == image_end { // accept images with no mask data Ok(DecodedImageAttributes::default()) - } else if self.spec_strictness == SpecCompliance::Lenient - && self.selected_entry.bits_per_pixel >= 32 - { + } else if self.spec_strictness == SpecCompliance::Lenient && bit_count >= 32 { // In lenient mode, we accept truncated mask data for 32bpp images // since they already have an alpha channel and we ignore the AND mask anyway. Ok(DecodedImageAttributes::default()) diff --git a/tests/images/ico/images/bmp-32bpp-conflicting-and-mask-reported-as-8bpp.ico b/tests/images/ico/images/bmp-32bpp-conflicting-and-mask-reported-as-8bpp.ico new file mode 100644 index 0000000000..a75ba41752 Binary files /dev/null and b/tests/images/ico/images/bmp-32bpp-conflicting-and-mask-reported-as-8bpp.ico differ diff --git a/tests/reference/ico/images/bmp-32bpp-conflicting-and-mask-reported-as-8bpp.ico.png b/tests/reference/ico/images/bmp-32bpp-conflicting-and-mask-reported-as-8bpp.ico.png new file mode 100644 index 0000000000..2b93672d51 Binary files /dev/null and b/tests/reference/ico/images/bmp-32bpp-conflicting-and-mask-reported-as-8bpp.ico.png differ