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