1use crate::utils::vec_try_with_capacity;
2use std::cmp::{self, Ordering};
3use std::io::{self, BufRead, Seek, SeekFrom};
4use std::iter::{repeat, Rev};
5use std::slice::ChunksExactMut;
6use std::{error, fmt};
7
8use byteorder_lite::{LittleEndian, ReadBytesExt};
9
10use crate::color::ColorType;
11use crate::error::{
12 DecodingError, ImageError, ImageResult, UnsupportedError, UnsupportedErrorKind,
13};
14use crate::io::free_functions::load_rect;
15use crate::io::ReadExt;
16use crate::{ImageDecoder, ImageDecoderRect, ImageFormat};
17
18const BITMAPCOREHEADER_SIZE: u32 = 12;
19const BITMAPINFOHEADER_SIZE: u32 = 40;
20const BITMAPV2HEADER_SIZE: u32 = 52;
21const BITMAPV3HEADER_SIZE: u32 = 56;
22const BITMAPV4HEADER_SIZE: u32 = 108;
23const BITMAPV5HEADER_SIZE: u32 = 124;
24
25static LOOKUP_TABLE_3_BIT_TO_8_BIT: [u8; 8] = [0, 36, 73, 109, 146, 182, 219, 255];
26static LOOKUP_TABLE_4_BIT_TO_8_BIT: [u8; 16] = [
27 0, 17, 34, 51, 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255,
28];
29static LOOKUP_TABLE_5_BIT_TO_8_BIT: [u8; 32] = [
30 0, 8, 16, 25, 33, 41, 49, 58, 66, 74, 82, 90, 99, 107, 115, 123, 132, 140, 148, 156, 165, 173,
31 181, 189, 197, 206, 214, 222, 230, 239, 247, 255,
32];
33static LOOKUP_TABLE_6_BIT_TO_8_BIT: [u8; 64] = [
34 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 45, 49, 53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 93,
35 97, 101, 105, 109, 113, 117, 121, 125, 130, 134, 138, 142, 146, 150, 154, 158, 162, 166, 170,
36 174, 178, 182, 186, 190, 194, 198, 202, 206, 210, 215, 219, 223, 227, 231, 235, 239, 243, 247,
37 251, 255,
38];
39
40static R5_G5_B5_COLOR_MASK: Bitfields = Bitfields {
41 r: Bitfield { len: 5, shift: 10 },
42 g: Bitfield { len: 5, shift: 5 },
43 b: Bitfield { len: 5, shift: 0 },
44 a: Bitfield { len: 0, shift: 0 },
45};
46const R8_G8_B8_COLOR_MASK: Bitfields = Bitfields {
47 r: Bitfield { len: 8, shift: 24 },
48 g: Bitfield { len: 8, shift: 16 },
49 b: Bitfield { len: 8, shift: 8 },
50 a: Bitfield { len: 0, shift: 0 },
51};
52const R8_G8_B8_A8_COLOR_MASK: Bitfields = Bitfields {
53 r: Bitfield { len: 8, shift: 16 },
54 g: Bitfield { len: 8, shift: 8 },
55 b: Bitfield { len: 8, shift: 0 },
56 a: Bitfield { len: 8, shift: 24 },
57};
58
59const RLE_ESCAPE: u8 = 0;
60const RLE_ESCAPE_EOL: u8 = 0;
61const RLE_ESCAPE_EOF: u8 = 1;
62const RLE_ESCAPE_DELTA: u8 = 2;
63
64const MAX_WIDTH_HEIGHT: i32 = 0xFFFF;
66
67#[derive(PartialEq, Copy, Clone)]
68enum ImageType {
69 Palette,
70 RGB16,
71 RGB24,
72 RGB32,
73 RGBA32,
74 RLE8,
75 RLE4,
76 Bitfields16,
77 Bitfields32,
78}
79
80#[derive(PartialEq)]
81enum BMPHeaderType {
82 Core,
83 Info,
84 V2,
85 V3,
86 V4,
87 V5,
88}
89
90#[derive(PartialEq)]
91enum FormatFullBytes {
92 RGB24,
93 RGB32,
94 RGBA32,
95 Format888,
96}
97
98enum Chunker<'a> {
99 FromTop(ChunksExactMut<'a, u8>),
100 FromBottom(Rev<ChunksExactMut<'a, u8>>),
101}
102
103pub(crate) struct RowIterator<'a> {
104 chunks: Chunker<'a>,
105}
106
107impl<'a> Iterator for RowIterator<'a> {
108 type Item = &'a mut [u8];
109
110 #[inline(always)]
111 fn next(&mut self) -> Option<&'a mut [u8]> {
112 match self.chunks {
113 Chunker::FromTop(ref mut chunks) => chunks.next(),
114 Chunker::FromBottom(ref mut chunks) => chunks.next(),
115 }
116 }
117}
118
119#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
121enum DecoderError {
122 CorruptRleData,
124
125 BitfieldMaskNonContiguous,
127 BitfieldMaskInvalid,
129 BitfieldMaskMissing(u32),
131 BitfieldMasksMissing(u32),
133
134 BmpSignatureInvalid,
136 MoreThanOnePlane,
138 InvalidChannelWidth(ChannelWidthError, u16),
140
141 NegativeWidth(i32),
143 ImageTooLarge(i32, i32),
145 InvalidHeight,
149
150 ImageTypeInvalidForTopDown(u32),
152 ImageTypeUnknown(u32),
154
155 HeaderTooSmall(u32),
157
158 PaletteSizeExceeded {
160 colors_used: u32,
161 bit_count: u16,
162 },
163}
164
165impl fmt::Display for DecoderError {
166 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
167 match self {
168 DecoderError::CorruptRleData => f.write_str("Corrupt RLE data"),
169 DecoderError::BitfieldMaskNonContiguous => f.write_str("Non-contiguous bitfield mask"),
170 DecoderError::BitfieldMaskInvalid => f.write_str("Invalid bitfield mask"),
171 DecoderError::BitfieldMaskMissing(bb) => {
172 f.write_fmt(format_args!("Missing {bb}-bit bitfield mask"))
173 }
174 DecoderError::BitfieldMasksMissing(bb) => {
175 f.write_fmt(format_args!("Missing {bb}-bit bitfield masks"))
176 }
177 DecoderError::BmpSignatureInvalid => f.write_str("BMP signature not found"),
178 DecoderError::MoreThanOnePlane => f.write_str("More than one plane"),
179 DecoderError::InvalidChannelWidth(tp, n) => {
180 f.write_fmt(format_args!("Invalid channel bit count for {tp}: {n}"))
181 }
182 DecoderError::NegativeWidth(w) => f.write_fmt(format_args!("Negative width ({w})")),
183 DecoderError::ImageTooLarge(w, h) => f.write_fmt(format_args!(
184 "Image too large (one of ({w}, {h}) > soft limit of {MAX_WIDTH_HEIGHT})"
185 )),
186 DecoderError::InvalidHeight => f.write_str("Invalid height"),
187 DecoderError::ImageTypeInvalidForTopDown(tp) => f.write_fmt(format_args!(
188 "Invalid image type {tp} for top-down image."
189 )),
190 DecoderError::ImageTypeUnknown(tp) => {
191 f.write_fmt(format_args!("Unknown image compression type {tp}"))
192 }
193 DecoderError::HeaderTooSmall(s) => {
194 f.write_fmt(format_args!("Bitmap header too small ({s} bytes)"))
195 }
196 DecoderError::PaletteSizeExceeded {
197 colors_used,
198 bit_count,
199 } => f.write_fmt(format_args!(
200 "Palette size {colors_used} exceeds maximum size for BMP with bit count of {bit_count}"
201 )),
202 }
203 }
204}
205
206impl From<DecoderError> for ImageError {
207 fn from(e: DecoderError) -> ImageError {
208 ImageError::Decoding(DecodingError::new(ImageFormat::Bmp.into(), e))
209 }
210}
211
212impl error::Error for DecoderError {}
213
214#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
216enum ChannelWidthError {
217 Rgb,
219 Rle8,
221 Rle4,
223 Bitfields,
225}
226
227impl fmt::Display for ChannelWidthError {
228 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
229 f.write_str(match self {
230 ChannelWidthError::Rgb => "RGB",
231 ChannelWidthError::Rle8 => "RLE8",
232 ChannelWidthError::Rle4 => "RLE4",
233 ChannelWidthError::Bitfields => "bitfields",
234 })
235 }
236}
237
238fn check_for_overflow(width: i32, length: i32, channels: usize) -> ImageResult<()> {
241 num_bytes(width, length, channels)
242 .map(|_| ())
243 .ok_or_else(|| {
244 ImageError::Unsupported(UnsupportedError::from_format_and_kind(
245 ImageFormat::Bmp.into(),
246 UnsupportedErrorKind::GenericFeature(format!(
247 "Image dimensions ({width}x{length} w/{channels} channels) are too large"
248 )),
249 ))
250 })
251}
252
253fn num_bytes(width: i32, length: i32, channels: usize) -> Option<usize> {
256 if width <= 0 || length <= 0 {
257 None
258 } else {
259 match channels.checked_mul(width as usize) {
260 Some(n) => n.checked_mul(length as usize),
261 None => None,
262 }
263 }
264}
265
266fn with_rows<F>(
269 buffer: &mut [u8],
270 width: i32,
271 height: i32,
272 channels: usize,
273 top_down: bool,
274 mut func: F,
275) -> io::Result<()>
276where
277 F: FnMut(&mut [u8]) -> io::Result<()>,
278{
279 let row_width = channels.checked_mul(width as usize).unwrap();
282 let full_image_size = row_width.checked_mul(height as usize).unwrap();
283 assert_eq!(buffer.len(), full_image_size);
284
285 if !top_down {
286 for row in buffer.chunks_mut(row_width).rev() {
287 func(row)?;
288 }
289 } else {
290 for row in buffer.chunks_mut(row_width) {
291 func(row)?;
292 }
293 }
294 Ok(())
295}
296
297fn set_8bit_pixel_run<'a, T: Iterator<Item = &'a u8>>(
298 pixel_iter: &mut ChunksExactMut<u8>,
299 palette: &[[u8; 3]],
300 indices: T,
301 n_pixels: usize,
302) -> bool {
303 for idx in indices.take(n_pixels) {
304 if let Some(pixel) = pixel_iter.next() {
305 let rgb = palette[*idx as usize];
306 pixel[0] = rgb[0];
307 pixel[1] = rgb[1];
308 pixel[2] = rgb[2];
309 } else {
310 return false;
311 }
312 }
313 true
314}
315
316fn set_4bit_pixel_run<'a, T: Iterator<Item = &'a u8>>(
317 pixel_iter: &mut ChunksExactMut<u8>,
318 palette: &[[u8; 3]],
319 indices: T,
320 mut n_pixels: usize,
321) -> bool {
322 for idx in indices {
323 macro_rules! set_pixel {
324 ($i:expr) => {
325 if n_pixels == 0 {
326 break;
327 }
328 if let Some(pixel) = pixel_iter.next() {
329 let rgb = palette[$i as usize];
330 pixel[0] = rgb[0];
331 pixel[1] = rgb[1];
332 pixel[2] = rgb[2];
333 } else {
334 return false;
335 }
336 n_pixels -= 1;
337 };
338 }
339 set_pixel!(idx >> 4);
340 set_pixel!(idx & 0xf);
341 }
342 true
343}
344
345#[rustfmt::skip]
346fn set_2bit_pixel_run<'a, T: Iterator<Item = &'a u8>>(
347 pixel_iter: &mut ChunksExactMut<u8>,
348 palette: &[[u8; 3]],
349 indices: T,
350 mut n_pixels: usize,
351) -> bool {
352 for idx in indices {
353 macro_rules! set_pixel {
354 ($i:expr) => {
355 if n_pixels == 0 {
356 break;
357 }
358 if let Some(pixel) = pixel_iter.next() {
359 let rgb = palette[$i as usize];
360 pixel[0] = rgb[0];
361 pixel[1] = rgb[1];
362 pixel[2] = rgb[2];
363 } else {
364 return false;
365 }
366 n_pixels -= 1;
367 };
368 }
369 set_pixel!((idx >> 6) & 0x3u8);
370 set_pixel!((idx >> 4) & 0x3u8);
371 set_pixel!((idx >> 2) & 0x3u8);
372 set_pixel!( idx & 0x3u8);
373 }
374 true
375}
376
377fn set_1bit_pixel_run<'a, T: Iterator<Item = &'a u8>>(
378 pixel_iter: &mut ChunksExactMut<u8>,
379 palette: &[[u8; 3]],
380 indices: T,
381) {
382 for idx in indices {
383 let mut bit = 0x80;
384 loop {
385 if let Some(pixel) = pixel_iter.next() {
386 let rgb = palette[usize::from((idx & bit) != 0)];
387 pixel[0] = rgb[0];
388 pixel[1] = rgb[1];
389 pixel[2] = rgb[2];
390 } else {
391 return;
392 }
393
394 bit >>= 1;
395 if bit == 0 {
396 break;
397 }
398 }
399 }
400}
401
402#[derive(PartialEq, Eq)]
403struct Bitfield {
404 shift: u32,
405 len: u32,
406}
407
408impl Bitfield {
409 fn from_mask(mask: u32, max_len: u32) -> ImageResult<Bitfield> {
410 if mask == 0 {
411 return Ok(Bitfield { shift: 0, len: 0 });
412 }
413 let mut shift = mask.trailing_zeros();
414 let mut len = (!(mask >> shift)).trailing_zeros();
415 if len != mask.count_ones() {
416 return Err(DecoderError::BitfieldMaskNonContiguous.into());
417 }
418 if len + shift > max_len {
419 return Err(DecoderError::BitfieldMaskInvalid.into());
420 }
421 if len > 8 {
422 shift += len - 8;
423 len = 8;
424 }
425 Ok(Bitfield { shift, len })
426 }
427
428 fn read(&self, data: u32) -> u8 {
429 let data = data >> self.shift;
430 match self.len {
431 1 => ((data & 0b1) * 0xff) as u8,
432 2 => ((data & 0b11) * 0x55) as u8,
433 3 => LOOKUP_TABLE_3_BIT_TO_8_BIT[(data & 0b00_0111) as usize],
434 4 => LOOKUP_TABLE_4_BIT_TO_8_BIT[(data & 0b00_1111) as usize],
435 5 => LOOKUP_TABLE_5_BIT_TO_8_BIT[(data & 0b01_1111) as usize],
436 6 => LOOKUP_TABLE_6_BIT_TO_8_BIT[(data & 0b11_1111) as usize],
437 7 => (((data & 0x7f) << 1) | ((data & 0x7f) >> 6)) as u8,
438 8 => (data & 0xff) as u8,
439 _ => panic!(),
440 }
441 }
442}
443
444#[derive(PartialEq, Eq)]
445struct Bitfields {
446 r: Bitfield,
447 g: Bitfield,
448 b: Bitfield,
449 a: Bitfield,
450}
451
452impl Bitfields {
453 fn from_mask(
454 r_mask: u32,
455 g_mask: u32,
456 b_mask: u32,
457 a_mask: u32,
458 max_len: u32,
459 ) -> ImageResult<Bitfields> {
460 let bitfields = Bitfields {
461 r: Bitfield::from_mask(r_mask, max_len)?,
462 g: Bitfield::from_mask(g_mask, max_len)?,
463 b: Bitfield::from_mask(b_mask, max_len)?,
464 a: Bitfield::from_mask(a_mask, max_len)?,
465 };
466 if bitfields.r.len == 0 || bitfields.g.len == 0 || bitfields.b.len == 0 {
467 return Err(DecoderError::BitfieldMaskMissing(max_len).into());
468 }
469 Ok(bitfields)
470 }
471}
472
473pub struct BmpDecoder<R> {
475 reader: R,
476
477 bmp_header_type: BMPHeaderType,
478 indexed_color: bool,
479
480 width: i32,
481 height: i32,
482 data_offset: u64,
483 top_down: bool,
484 no_file_header: bool,
485 add_alpha_channel: bool,
486 has_loaded_metadata: bool,
487 image_type: ImageType,
488
489 bit_count: u16,
490 colors_used: u32,
491 palette: Option<Vec<[u8; 3]>>,
492 bitfields: Option<Bitfields>,
493}
494
495enum RLEInsn {
496 EndOfFile,
497 EndOfRow,
498 Delta(u8, u8),
499 Absolute(u8, Vec<u8>),
500 PixelRun(u8, u8),
501}
502
503impl<R: BufRead + Seek> BmpDecoder<R> {
504 fn new_decoder(reader: R) -> BmpDecoder<R> {
505 BmpDecoder {
506 reader,
507
508 bmp_header_type: BMPHeaderType::Info,
509 indexed_color: false,
510
511 width: 0,
512 height: 0,
513 data_offset: 0,
514 top_down: false,
515 no_file_header: false,
516 add_alpha_channel: false,
517 has_loaded_metadata: false,
518 image_type: ImageType::Palette,
519
520 bit_count: 0,
521 colors_used: 0,
522 palette: None,
523 bitfields: None,
524 }
525 }
526
527 pub fn new(reader: R) -> ImageResult<BmpDecoder<R>> {
529 let mut decoder = Self::new_decoder(reader);
530 decoder.read_metadata()?;
531 Ok(decoder)
532 }
533
534 pub fn new_without_file_header(reader: R) -> ImageResult<BmpDecoder<R>> {
538 let mut decoder = Self::new_decoder(reader);
539 decoder.no_file_header = true;
540 decoder.read_metadata()?;
541 Ok(decoder)
542 }
543
544 #[cfg(feature = "ico")]
545 pub(crate) fn new_with_ico_format(reader: R) -> ImageResult<BmpDecoder<R>> {
546 let mut decoder = Self::new_decoder(reader);
547 decoder.read_metadata_in_ico_format()?;
548 Ok(decoder)
549 }
550
551 pub fn set_indexed_color(&mut self, indexed_color: bool) {
554 self.indexed_color = indexed_color;
555 }
556
557 #[cfg(feature = "ico")]
558 pub(crate) fn reader(&mut self) -> &mut R {
559 &mut self.reader
560 }
561
562 fn read_file_header(&mut self) -> ImageResult<()> {
563 if self.no_file_header {
564 return Ok(());
565 }
566 let mut signature = [0; 2];
567 self.reader.read_exact(&mut signature)?;
568
569 if signature != b"BM"[..] {
570 return Err(DecoderError::BmpSignatureInvalid.into());
571 }
572
573 self.reader.read_u32::<LittleEndian>()?;
576 self.reader.read_u32::<LittleEndian>()?;
577
578 self.data_offset = u64::from(self.reader.read_u32::<LittleEndian>()?);
579
580 Ok(())
581 }
582
583 fn read_bitmap_core_header(&mut self) -> ImageResult<()> {
587 self.width = i32::from(self.reader.read_u16::<LittleEndian>()?);
590 self.height = i32::from(self.reader.read_u16::<LittleEndian>()?);
591
592 check_for_overflow(self.width, self.height, self.num_channels())?;
593
594 if self.reader.read_u16::<LittleEndian>()? != 1 {
596 return Err(DecoderError::MoreThanOnePlane.into());
597 }
598
599 self.bit_count = self.reader.read_u16::<LittleEndian>()?;
600 self.image_type = match self.bit_count {
601 1 | 4 | 8 => ImageType::Palette,
602 24 => ImageType::RGB24,
603 _ => {
604 return Err(DecoderError::InvalidChannelWidth(
605 ChannelWidthError::Rgb,
606 self.bit_count,
607 )
608 .into())
609 }
610 };
611
612 Ok(())
613 }
614
615 fn read_bitmap_info_header(&mut self) -> ImageResult<()> {
620 self.width = self.reader.read_i32::<LittleEndian>()?;
621 self.height = self.reader.read_i32::<LittleEndian>()?;
622
623 if self.width < 0 {
625 return Err(DecoderError::NegativeWidth(self.width).into());
626 } else if self.width > MAX_WIDTH_HEIGHT || self.height > MAX_WIDTH_HEIGHT {
627 return Err(DecoderError::ImageTooLarge(self.width, self.height).into());
630 }
631
632 if self.height == i32::MIN {
633 return Err(DecoderError::InvalidHeight.into());
634 }
635
636 if self.height < 0 {
638 self.height *= -1;
639 self.top_down = true;
640 }
641
642 check_for_overflow(self.width, self.height, self.num_channels())?;
643
644 if self.reader.read_u16::<LittleEndian>()? != 1 {
646 return Err(DecoderError::MoreThanOnePlane.into());
647 }
648
649 self.bit_count = self.reader.read_u16::<LittleEndian>()?;
650 let image_type_u32 = self.reader.read_u32::<LittleEndian>()?;
651
652 if self.top_down && image_type_u32 != 0 && image_type_u32 != 3 {
654 return Err(DecoderError::ImageTypeInvalidForTopDown(image_type_u32).into());
655 }
656 self.image_type = match image_type_u32 {
657 0 => match self.bit_count {
658 1 | 2 | 4 | 8 => ImageType::Palette,
659 16 => ImageType::RGB16,
660 24 => ImageType::RGB24,
661 32 if self.add_alpha_channel => ImageType::RGBA32,
662 32 => ImageType::RGB32,
663 _ => {
664 return Err(DecoderError::InvalidChannelWidth(
665 ChannelWidthError::Rgb,
666 self.bit_count,
667 )
668 .into())
669 }
670 },
671 1 => match self.bit_count {
672 8 => ImageType::RLE8,
673 _ => {
674 return Err(DecoderError::InvalidChannelWidth(
675 ChannelWidthError::Rle8,
676 self.bit_count,
677 )
678 .into())
679 }
680 },
681 2 => match self.bit_count {
682 4 => ImageType::RLE4,
683 _ => {
684 return Err(DecoderError::InvalidChannelWidth(
685 ChannelWidthError::Rle4,
686 self.bit_count,
687 )
688 .into())
689 }
690 },
691 3 => match self.bit_count {
692 16 => ImageType::Bitfields16,
693 32 => ImageType::Bitfields32,
694 _ => {
695 return Err(DecoderError::InvalidChannelWidth(
696 ChannelWidthError::Bitfields,
697 self.bit_count,
698 )
699 .into())
700 }
701 },
702 4 => {
703 return Err(ImageError::Unsupported(
705 UnsupportedError::from_format_and_kind(
706 ImageFormat::Bmp.into(),
707 UnsupportedErrorKind::GenericFeature("JPEG compression".to_owned()),
708 ),
709 ));
710 }
711 5 => {
712 return Err(ImageError::Unsupported(
714 UnsupportedError::from_format_and_kind(
715 ImageFormat::Bmp.into(),
716 UnsupportedErrorKind::GenericFeature("PNG compression".to_owned()),
717 ),
718 ));
719 }
720 11..=13 => {
721 return Err(ImageError::Unsupported(
723 UnsupportedError::from_format_and_kind(
724 ImageFormat::Bmp.into(),
725 UnsupportedErrorKind::GenericFeature("CMYK format".to_owned()),
726 ),
727 ));
728 }
729 _ => {
730 return Err(DecoderError::ImageTypeUnknown(image_type_u32).into());
732 }
733 };
734
735 self.reader.read_u32::<LittleEndian>()?;
740 self.reader.read_u32::<LittleEndian>()?;
741 self.reader.read_u32::<LittleEndian>()?;
742
743 self.colors_used = self.reader.read_u32::<LittleEndian>()?;
744
745 self.reader.read_u32::<LittleEndian>()?;
748
749 Ok(())
750 }
751
752 fn read_bitmasks(&mut self) -> ImageResult<()> {
753 let r_mask = self.reader.read_u32::<LittleEndian>()?;
754 let g_mask = self.reader.read_u32::<LittleEndian>()?;
755 let b_mask = self.reader.read_u32::<LittleEndian>()?;
756
757 let a_mask = match self.bmp_header_type {
758 BMPHeaderType::V3 | BMPHeaderType::V4 | BMPHeaderType::V5 => {
759 self.reader.read_u32::<LittleEndian>()?
760 }
761 _ => 0,
762 };
763
764 self.bitfields = match self.image_type {
765 ImageType::Bitfields16 => {
766 Some(Bitfields::from_mask(r_mask, g_mask, b_mask, a_mask, 16)?)
767 }
768 ImageType::Bitfields32 => {
769 Some(Bitfields::from_mask(r_mask, g_mask, b_mask, a_mask, 32)?)
770 }
771 _ => None,
772 };
773
774 if self.bitfields.is_some() && a_mask != 0 {
775 self.add_alpha_channel = true;
776 }
777
778 Ok(())
779 }
780
781 fn read_metadata(&mut self) -> ImageResult<()> {
782 if !self.has_loaded_metadata {
783 self.read_file_header()?;
784 let bmp_header_offset = self.reader.stream_position()?;
785 let bmp_header_size = self.reader.read_u32::<LittleEndian>()?;
786 let bmp_header_end = bmp_header_offset + u64::from(bmp_header_size);
787
788 self.bmp_header_type = match bmp_header_size {
789 BITMAPCOREHEADER_SIZE => BMPHeaderType::Core,
790 BITMAPINFOHEADER_SIZE => BMPHeaderType::Info,
791 BITMAPV2HEADER_SIZE => BMPHeaderType::V2,
792 BITMAPV3HEADER_SIZE => BMPHeaderType::V3,
793 BITMAPV4HEADER_SIZE => BMPHeaderType::V4,
794 BITMAPV5HEADER_SIZE => BMPHeaderType::V5,
795 _ if bmp_header_size < BITMAPCOREHEADER_SIZE => {
796 return Err(DecoderError::HeaderTooSmall(bmp_header_size).into());
798 }
799 _ => {
800 return Err(ImageError::Unsupported(
801 UnsupportedError::from_format_and_kind(
802 ImageFormat::Bmp.into(),
803 UnsupportedErrorKind::GenericFeature(format!(
804 "Unknown bitmap header type (size={bmp_header_size})"
805 )),
806 ),
807 ))
808 }
809 };
810
811 match self.bmp_header_type {
812 BMPHeaderType::Core => {
813 self.read_bitmap_core_header()?;
814 }
815 BMPHeaderType::Info
816 | BMPHeaderType::V2
817 | BMPHeaderType::V3
818 | BMPHeaderType::V4
819 | BMPHeaderType::V5 => {
820 self.read_bitmap_info_header()?;
821 }
822 }
823
824 let mut bitmask_bytes_offset = 0;
825 if self.image_type == ImageType::Bitfields16
826 || self.image_type == ImageType::Bitfields32
827 {
828 self.read_bitmasks()?;
829
830 if matches!(
837 self.bmp_header_type,
838 BMPHeaderType::Info | BMPHeaderType::V4 | BMPHeaderType::V5
839 ) {
840 bitmask_bytes_offset = 12;
842 }
843 };
844
845 self.reader
846 .seek(SeekFrom::Start(bmp_header_end + bitmask_bytes_offset))?;
847
848 match self.image_type {
849 ImageType::Palette | ImageType::RLE4 | ImageType::RLE8 => self.read_palette()?,
850 _ => {}
851 }
852
853 if self.no_file_header {
854 self.data_offset = self.reader.stream_position()?;
856 }
857
858 self.has_loaded_metadata = true;
859 }
860 Ok(())
861 }
862
863 #[cfg(feature = "ico")]
864 #[doc(hidden)]
865 pub fn read_metadata_in_ico_format(&mut self) -> ImageResult<()> {
866 self.no_file_header = true;
867 self.add_alpha_channel = true;
868 self.read_metadata()?;
869
870 self.height /= 2;
873 Ok(())
874 }
875
876 fn get_palette_size(&mut self) -> ImageResult<usize> {
877 match self.colors_used {
878 0 => Ok(1 << self.bit_count),
879 _ => {
880 if self.colors_used > 1 << self.bit_count {
881 return Err(DecoderError::PaletteSizeExceeded {
882 colors_used: self.colors_used,
883 bit_count: self.bit_count,
884 }
885 .into());
886 }
887 Ok(self.colors_used as usize)
888 }
889 }
890 }
891
892 fn bytes_per_color(&self) -> usize {
893 match self.bmp_header_type {
894 BMPHeaderType::Core => 3,
895 _ => 4,
896 }
897 }
898
899 fn read_palette(&mut self) -> ImageResult<()> {
900 const MAX_PALETTE_SIZE: usize = 256; let bytes_per_color = self.bytes_per_color();
903 let palette_size = self.get_palette_size()?;
904 let max_length = MAX_PALETTE_SIZE * bytes_per_color;
905
906 let length = palette_size * bytes_per_color;
907 let mut buf = vec_try_with_capacity(max_length)?;
908
909 buf.resize(cmp::min(length, max_length), 0);
913 self.reader.by_ref().read_exact(&mut buf)?;
914
915 match length.cmp(&max_length) {
918 Ordering::Greater => {
919 self.reader
920 .seek(SeekFrom::Current((length - max_length) as i64))?;
921 }
922 Ordering::Less => buf.resize(max_length, 0),
923 Ordering::Equal => (),
924 }
925
926 let p: Vec<[u8; 3]> = (0..MAX_PALETTE_SIZE)
927 .map(|i| {
928 let b = buf[bytes_per_color * i];
929 let g = buf[bytes_per_color * i + 1];
930 let r = buf[bytes_per_color * i + 2];
931 [r, g, b]
932 })
933 .collect();
934
935 self.palette = Some(p);
936
937 Ok(())
938 }
939
940 pub fn get_palette(&self) -> Option<&[[u8; 3]]> {
942 self.palette.as_ref().map(|vec| &vec[..])
943 }
944
945 fn num_channels(&self) -> usize {
946 if self.indexed_color {
947 1
948 } else if self.add_alpha_channel {
949 4
950 } else {
951 3
952 }
953 }
954
955 fn rows<'a>(&self, pixel_data: &'a mut [u8]) -> RowIterator<'a> {
956 let stride = self.width as usize * self.num_channels();
957 if self.top_down {
958 RowIterator {
959 chunks: Chunker::FromTop(pixel_data.chunks_exact_mut(stride)),
960 }
961 } else {
962 RowIterator {
963 chunks: Chunker::FromBottom(pixel_data.chunks_exact_mut(stride).rev()),
964 }
965 }
966 }
967
968 fn read_palettized_pixel_data(&mut self, buf: &mut [u8]) -> ImageResult<()> {
969 let num_channels = self.num_channels();
970 let row_byte_length = ((i32::from(self.bit_count) * self.width + 31) / 32 * 4) as usize;
971 let mut indices = vec![0; row_byte_length];
972 let palette = self.palette.as_ref().unwrap();
973 let bit_count = self.bit_count;
974 let reader = &mut self.reader;
975 let width = self.width as usize;
976 let skip_palette = self.indexed_color;
977
978 reader.seek(SeekFrom::Start(self.data_offset))?;
979
980 if num_channels == 4 {
981 buf.chunks_exact_mut(4).for_each(|c| c[3] = 0xFF);
982 }
983
984 with_rows(
985 buf,
986 self.width,
987 self.height,
988 num_channels,
989 self.top_down,
990 |row| {
991 reader.read_exact(&mut indices)?;
992 if skip_palette {
993 row.clone_from_slice(&indices[0..width]);
994 } else {
995 let mut pixel_iter = row.chunks_exact_mut(num_channels);
996 match bit_count {
997 1 => {
998 set_1bit_pixel_run(&mut pixel_iter, palette, indices.iter());
999 }
1000 2 => {
1001 set_2bit_pixel_run(&mut pixel_iter, palette, indices.iter(), width);
1002 }
1003 4 => {
1004 set_4bit_pixel_run(&mut pixel_iter, palette, indices.iter(), width);
1005 }
1006 8 => {
1007 set_8bit_pixel_run(&mut pixel_iter, palette, indices.iter(), width);
1008 }
1009 _ => panic!(),
1010 }
1011 }
1012 Ok(())
1013 },
1014 )?;
1015
1016 Ok(())
1017 }
1018
1019 fn read_16_bit_pixel_data(
1020 &mut self,
1021 buf: &mut [u8],
1022 bitfields: Option<&Bitfields>,
1023 ) -> ImageResult<()> {
1024 let num_channels = self.num_channels();
1025 let row_padding_len = self.width as usize % 2 * 2;
1026 let row_padding = &mut [0; 2][..row_padding_len];
1027 let bitfields = match bitfields {
1028 Some(b) => b,
1029 None => self.bitfields.as_ref().unwrap(),
1030 };
1031 let reader = &mut self.reader;
1032
1033 reader.seek(SeekFrom::Start(self.data_offset))?;
1034
1035 with_rows(
1036 buf,
1037 self.width,
1038 self.height,
1039 num_channels,
1040 self.top_down,
1041 |row| {
1042 for pixel in row.chunks_mut(num_channels) {
1043 let data = u32::from(reader.read_u16::<LittleEndian>()?);
1044
1045 pixel[0] = bitfields.r.read(data);
1046 pixel[1] = bitfields.g.read(data);
1047 pixel[2] = bitfields.b.read(data);
1048 if num_channels == 4 {
1049 if bitfields.a.len != 0 {
1050 pixel[3] = bitfields.a.read(data);
1051 } else {
1052 pixel[3] = 0xFF;
1053 }
1054 }
1055 }
1056 reader.read_exact(row_padding)
1057 },
1058 )?;
1059
1060 Ok(())
1061 }
1062
1063 fn read_32_bit_pixel_data(&mut self, buf: &mut [u8]) -> ImageResult<()> {
1065 let num_channels = self.num_channels();
1066
1067 let bitfields = self.bitfields.as_ref().unwrap();
1068
1069 let reader = &mut self.reader;
1070 reader.seek(SeekFrom::Start(self.data_offset))?;
1071
1072 with_rows(
1073 buf,
1074 self.width,
1075 self.height,
1076 num_channels,
1077 self.top_down,
1078 |row| {
1079 for pixel in row.chunks_mut(num_channels) {
1080 let data = reader.read_u32::<LittleEndian>()?;
1081
1082 pixel[0] = bitfields.r.read(data);
1083 pixel[1] = bitfields.g.read(data);
1084 pixel[2] = bitfields.b.read(data);
1085 if num_channels == 4 {
1086 if bitfields.a.len != 0 {
1087 pixel[3] = bitfields.a.read(data);
1088 } else {
1089 pixel[3] = 0xff;
1090 }
1091 }
1092 }
1093 Ok(())
1094 },
1095 )?;
1096
1097 Ok(())
1098 }
1099
1100 fn read_full_byte_pixel_data(
1102 &mut self,
1103 buf: &mut [u8],
1104 format: &FormatFullBytes,
1105 ) -> ImageResult<()> {
1106 let num_channels = self.num_channels();
1107 let row_padding_len = match *format {
1108 FormatFullBytes::RGB24 => (4 - (self.width as usize * 3) % 4) % 4,
1109 _ => 0,
1110 };
1111 let row_padding = &mut [0; 4][..row_padding_len];
1112
1113 self.reader.seek(SeekFrom::Start(self.data_offset))?;
1114
1115 let reader = &mut self.reader;
1116
1117 with_rows(
1118 buf,
1119 self.width,
1120 self.height,
1121 num_channels,
1122 self.top_down,
1123 |row| {
1124 for pixel in row.chunks_mut(num_channels) {
1125 if *format == FormatFullBytes::Format888 {
1126 reader.read_u8()?;
1127 }
1128
1129 reader.read_exact(&mut pixel[0..3])?;
1133 pixel[0..3].reverse();
1134
1135 if *format == FormatFullBytes::RGB32 {
1136 reader.read_u8()?;
1137 }
1138
1139 if *format == FormatFullBytes::RGBA32 {
1141 reader.read_exact(&mut pixel[3..4])?;
1142 } else if num_channels == 4 {
1143 pixel[3] = 0xFF;
1144 }
1145 }
1146 reader.read_exact(row_padding)
1147 },
1148 )?;
1149
1150 Ok(())
1151 }
1152
1153 fn read_rle_data(&mut self, buf: &mut [u8], image_type: ImageType) -> ImageResult<()> {
1154 self.reader.seek(SeekFrom::Start(self.data_offset))?;
1156
1157 let num_channels = self.num_channels();
1158 let p = self.palette.as_ref().unwrap();
1159
1160 let mut row_iter = self.rows(buf);
1165
1166 while let Some(row) = row_iter.next() {
1167 let mut pixel_iter = row.chunks_exact_mut(num_channels);
1168
1169 let mut x = 0;
1170 loop {
1171 let instruction = {
1172 let control_byte = self.reader.read_u8()?;
1173 match control_byte {
1174 RLE_ESCAPE => {
1175 let op = self.reader.read_u8()?;
1176
1177 match op {
1178 RLE_ESCAPE_EOL => RLEInsn::EndOfRow,
1179 RLE_ESCAPE_EOF => RLEInsn::EndOfFile,
1180 RLE_ESCAPE_DELTA => {
1181 let xdelta = self.reader.read_u8()?;
1182 let ydelta = self.reader.read_u8()?;
1183 RLEInsn::Delta(xdelta, ydelta)
1184 }
1185 _ => {
1186 let mut length = op as usize;
1187 if self.image_type == ImageType::RLE4 {
1188 length = length.div_ceil(2);
1189 }
1190 length += length & 1;
1191 let mut buffer = Vec::new();
1192 self.reader.read_exact_vec(&mut buffer, length)?;
1193 RLEInsn::Absolute(op, buffer)
1194 }
1195 }
1196 }
1197 _ => {
1198 let palette_index = self.reader.read_u8()?;
1199 RLEInsn::PixelRun(control_byte, palette_index)
1200 }
1201 }
1202 };
1203
1204 match instruction {
1205 RLEInsn::EndOfFile => {
1206 pixel_iter.for_each(|p| p.fill(0));
1207 row_iter.for_each(|r| r.fill(0));
1208 return Ok(());
1209 }
1210 RLEInsn::EndOfRow => {
1211 pixel_iter.for_each(|p| p.fill(0));
1212 break;
1213 }
1214 RLEInsn::Delta(x_delta, y_delta) => {
1215 if y_delta > 0 {
1222 pixel_iter.for_each(|p| p.fill(0));
1224
1225 for _ in 1..y_delta {
1227 let row = row_iter.next().ok_or(DecoderError::CorruptRleData)?;
1228 row.fill(0);
1229 }
1230
1231 pixel_iter = row_iter
1233 .next()
1234 .ok_or(DecoderError::CorruptRleData)?
1235 .chunks_exact_mut(num_channels);
1236
1237 for _ in 0..x {
1239 pixel_iter
1240 .next()
1241 .ok_or(DecoderError::CorruptRleData)?
1242 .fill(0);
1243 }
1244 }
1245
1246 for _ in 0..x_delta {
1247 let pixel = pixel_iter.next().ok_or(DecoderError::CorruptRleData)?;
1248 pixel.fill(0);
1249 }
1250 x += x_delta as usize;
1251 }
1252 RLEInsn::Absolute(length, indices) => {
1253 match image_type {
1257 ImageType::RLE8 => {
1258 if !set_8bit_pixel_run(
1259 &mut pixel_iter,
1260 p,
1261 indices.iter(),
1262 length as usize,
1263 ) {
1264 return Err(DecoderError::CorruptRleData.into());
1265 }
1266 }
1267 ImageType::RLE4 => {
1268 if !set_4bit_pixel_run(
1269 &mut pixel_iter,
1270 p,
1271 indices.iter(),
1272 length as usize,
1273 ) {
1274 return Err(DecoderError::CorruptRleData.into());
1275 }
1276 }
1277 _ => unreachable!(),
1278 }
1279 x += length as usize;
1280 }
1281 RLEInsn::PixelRun(n_pixels, palette_index) => {
1282 match image_type {
1283 ImageType::RLE8 => {
1284 let repeat_pixel: [u8; 3] = p[palette_index as usize];
1291 (&mut pixel_iter).take(n_pixels as usize).for_each(|p| {
1292 p[2] = repeat_pixel[2];
1293 p[1] = repeat_pixel[1];
1294 p[0] = repeat_pixel[0];
1295 });
1296 }
1297 ImageType::RLE4 => {
1298 if !set_4bit_pixel_run(
1299 &mut pixel_iter,
1300 p,
1301 repeat(&palette_index),
1302 n_pixels as usize,
1303 ) {
1304 return Err(DecoderError::CorruptRleData.into());
1305 }
1306 }
1307 _ => unreachable!(),
1308 }
1309 x += n_pixels as usize;
1310 }
1311 }
1312 }
1313 }
1314
1315 Ok(())
1316 }
1317
1318 pub(crate) fn read_image_data(&mut self, buf: &mut [u8]) -> ImageResult<()> {
1321 match self.image_type {
1322 ImageType::Palette => self.read_palettized_pixel_data(buf),
1323 ImageType::RGB16 => self.read_16_bit_pixel_data(buf, Some(&R5_G5_B5_COLOR_MASK)),
1324 ImageType::RGB24 => self.read_full_byte_pixel_data(buf, &FormatFullBytes::RGB24),
1325 ImageType::RGB32 => self.read_full_byte_pixel_data(buf, &FormatFullBytes::RGB32),
1326 ImageType::RGBA32 => self.read_full_byte_pixel_data(buf, &FormatFullBytes::RGBA32),
1327 ImageType::RLE8 => self.read_rle_data(buf, ImageType::RLE8),
1328 ImageType::RLE4 => self.read_rle_data(buf, ImageType::RLE4),
1329 ImageType::Bitfields16 => match self.bitfields {
1330 Some(_) => self.read_16_bit_pixel_data(buf, None),
1331 None => Err(DecoderError::BitfieldMasksMissing(16).into()),
1332 },
1333 ImageType::Bitfields32 => match self.bitfields {
1334 Some(R8_G8_B8_COLOR_MASK) => {
1335 self.read_full_byte_pixel_data(buf, &FormatFullBytes::Format888)
1336 }
1337 Some(R8_G8_B8_A8_COLOR_MASK) => {
1338 self.read_full_byte_pixel_data(buf, &FormatFullBytes::RGBA32)
1339 }
1340 Some(_) => self.read_32_bit_pixel_data(buf),
1341 None => Err(DecoderError::BitfieldMasksMissing(32).into()),
1342 },
1343 }
1344 }
1345}
1346
1347impl<R: BufRead + Seek> ImageDecoder for BmpDecoder<R> {
1348 fn dimensions(&self) -> (u32, u32) {
1349 (self.width as u32, self.height as u32)
1350 }
1351
1352 fn color_type(&self) -> ColorType {
1353 if self.indexed_color {
1354 ColorType::L8
1355 } else if self.add_alpha_channel {
1356 ColorType::Rgba8
1357 } else {
1358 ColorType::Rgb8
1359 }
1360 }
1361
1362 fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> {
1363 assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));
1364 self.read_image_data(buf)
1365 }
1366
1367 fn read_image_boxed(self: Box<Self>, buf: &mut [u8]) -> ImageResult<()> {
1368 (*self).read_image(buf)
1369 }
1370}
1371
1372impl<R: BufRead + Seek> ImageDecoderRect for BmpDecoder<R> {
1373 fn read_rect(
1374 &mut self,
1375 x: u32,
1376 y: u32,
1377 width: u32,
1378 height: u32,
1379 buf: &mut [u8],
1380 row_pitch: usize,
1381 ) -> ImageResult<()> {
1382 let start = self.reader.stream_position()?;
1383 load_rect(
1384 x,
1385 y,
1386 width,
1387 height,
1388 buf,
1389 row_pitch,
1390 self,
1391 self.total_bytes() as usize,
1392 |_, _| Ok(()),
1393 |s, buf| s.read_image_data(buf),
1394 )?;
1395 self.reader.seek(SeekFrom::Start(start))?;
1396 Ok(())
1397 }
1398}
1399
1400#[cfg(test)]
1401mod test {
1402 use std::io::{BufReader, Cursor};
1403
1404 use super::*;
1405
1406 #[test]
1407 fn test_bitfield_len() {
1408 for len in 1..9 {
1409 let bitfield = Bitfield { shift: 0, len };
1410 for i in 0..(1 << len) {
1411 let read = bitfield.read(i);
1412 let calc = (f64::from(i) / f64::from((1 << len) - 1) * 255f64).round() as u8;
1413 if read != calc {
1414 println!("len:{len} i:{i} read:{read} calc:{calc}");
1415 }
1416 assert_eq!(read, calc);
1417 }
1418 }
1419 }
1420
1421 #[test]
1422 fn read_rect() {
1423 let f =
1424 BufReader::new(std::fs::File::open("tests/images/bmp/images/Core_8_Bit.bmp").unwrap());
1425 let mut decoder = BmpDecoder::new(f).unwrap();
1426
1427 let mut buf: Vec<u8> = vec![0; 8 * 8 * 3];
1428 decoder.read_rect(0, 0, 8, 8, &mut buf, 8 * 3).unwrap();
1429 }
1430
1431 #[test]
1432 fn read_rle_too_short() {
1433 let data = vec![
1434 0x42, 0x4d, 0x04, 0xee, 0xfe, 0xff, 0xff, 0x10, 0xff, 0x00, 0x04, 0x00, 0x00, 0x00,
1435 0x7c, 0x00, 0x00, 0x00, 0x0c, 0x41, 0x00, 0x00, 0x07, 0x10, 0x00, 0x00, 0x01, 0x00,
1436 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
1437 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x21,
1438 0xff, 0x00, 0x66, 0x61, 0x72, 0x62, 0x66, 0x65, 0x6c, 0x64, 0x00, 0x00, 0x00, 0x00,
1439 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1440 0xff, 0xd8, 0xff, 0x00, 0x00, 0x19, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1441 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0xff, 0x00, 0x00, 0x00,
1442 0x00, 0x01, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00,
1443 0x00, 0x00, 0x00, 0x2d, 0x31, 0x31, 0x35, 0x36, 0x00, 0xff, 0x00, 0x00, 0x52, 0x3a,
1444 0x37, 0x30, 0x7e, 0x71, 0x63, 0x91, 0x5a, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
1445 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
1446 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x35, 0x37, 0x00, 0xff, 0x00, 0x00, 0x52,
1447 0x3a, 0x37, 0x30, 0x7e, 0x71, 0x63, 0x91, 0x5a, 0x04, 0x05, 0x3c, 0x00, 0x00, 0x11,
1448 0x00, 0x5d, 0x7a, 0x82, 0xb7, 0xca, 0x2d, 0x31, 0xff, 0xff, 0xc7, 0x95, 0x33, 0x2e,
1449 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00,
1450 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x66, 0x00, 0x4d,
1451 0x4d, 0x00, 0x2a, 0x00,
1452 ];
1453
1454 let decoder = BmpDecoder::new(Cursor::new(&data)).unwrap();
1455 let mut buf = vec![0; usize::try_from(decoder.total_bytes()).unwrap()];
1456 assert!(decoder.read_image(&mut buf).is_ok());
1457 }
1458
1459 #[test]
1460 fn test_no_header() {
1461 let tests = [
1462 "Info_R8_G8_B8.bmp",
1463 "Info_A8_R8_G8_B8.bmp",
1464 "Info_8_Bit.bmp",
1465 "Info_4_Bit.bmp",
1466 "Info_1_Bit.bmp",
1467 ];
1468
1469 for name in &tests {
1470 let path = format!("tests/images/bmp/images/{name}");
1471 let ref_img = crate::open(&path).unwrap();
1472 let mut data = std::fs::read(&path).unwrap();
1473 let slice = &mut data[14..];
1475 let decoder = BmpDecoder::new_without_file_header(Cursor::new(slice)).unwrap();
1476 let no_hdr_img = crate::DynamicImage::from_decoder(decoder).unwrap();
1477 assert_eq!(ref_img, no_hdr_img);
1478 }
1479 }
1480}