/src/image/src/codecs/bmp/decoder.rs
Line | Count | Source |
1 | | use crate::utils::vec_try_with_capacity; |
2 | | use std::cmp::{self, Ordering}; |
3 | | use std::io::{self, BufRead, Seek, SeekFrom}; |
4 | | use std::iter::{repeat, Rev}; |
5 | | use std::slice::ChunksExactMut; |
6 | | use std::{error, fmt}; |
7 | | |
8 | | use byteorder_lite::{LittleEndian, ReadBytesExt}; |
9 | | |
10 | | use crate::color::ColorType; |
11 | | use crate::error::{ |
12 | | DecodingError, ImageError, ImageResult, UnsupportedError, UnsupportedErrorKind, |
13 | | }; |
14 | | use crate::io::free_functions::load_rect; |
15 | | use crate::io::ReadExt; |
16 | | use crate::{ImageDecoder, ImageDecoderRect, ImageFormat}; |
17 | | |
18 | | const BITMAPCOREHEADER_SIZE: u32 = 12; |
19 | | const BITMAPINFOHEADER_SIZE: u32 = 40; |
20 | | const BITMAPV2HEADER_SIZE: u32 = 52; |
21 | | const BITMAPV3HEADER_SIZE: u32 = 56; |
22 | | const BITMAPV4HEADER_SIZE: u32 = 108; |
23 | | const BITMAPV5HEADER_SIZE: u32 = 124; |
24 | | |
25 | | static LOOKUP_TABLE_3_BIT_TO_8_BIT: [u8; 8] = [0, 36, 73, 109, 146, 182, 219, 255]; |
26 | | static 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 | | ]; |
29 | | static 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 | | ]; |
33 | | static 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 | | |
40 | | static 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 | | }; |
46 | | const 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 | | }; |
52 | | const 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 | | |
59 | | const RLE_ESCAPE: u8 = 0; |
60 | | const RLE_ESCAPE_EOL: u8 = 0; |
61 | | const RLE_ESCAPE_EOF: u8 = 1; |
62 | | const RLE_ESCAPE_DELTA: u8 = 2; |
63 | | |
64 | | /// The maximum width/height the decoder will process. |
65 | | const MAX_WIDTH_HEIGHT: i32 = 0xFFFF; |
66 | | |
67 | | #[derive(PartialEq, Copy, Clone)] |
68 | | enum ImageType { |
69 | | Palette, |
70 | | RGB16, |
71 | | RGB24, |
72 | | RGB32, |
73 | | RGBA32, |
74 | | RLE8, |
75 | | RLE4, |
76 | | Bitfields16, |
77 | | Bitfields32, |
78 | | } |
79 | | |
80 | | #[derive(PartialEq)] |
81 | | enum BMPHeaderType { |
82 | | Core, |
83 | | Info, |
84 | | V2, |
85 | | V3, |
86 | | V4, |
87 | | V5, |
88 | | } |
89 | | |
90 | | #[derive(PartialEq)] |
91 | | enum FormatFullBytes { |
92 | | RGB24, |
93 | | RGB32, |
94 | | RGBA32, |
95 | | Format888, |
96 | | } |
97 | | |
98 | | enum Chunker<'a> { |
99 | | FromTop(ChunksExactMut<'a, u8>), |
100 | | FromBottom(Rev<ChunksExactMut<'a, u8>>), |
101 | | } |
102 | | |
103 | | pub(crate) struct RowIterator<'a> { |
104 | | chunks: Chunker<'a>, |
105 | | } |
106 | | |
107 | | impl<'a> Iterator for RowIterator<'a> { |
108 | | type Item = &'a mut [u8]; |
109 | | |
110 | | #[inline(always)] |
111 | 4.66M | fn next(&mut self) -> Option<&'a mut [u8]> { |
112 | 4.66M | match self.chunks { |
113 | 0 | Chunker::FromTop(ref mut chunks) => chunks.next(), |
114 | 4.66M | Chunker::FromBottom(ref mut chunks) => chunks.next(), |
115 | | } |
116 | 4.66M | } |
117 | | } |
118 | | |
119 | | /// All errors that can occur when attempting to parse a BMP |
120 | | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] |
121 | | enum DecoderError { |
122 | | // Failed to decompress RLE data. |
123 | | CorruptRleData, |
124 | | |
125 | | /// The bitfield mask interleaves set and unset bits |
126 | | BitfieldMaskNonContiguous, |
127 | | /// Bitfield mask invalid (e.g. too long for specified type) |
128 | | BitfieldMaskInvalid, |
129 | | /// Bitfield (of the specified width – 16- or 32-bit) mask not present |
130 | | BitfieldMaskMissing(u32), |
131 | | /// Bitfield (of the specified width – 16- or 32-bit) masks not present |
132 | | BitfieldMasksMissing(u32), |
133 | | |
134 | | /// BMP's "BM" signature wrong or missing |
135 | | BmpSignatureInvalid, |
136 | | /// More than the exactly one allowed plane specified by the format |
137 | | MoreThanOnePlane, |
138 | | /// Invalid amount of bits per channel for the specified image type |
139 | | InvalidChannelWidth(ChannelWidthError, u16), |
140 | | |
141 | | /// The width is negative |
142 | | NegativeWidth(i32), |
143 | | /// One of the dimensions is larger than a soft limit |
144 | | ImageTooLarge(i32, i32), |
145 | | /// The height is `i32::min_value()` |
146 | | /// |
147 | | /// General negative heights specify top-down DIBs |
148 | | InvalidHeight, |
149 | | |
150 | | /// Specified image type is invalid for top-down BMPs (i.e. is compressed) |
151 | | ImageTypeInvalidForTopDown(u32), |
152 | | /// Image type not currently recognized by the decoder |
153 | | ImageTypeUnknown(u32), |
154 | | |
155 | | /// Bitmap header smaller than the core header |
156 | | HeaderTooSmall(u32), |
157 | | |
158 | | /// The palette is bigger than allowed by the bit count of the BMP |
159 | | PaletteSizeExceeded { |
160 | | colors_used: u32, |
161 | | bit_count: u16, |
162 | | }, |
163 | | } |
164 | | |
165 | | impl fmt::Display for DecoderError { |
166 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
167 | 0 | match self { |
168 | 0 | DecoderError::CorruptRleData => f.write_str("Corrupt RLE data"), |
169 | 0 | DecoderError::BitfieldMaskNonContiguous => f.write_str("Non-contiguous bitfield mask"), |
170 | 0 | DecoderError::BitfieldMaskInvalid => f.write_str("Invalid bitfield mask"), |
171 | 0 | DecoderError::BitfieldMaskMissing(bb) => { |
172 | 0 | f.write_fmt(format_args!("Missing {bb}-bit bitfield mask")) |
173 | | } |
174 | 0 | DecoderError::BitfieldMasksMissing(bb) => { |
175 | 0 | f.write_fmt(format_args!("Missing {bb}-bit bitfield masks")) |
176 | | } |
177 | 0 | DecoderError::BmpSignatureInvalid => f.write_str("BMP signature not found"), |
178 | 0 | DecoderError::MoreThanOnePlane => f.write_str("More than one plane"), |
179 | 0 | DecoderError::InvalidChannelWidth(tp, n) => { |
180 | 0 | f.write_fmt(format_args!("Invalid channel bit count for {tp}: {n}")) |
181 | | } |
182 | 0 | DecoderError::NegativeWidth(w) => f.write_fmt(format_args!("Negative width ({w})")), |
183 | 0 | DecoderError::ImageTooLarge(w, h) => f.write_fmt(format_args!( |
184 | 0 | "Image too large (one of ({w}, {h}) > soft limit of {MAX_WIDTH_HEIGHT})" |
185 | | )), |
186 | 0 | DecoderError::InvalidHeight => f.write_str("Invalid height"), |
187 | 0 | DecoderError::ImageTypeInvalidForTopDown(tp) => f.write_fmt(format_args!( |
188 | 0 | "Invalid image type {tp} for top-down image." |
189 | | )), |
190 | 0 | DecoderError::ImageTypeUnknown(tp) => { |
191 | 0 | f.write_fmt(format_args!("Unknown image compression type {tp}")) |
192 | | } |
193 | 0 | DecoderError::HeaderTooSmall(s) => { |
194 | 0 | f.write_fmt(format_args!("Bitmap header too small ({s} bytes)")) |
195 | | } |
196 | | DecoderError::PaletteSizeExceeded { |
197 | 0 | colors_used, |
198 | 0 | bit_count, |
199 | 0 | } => f.write_fmt(format_args!( |
200 | 0 | "Palette size {colors_used} exceeds maximum size for BMP with bit count of {bit_count}" |
201 | | )), |
202 | | } |
203 | 0 | } |
204 | | } |
205 | | |
206 | | impl From<DecoderError> for ImageError { |
207 | 877 | fn from(e: DecoderError) -> ImageError { |
208 | 877 | ImageError::Decoding(DecodingError::new(ImageFormat::Bmp.into(), e)) |
209 | 877 | } |
210 | | } |
211 | | |
212 | | impl error::Error for DecoderError {} |
213 | | |
214 | | /// Distinct image types whose saved channel width can be invalid |
215 | | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] |
216 | | enum ChannelWidthError { |
217 | | /// RGB |
218 | | Rgb, |
219 | | /// 8-bit run length encoding |
220 | | Rle8, |
221 | | /// 4-bit run length encoding |
222 | | Rle4, |
223 | | /// Bitfields (16- or 32-bit) |
224 | | Bitfields, |
225 | | } |
226 | | |
227 | | impl fmt::Display for ChannelWidthError { |
228 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
229 | 0 | f.write_str(match self { |
230 | 0 | ChannelWidthError::Rgb => "RGB", |
231 | 0 | ChannelWidthError::Rle8 => "RLE8", |
232 | 0 | ChannelWidthError::Rle4 => "RLE4", |
233 | 0 | ChannelWidthError::Bitfields => "bitfields", |
234 | | }) |
235 | 0 | } |
236 | | } |
237 | | |
238 | | /// Convenience function to check if the combination of width, length and number of |
239 | | /// channels would result in a buffer that would overflow. |
240 | 4.20k | fn check_for_overflow(width: i32, length: i32, channels: usize) -> ImageResult<()> { |
241 | 4.20k | num_bytes(width, length, channels) |
242 | 4.20k | .map(|_| ()) |
243 | 4.20k | .ok_or_else(|| { |
244 | 10 | ImageError::Unsupported(UnsupportedError::from_format_and_kind( |
245 | 10 | ImageFormat::Bmp.into(), |
246 | 10 | UnsupportedErrorKind::GenericFeature(format!( |
247 | 10 | "Image dimensions ({width}x{length} w/{channels} channels) are too large" |
248 | 10 | )), |
249 | 10 | )) |
250 | 10 | }) |
251 | 4.20k | } |
252 | | |
253 | | /// Calculate how many many bytes a buffer holding a decoded image with these properties would |
254 | | /// require. Returns `None` if the buffer size would overflow or if one of the sizes are negative. |
255 | 4.20k | fn num_bytes(width: i32, length: i32, channels: usize) -> Option<usize> { |
256 | 4.20k | if width <= 0 || length <= 0 { |
257 | 10 | None |
258 | | } else { |
259 | 4.19k | match channels.checked_mul(width as usize) { |
260 | 4.19k | Some(n) => n.checked_mul(length as usize), |
261 | 0 | None => None, |
262 | | } |
263 | | } |
264 | 4.20k | } |
265 | | |
266 | | /// Call the provided function on each row of the provided buffer, returning Err if the provided |
267 | | /// function returns an error, extends the buffer if it's not large enough. |
268 | 1.94k | fn with_rows<F>( |
269 | 1.94k | buffer: &mut [u8], |
270 | 1.94k | width: i32, |
271 | 1.94k | height: i32, |
272 | 1.94k | channels: usize, |
273 | 1.94k | top_down: bool, |
274 | 1.94k | mut func: F, |
275 | 1.94k | ) -> io::Result<()> |
276 | 1.94k | where |
277 | 1.94k | F: FnMut(&mut [u8]) -> io::Result<()>, |
278 | | { |
279 | | // An overflow should already have been checked for when this is called, |
280 | | // though we check anyhow, as it somehow seems to increase performance slightly. |
281 | 1.94k | let row_width = channels.checked_mul(width as usize).unwrap(); |
282 | 1.94k | let full_image_size = row_width.checked_mul(height as usize).unwrap(); |
283 | 1.94k | assert_eq!(buffer.len(), full_image_size); |
284 | | |
285 | 1.94k | if !top_down { |
286 | 1.23M | for row in buffer.chunks_mut(row_width).rev() { |
287 | 1.23M | func(row)?; |
288 | | } |
289 | | } else { |
290 | 4.07M | for row in buffer.chunks_mut(row_width) { |
291 | 4.07M | func(row)?; |
292 | | } |
293 | | } |
294 | 284 | Ok(()) |
295 | 1.94k | } image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_16_bit_pixel_data::{closure#0}>Line | Count | Source | 268 | 334 | fn with_rows<F>( | 269 | 334 | buffer: &mut [u8], | 270 | 334 | width: i32, | 271 | 334 | height: i32, | 272 | 334 | channels: usize, | 273 | 334 | top_down: bool, | 274 | 334 | mut func: F, | 275 | 334 | ) -> io::Result<()> | 276 | 334 | where | 277 | 334 | F: FnMut(&mut [u8]) -> io::Result<()>, | 278 | | { | 279 | | // An overflow should already have been checked for when this is called, | 280 | | // though we check anyhow, as it somehow seems to increase performance slightly. | 281 | 334 | let row_width = channels.checked_mul(width as usize).unwrap(); | 282 | 334 | let full_image_size = row_width.checked_mul(height as usize).unwrap(); | 283 | 334 | assert_eq!(buffer.len(), full_image_size); | 284 | | | 285 | 334 | if !top_down { | 286 | 276k | for row in buffer.chunks_mut(row_width).rev() { | 287 | 276k | func(row)?; | 288 | | } | 289 | | } else { | 290 | 1.39M | for row in buffer.chunks_mut(row_width) { | 291 | 1.39M | func(row)?; | 292 | | } | 293 | | } | 294 | 47 | Ok(()) | 295 | 334 | } |
image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_32_bit_pixel_data::{closure#0}>Line | Count | Source | 268 | 280 | fn with_rows<F>( | 269 | 280 | buffer: &mut [u8], | 270 | 280 | width: i32, | 271 | 280 | height: i32, | 272 | 280 | channels: usize, | 273 | 280 | top_down: bool, | 274 | 280 | mut func: F, | 275 | 280 | ) -> io::Result<()> | 276 | 280 | where | 277 | 280 | F: FnMut(&mut [u8]) -> io::Result<()>, | 278 | | { | 279 | | // An overflow should already have been checked for when this is called, | 280 | | // though we check anyhow, as it somehow seems to increase performance slightly. | 281 | 280 | let row_width = channels.checked_mul(width as usize).unwrap(); | 282 | 280 | let full_image_size = row_width.checked_mul(height as usize).unwrap(); | 283 | 280 | assert_eq!(buffer.len(), full_image_size); | 284 | | | 285 | 280 | if !top_down { | 286 | 110k | for row in buffer.chunks_mut(row_width).rev() { | 287 | 110k | func(row)?; | 288 | | } | 289 | | } else { | 290 | 5.63k | for row in buffer.chunks_mut(row_width) { | 291 | 5.63k | func(row)?; | 292 | | } | 293 | | } | 294 | 18 | Ok(()) | 295 | 280 | } |
image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_full_byte_pixel_data::{closure#0}>Line | Count | Source | 268 | 423 | fn with_rows<F>( | 269 | 423 | buffer: &mut [u8], | 270 | 423 | width: i32, | 271 | 423 | height: i32, | 272 | 423 | channels: usize, | 273 | 423 | top_down: bool, | 274 | 423 | mut func: F, | 275 | 423 | ) -> io::Result<()> | 276 | 423 | where | 277 | 423 | F: FnMut(&mut [u8]) -> io::Result<()>, | 278 | | { | 279 | | // An overflow should already have been checked for when this is called, | 280 | | // though we check anyhow, as it somehow seems to increase performance slightly. | 281 | 423 | let row_width = channels.checked_mul(width as usize).unwrap(); | 282 | 423 | let full_image_size = row_width.checked_mul(height as usize).unwrap(); | 283 | 423 | assert_eq!(buffer.len(), full_image_size); | 284 | | | 285 | 423 | if !top_down { | 286 | 403k | for row in buffer.chunks_mut(row_width).rev() { | 287 | 403k | func(row)?; | 288 | | } | 289 | | } else { | 290 | 2.50M | for row in buffer.chunks_mut(row_width) { | 291 | 2.50M | func(row)?; | 292 | | } | 293 | | } | 294 | 59 | Ok(()) | 295 | 423 | } |
image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data::{closure#1}>Line | Count | Source | 268 | 905 | fn with_rows<F>( | 269 | 905 | buffer: &mut [u8], | 270 | 905 | width: i32, | 271 | 905 | height: i32, | 272 | 905 | channels: usize, | 273 | 905 | top_down: bool, | 274 | 905 | mut func: F, | 275 | 905 | ) -> io::Result<()> | 276 | 905 | where | 277 | 905 | F: FnMut(&mut [u8]) -> io::Result<()>, | 278 | | { | 279 | | // An overflow should already have been checked for when this is called, | 280 | | // though we check anyhow, as it somehow seems to increase performance slightly. | 281 | 905 | let row_width = channels.checked_mul(width as usize).unwrap(); | 282 | 905 | let full_image_size = row_width.checked_mul(height as usize).unwrap(); | 283 | 905 | assert_eq!(buffer.len(), full_image_size); | 284 | | | 285 | 905 | if !top_down { | 286 | 447k | for row in buffer.chunks_mut(row_width).rev() { | 287 | 447k | func(row)?; | 288 | | } | 289 | | } else { | 290 | 166k | for row in buffer.chunks_mut(row_width) { | 291 | 166k | func(row)?; | 292 | | } | 293 | | } | 294 | 160 | Ok(()) | 295 | 905 | } |
|
296 | | |
297 | 2.92k | fn set_8bit_pixel_run<'a, T: Iterator<Item = &'a u8>>( |
298 | 2.92k | pixel_iter: &mut ChunksExactMut<u8>, |
299 | 2.92k | palette: &[[u8; 3]], |
300 | 2.92k | indices: T, |
301 | 2.92k | n_pixels: usize, |
302 | 2.92k | ) -> bool { |
303 | 449k | for idx in indices.take(n_pixels) { |
304 | 449k | if let Some(pixel) = pixel_iter.next() { |
305 | 449k | let rgb = palette[*idx as usize]; |
306 | 449k | pixel[0] = rgb[0]; |
307 | 449k | pixel[1] = rgb[1]; |
308 | 449k | pixel[2] = rgb[2]; |
309 | 449k | } else { |
310 | 32 | return false; |
311 | | } |
312 | | } |
313 | 2.89k | true |
314 | 2.92k | } |
315 | | |
316 | 1.04M | fn set_4bit_pixel_run<'a, T: Iterator<Item = &'a u8>>( |
317 | 1.04M | pixel_iter: &mut ChunksExactMut<u8>, |
318 | 1.04M | palette: &[[u8; 3]], |
319 | 1.04M | indices: T, |
320 | 1.04M | mut n_pixels: usize, |
321 | 1.04M | ) -> bool { |
322 | 8.13M | 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 | 7.93M | set_pixel!(idx >> 4); |
340 | 7.17M | set_pixel!(idx & 0xf); |
341 | | } |
342 | 1.04M | true |
343 | 1.04M | } image::codecs::bmp::decoder::set_4bit_pixel_run::<core::slice::iter::Iter<u8>> Line | Count | Source | 316 | 227k | fn set_4bit_pixel_run<'a, T: Iterator<Item = &'a u8>>( | 317 | 227k | pixel_iter: &mut ChunksExactMut<u8>, | 318 | 227k | palette: &[[u8; 3]], | 319 | 227k | indices: T, | 320 | 227k | mut n_pixels: usize, | 321 | 227k | ) -> bool { | 322 | 2.24M | 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 | 2.04M | set_pixel!(idx >> 4); | 340 | 2.03M | set_pixel!(idx & 0xf); | 341 | | } | 342 | 227k | true | 343 | 227k | } |
image::codecs::bmp::decoder::set_4bit_pixel_run::<core::iter::sources::repeat::Repeat<&u8>> Line | Count | Source | 316 | 822k | fn set_4bit_pixel_run<'a, T: Iterator<Item = &'a u8>>( | 317 | 822k | pixel_iter: &mut ChunksExactMut<u8>, | 318 | 822k | palette: &[[u8; 3]], | 319 | 822k | indices: T, | 320 | 822k | mut n_pixels: usize, | 321 | 822k | ) -> bool { | 322 | 5.89M | 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 | 5.89M | set_pixel!(idx >> 4); | 340 | 5.14M | set_pixel!(idx & 0xf); | 341 | | } | 342 | 822k | true | 343 | 822k | } |
|
344 | | |
345 | | #[rustfmt::skip] |
346 | 4.41k | fn set_2bit_pixel_run<'a, T: Iterator<Item = &'a u8>>( |
347 | 4.41k | pixel_iter: &mut ChunksExactMut<u8>, |
348 | 4.41k | palette: &[[u8; 3]], |
349 | 4.41k | indices: T, |
350 | 4.41k | mut n_pixels: usize, |
351 | 4.41k | ) -> bool { |
352 | 375k | 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 | 374k | set_pixel!((idx >> 6) & 0x3u8); |
370 | 373k | set_pixel!((idx >> 4) & 0x3u8); |
371 | 372k | set_pixel!((idx >> 2) & 0x3u8); |
372 | 371k | set_pixel!( idx & 0x3u8); |
373 | | } |
374 | 4.41k | true |
375 | 4.41k | } |
376 | | |
377 | 605k | fn set_1bit_pixel_run<'a, T: Iterator<Item = &'a u8>>( |
378 | 605k | pixel_iter: &mut ChunksExactMut<u8>, |
379 | 605k | palette: &[[u8; 3]], |
380 | 605k | indices: T, |
381 | 605k | ) { |
382 | 2.48M | for idx in indices { |
383 | 2.30M | let mut bit = 0x80; |
384 | | loop { |
385 | 17.3M | if let Some(pixel) = pixel_iter.next() { |
386 | 16.9M | let rgb = palette[usize::from((idx & bit) != 0)]; |
387 | 16.9M | pixel[0] = rgb[0]; |
388 | 16.9M | pixel[1] = rgb[1]; |
389 | 16.9M | pixel[2] = rgb[2]; |
390 | 16.9M | } else { |
391 | 431k | return; |
392 | | } |
393 | | |
394 | 16.9M | bit >>= 1; |
395 | 16.9M | if bit == 0 { |
396 | 1.87M | break; |
397 | 15.0M | } |
398 | | } |
399 | | } |
400 | 605k | } |
401 | | |
402 | | #[derive(PartialEq, Eq)] |
403 | | struct Bitfield { |
404 | | shift: u32, |
405 | | len: u32, |
406 | | } |
407 | | |
408 | | impl Bitfield { |
409 | 2.41k | fn from_mask(mask: u32, max_len: u32) -> ImageResult<Bitfield> { |
410 | 2.41k | if mask == 0 { |
411 | 352 | return Ok(Bitfield { shift: 0, len: 0 }); |
412 | 2.06k | } |
413 | 2.06k | let mut shift = mask.trailing_zeros(); |
414 | 2.06k | let mut len = (!(mask >> shift)).trailing_zeros(); |
415 | 2.06k | if len != mask.count_ones() { |
416 | 58 | return Err(DecoderError::BitfieldMaskNonContiguous.into()); |
417 | 2.00k | } |
418 | 2.00k | if len + shift > max_len { |
419 | 10 | return Err(DecoderError::BitfieldMaskInvalid.into()); |
420 | 1.99k | } |
421 | 1.99k | if len > 8 { |
422 | 666 | shift += len - 8; |
423 | 666 | len = 8; |
424 | 1.33k | } |
425 | 1.99k | Ok(Bitfield { shift, len }) |
426 | 2.41k | } |
427 | | |
428 | 8.28M | fn read(&self, data: u32) -> u8 { |
429 | 8.28M | let data = data >> self.shift; |
430 | 8.28M | match self.len { |
431 | 93.1k | 1 => ((data & 0b1) * 0xff) as u8, |
432 | 64.0k | 2 => ((data & 0b11) * 0x55) as u8, |
433 | 664k | 3 => LOOKUP_TABLE_3_BIT_TO_8_BIT[(data & 0b00_0111) as usize], |
434 | 50.1k | 4 => LOOKUP_TABLE_4_BIT_TO_8_BIT[(data & 0b00_1111) as usize], |
435 | 5.79M | 5 => LOOKUP_TABLE_5_BIT_TO_8_BIT[(data & 0b01_1111) as usize], |
436 | 609k | 6 => LOOKUP_TABLE_6_BIT_TO_8_BIT[(data & 0b11_1111) as usize], |
437 | 3.53k | 7 => (((data & 0x7f) << 1) | ((data & 0x7f) >> 6)) as u8, |
438 | 1.00M | 8 => (data & 0xff) as u8, |
439 | 0 | _ => panic!(), |
440 | | } |
441 | 8.28M | } |
442 | | } |
443 | | |
444 | | #[derive(PartialEq, Eq)] |
445 | | struct Bitfields { |
446 | | r: Bitfield, |
447 | | g: Bitfield, |
448 | | b: Bitfield, |
449 | | a: Bitfield, |
450 | | } |
451 | | |
452 | | impl Bitfields { |
453 | 642 | fn from_mask( |
454 | 642 | r_mask: u32, |
455 | 642 | g_mask: u32, |
456 | 642 | b_mask: u32, |
457 | 642 | a_mask: u32, |
458 | 642 | max_len: u32, |
459 | 642 | ) -> ImageResult<Bitfields> { |
460 | 574 | let bitfields = Bitfields { |
461 | 642 | r: Bitfield::from_mask(r_mask, max_len)?, |
462 | 607 | g: Bitfield::from_mask(g_mask, max_len)?, |
463 | 591 | b: Bitfield::from_mask(b_mask, max_len)?, |
464 | 577 | a: Bitfield::from_mask(a_mask, max_len)?, |
465 | | }; |
466 | 574 | if bitfields.r.len == 0 || bitfields.g.len == 0 || bitfields.b.len == 0 { |
467 | 9 | return Err(DecoderError::BitfieldMaskMissing(max_len).into()); |
468 | 565 | } |
469 | 565 | Ok(bitfields) |
470 | 642 | } |
471 | | } |
472 | | |
473 | | /// A bmp decoder |
474 | | pub 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 | | |
495 | | enum RLEInsn { |
496 | | EndOfFile, |
497 | | EndOfRow, |
498 | | Delta(u8, u8), |
499 | | Absolute(u8, Vec<u8>), |
500 | | PixelRun(u8, u8), |
501 | | } |
502 | | |
503 | | impl<R: BufRead + Seek> BmpDecoder<R> { |
504 | 4.55k | fn new_decoder(reader: R) -> BmpDecoder<R> { |
505 | 4.55k | BmpDecoder { |
506 | 4.55k | reader, |
507 | 4.55k | |
508 | 4.55k | bmp_header_type: BMPHeaderType::Info, |
509 | 4.55k | indexed_color: false, |
510 | 4.55k | |
511 | 4.55k | width: 0, |
512 | 4.55k | height: 0, |
513 | 4.55k | data_offset: 0, |
514 | 4.55k | top_down: false, |
515 | 4.55k | no_file_header: false, |
516 | 4.55k | add_alpha_channel: false, |
517 | 4.55k | has_loaded_metadata: false, |
518 | 4.55k | image_type: ImageType::Palette, |
519 | 4.55k | |
520 | 4.55k | bit_count: 0, |
521 | 4.55k | colors_used: 0, |
522 | 4.55k | palette: None, |
523 | 4.55k | bitfields: None, |
524 | 4.55k | } |
525 | 4.55k | } |
526 | | |
527 | | /// Create a new decoder that decodes from the stream ```r``` |
528 | 2.06k | pub fn new(reader: R) -> ImageResult<BmpDecoder<R>> { |
529 | 2.06k | let mut decoder = Self::new_decoder(reader); |
530 | 2.06k | decoder.read_metadata()?; |
531 | 1.53k | Ok(decoder) |
532 | 2.06k | } |
533 | | |
534 | | /// Create a new decoder that decodes from the stream ```r``` without first |
535 | | /// reading a BITMAPFILEHEADER. This is useful for decoding the `CF_DIB` format |
536 | | /// directly from the Windows clipboard. |
537 | 0 | pub fn new_without_file_header(reader: R) -> ImageResult<BmpDecoder<R>> { |
538 | 0 | let mut decoder = Self::new_decoder(reader); |
539 | 0 | decoder.no_file_header = true; |
540 | 0 | decoder.read_metadata()?; |
541 | 0 | Ok(decoder) |
542 | 0 | } |
543 | | |
544 | | #[cfg(feature = "ico")] |
545 | 2.49k | pub(crate) fn new_with_ico_format(reader: R) -> ImageResult<BmpDecoder<R>> { |
546 | 2.49k | let mut decoder = Self::new_decoder(reader); |
547 | 2.49k | decoder.read_metadata_in_ico_format()?; |
548 | 1.91k | Ok(decoder) |
549 | 2.49k | } |
550 | | |
551 | | /// If true, the palette in BMP does not apply to the image even if it is found. |
552 | | /// In other words, the output image is the indexed color. |
553 | 0 | pub fn set_indexed_color(&mut self, indexed_color: bool) { |
554 | 0 | self.indexed_color = indexed_color; |
555 | 0 | } |
556 | | |
557 | | #[cfg(feature = "ico")] |
558 | 527 | pub(crate) fn reader(&mut self) -> &mut R { |
559 | 527 | &mut self.reader |
560 | 527 | } |
561 | | |
562 | 4.55k | fn read_file_header(&mut self) -> ImageResult<()> { |
563 | 4.55k | if self.no_file_header { |
564 | 2.49k | return Ok(()); |
565 | 2.06k | } |
566 | 2.06k | let mut signature = [0; 2]; |
567 | 2.06k | self.reader.read_exact(&mut signature)?; |
568 | | |
569 | 2.05k | if signature != b"BM"[..] { |
570 | 25 | return Err(DecoderError::BmpSignatureInvalid.into()); |
571 | 2.02k | } |
572 | | |
573 | | // The next 8 bytes represent file size, followed the 4 reserved bytes |
574 | | // We're not interesting these values |
575 | 2.02k | self.reader.read_u32::<LittleEndian>()?; |
576 | 2.02k | self.reader.read_u32::<LittleEndian>()?; |
577 | | |
578 | 2.01k | self.data_offset = u64::from(self.reader.read_u32::<LittleEndian>()?); |
579 | | |
580 | 2.01k | Ok(()) |
581 | 4.55k | } |
582 | | |
583 | | /// Read BITMAPCOREHEADER <https://msdn.microsoft.com/en-us/library/vs/alm/dd183372(v=vs.85).aspx> |
584 | | /// |
585 | | /// returns Err if any of the values are invalid. |
586 | 802 | fn read_bitmap_core_header(&mut self) -> ImageResult<()> { |
587 | | // As height/width values in BMP files with core headers are only 16 bits long, |
588 | | // they won't be larger than `MAX_WIDTH_HEIGHT`. |
589 | 802 | self.width = i32::from(self.reader.read_u16::<LittleEndian>()?); |
590 | 800 | self.height = i32::from(self.reader.read_u16::<LittleEndian>()?); |
591 | | |
592 | 798 | check_for_overflow(self.width, self.height, self.num_channels())?; |
593 | | |
594 | | // Number of planes (format specifies that this should be 1). |
595 | 793 | if self.reader.read_u16::<LittleEndian>()? != 1 { |
596 | 42 | return Err(DecoderError::MoreThanOnePlane.into()); |
597 | 730 | } |
598 | | |
599 | 730 | self.bit_count = self.reader.read_u16::<LittleEndian>()?; |
600 | 726 | self.image_type = match self.bit_count { |
601 | 555 | 1 | 4 | 8 => ImageType::Palette, |
602 | 164 | 24 => ImageType::RGB24, |
603 | | _ => { |
604 | 7 | return Err(DecoderError::InvalidChannelWidth( |
605 | 7 | ChannelWidthError::Rgb, |
606 | 7 | self.bit_count, |
607 | 7 | ) |
608 | 7 | .into()) |
609 | | } |
610 | | }; |
611 | | |
612 | 719 | Ok(()) |
613 | 802 | } |
614 | | |
615 | | /// Read BITMAPINFOHEADER <https://msdn.microsoft.com/en-us/library/vs/alm/dd183376(v=vs.85).aspx> |
616 | | /// or BITMAPV{2|3|4|5}HEADER. |
617 | | /// |
618 | | /// returns Err if any of the values are invalid. |
619 | 3.53k | fn read_bitmap_info_header(&mut self) -> ImageResult<()> { |
620 | 3.53k | self.width = self.reader.read_i32::<LittleEndian>()?; |
621 | 3.52k | self.height = self.reader.read_i32::<LittleEndian>()?; |
622 | | |
623 | | // Width can not be negative |
624 | 3.51k | if self.width < 0 { |
625 | 65 | return Err(DecoderError::NegativeWidth(self.width).into()); |
626 | 3.45k | } else if self.width > MAX_WIDTH_HEIGHT || self.height > MAX_WIDTH_HEIGHT { |
627 | | // Limit very large image sizes to avoid OOM issues. Images with these sizes are |
628 | | // unlikely to be valid anyhow. |
629 | 38 | return Err(DecoderError::ImageTooLarge(self.width, self.height).into()); |
630 | 3.41k | } |
631 | | |
632 | 3.41k | if self.height == i32::MIN { |
633 | 2 | return Err(DecoderError::InvalidHeight.into()); |
634 | 3.41k | } |
635 | | |
636 | | // A negative height indicates a top-down DIB. |
637 | 3.41k | if self.height < 0 { |
638 | 598 | self.height *= -1; |
639 | 598 | self.top_down = true; |
640 | 2.81k | } |
641 | | |
642 | 3.41k | check_for_overflow(self.width, self.height, self.num_channels())?; |
643 | | |
644 | | // Number of planes (format specifies that this should be 1). |
645 | 3.40k | if self.reader.read_u16::<LittleEndian>()? != 1 { |
646 | 75 | return Err(DecoderError::MoreThanOnePlane.into()); |
647 | 3.24k | } |
648 | | |
649 | 3.24k | self.bit_count = self.reader.read_u16::<LittleEndian>()?; |
650 | 3.24k | let image_type_u32 = self.reader.read_u32::<LittleEndian>()?; |
651 | | |
652 | | // Top-down dibs can not be compressed. |
653 | 3.23k | if self.top_down && image_type_u32 != 0 && image_type_u32 != 3 { |
654 | 2 | return Err(DecoderError::ImageTypeInvalidForTopDown(image_type_u32).into()); |
655 | 3.23k | } |
656 | 3.23k | self.image_type = match image_type_u32 { |
657 | 126 | 0 => match self.bit_count { |
658 | 497 | 1 | 2 | 4 | 8 => ImageType::Palette, |
659 | 202 | 16 => ImageType::RGB16, |
660 | 39 | 24 => ImageType::RGB24, |
661 | 56 | 32 if self.add_alpha_channel => ImageType::RGBA32, |
662 | 70 | 32 => ImageType::RGB32, |
663 | | _ => { |
664 | 2 | return Err(DecoderError::InvalidChannelWidth( |
665 | 2 | ChannelWidthError::Rgb, |
666 | 2 | self.bit_count, |
667 | 2 | ) |
668 | 2 | .into()) |
669 | | } |
670 | | }, |
671 | 611 | 1 => match self.bit_count { |
672 | 580 | 8 => ImageType::RLE8, |
673 | | _ => { |
674 | 31 | return Err(DecoderError::InvalidChannelWidth( |
675 | 31 | ChannelWidthError::Rle8, |
676 | 31 | self.bit_count, |
677 | 31 | ) |
678 | 31 | .into()) |
679 | | } |
680 | | }, |
681 | 984 | 2 => match self.bit_count { |
682 | 951 | 4 => ImageType::RLE4, |
683 | | _ => { |
684 | 33 | return Err(DecoderError::InvalidChannelWidth( |
685 | 33 | ChannelWidthError::Rle4, |
686 | 33 | self.bit_count, |
687 | 33 | ) |
688 | 33 | .into()) |
689 | | } |
690 | | }, |
691 | 677 | 3 => match self.bit_count { |
692 | 181 | 16 => ImageType::Bitfields16, |
693 | 493 | 32 => ImageType::Bitfields32, |
694 | | _ => { |
695 | 3 | return Err(DecoderError::InvalidChannelWidth( |
696 | 3 | ChannelWidthError::Bitfields, |
697 | 3 | self.bit_count, |
698 | 3 | ) |
699 | 3 | .into()) |
700 | | } |
701 | | }, |
702 | | 4 => { |
703 | | // JPEG compression is not implemented yet. |
704 | 2 | return Err(ImageError::Unsupported( |
705 | 2 | UnsupportedError::from_format_and_kind( |
706 | 2 | ImageFormat::Bmp.into(), |
707 | 2 | UnsupportedErrorKind::GenericFeature("JPEG compression".to_owned()), |
708 | 2 | ), |
709 | 2 | )); |
710 | | } |
711 | | 5 => { |
712 | | // PNG compression is not implemented yet. |
713 | 2 | return Err(ImageError::Unsupported( |
714 | 2 | UnsupportedError::from_format_and_kind( |
715 | 2 | ImageFormat::Bmp.into(), |
716 | 2 | UnsupportedErrorKind::GenericFeature("PNG compression".to_owned()), |
717 | 2 | ), |
718 | 2 | )); |
719 | | } |
720 | 90 | 11..=13 => { |
721 | | // CMYK types are not implemented yet. |
722 | 3 | return Err(ImageError::Unsupported( |
723 | 3 | UnsupportedError::from_format_and_kind( |
724 | 3 | ImageFormat::Bmp.into(), |
725 | 3 | UnsupportedErrorKind::GenericFeature("CMYK format".to_owned()), |
726 | 3 | ), |
727 | 3 | )); |
728 | | } |
729 | | _ => { |
730 | | // Unknown compression type. |
731 | 92 | return Err(DecoderError::ImageTypeUnknown(image_type_u32).into()); |
732 | | } |
733 | | }; |
734 | | |
735 | | // The next 12 bytes represent data array size in bytes, |
736 | | // followed the horizontal and vertical printing resolutions |
737 | | // We will calculate the pixel array size using width & height of image |
738 | | // We're not interesting the horz or vert printing resolutions |
739 | 3.06k | self.reader.read_u32::<LittleEndian>()?; |
740 | 3.04k | self.reader.read_u32::<LittleEndian>()?; |
741 | 3.03k | self.reader.read_u32::<LittleEndian>()?; |
742 | | |
743 | 3.03k | self.colors_used = self.reader.read_u32::<LittleEndian>()?; |
744 | | |
745 | | // The next 4 bytes represent number of "important" colors |
746 | | // We're not interested in this value, so we'll skip it |
747 | 3.02k | self.reader.read_u32::<LittleEndian>()?; |
748 | | |
749 | 3.01k | Ok(()) |
750 | 3.53k | } |
751 | | |
752 | 667 | fn read_bitmasks(&mut self) -> ImageResult<()> { |
753 | 667 | let r_mask = self.reader.read_u32::<LittleEndian>()?; |
754 | 659 | let g_mask = self.reader.read_u32::<LittleEndian>()?; |
755 | 654 | let b_mask = self.reader.read_u32::<LittleEndian>()?; |
756 | | |
757 | 645 | let a_mask = match self.bmp_header_type { |
758 | | BMPHeaderType::V3 | BMPHeaderType::V4 | BMPHeaderType::V5 => { |
759 | 286 | self.reader.read_u32::<LittleEndian>()? |
760 | | } |
761 | 359 | _ => 0, |
762 | | }; |
763 | | |
764 | 642 | self.bitfields = match self.image_type { |
765 | | ImageType::Bitfields16 => { |
766 | 171 | Some(Bitfields::from_mask(r_mask, g_mask, b_mask, a_mask, 16)?) |
767 | | } |
768 | | ImageType::Bitfields32 => { |
769 | 471 | Some(Bitfields::from_mask(r_mask, g_mask, b_mask, a_mask, 32)?) |
770 | | } |
771 | 0 | _ => None, |
772 | | }; |
773 | | |
774 | 565 | if self.bitfields.is_some() && a_mask != 0 { |
775 | 245 | self.add_alpha_channel = true; |
776 | 320 | } |
777 | | |
778 | 565 | Ok(()) |
779 | 667 | } |
780 | | |
781 | 4.55k | fn read_metadata(&mut self) -> ImageResult<()> { |
782 | 4.55k | if !self.has_loaded_metadata { |
783 | 4.55k | self.read_file_header()?; |
784 | 4.50k | let bmp_header_offset = self.reader.stream_position()?; |
785 | 4.50k | let bmp_header_size = self.reader.read_u32::<LittleEndian>()?; |
786 | 4.50k | let bmp_header_end = bmp_header_offset + u64::from(bmp_header_size); |
787 | | |
788 | 171 | self.bmp_header_type = match bmp_header_size { |
789 | 802 | BITMAPCOREHEADER_SIZE => BMPHeaderType::Core, |
790 | 2.72k | BITMAPINFOHEADER_SIZE => BMPHeaderType::Info, |
791 | 198 | BITMAPV2HEADER_SIZE => BMPHeaderType::V2, |
792 | 419 | BITMAPV3HEADER_SIZE => BMPHeaderType::V3, |
793 | 113 | BITMAPV4HEADER_SIZE => BMPHeaderType::V4, |
794 | 76 | BITMAPV5HEADER_SIZE => BMPHeaderType::V5, |
795 | 171 | _ if bmp_header_size < BITMAPCOREHEADER_SIZE => { |
796 | | // Size of any valid header types won't be smaller than core header type. |
797 | 13 | return Err(DecoderError::HeaderTooSmall(bmp_header_size).into()); |
798 | | } |
799 | | _ => { |
800 | 158 | return Err(ImageError::Unsupported( |
801 | 158 | UnsupportedError::from_format_and_kind( |
802 | 158 | ImageFormat::Bmp.into(), |
803 | 158 | UnsupportedErrorKind::GenericFeature(format!( |
804 | 158 | "Unknown bitmap header type (size={bmp_header_size})" |
805 | 158 | )), |
806 | 158 | ), |
807 | 158 | )) |
808 | | } |
809 | | }; |
810 | | |
811 | 4.33k | match self.bmp_header_type { |
812 | | BMPHeaderType::Core => { |
813 | 802 | self.read_bitmap_core_header()?; |
814 | | } |
815 | | BMPHeaderType::Info |
816 | | | BMPHeaderType::V2 |
817 | | | BMPHeaderType::V3 |
818 | | | BMPHeaderType::V4 |
819 | | | BMPHeaderType::V5 => { |
820 | 3.53k | self.read_bitmap_info_header()?; |
821 | | } |
822 | | } |
823 | | |
824 | 3.73k | let mut bitmask_bytes_offset = 0; |
825 | 3.73k | if self.image_type == ImageType::Bitfields16 |
826 | 3.55k | || self.image_type == ImageType::Bitfields32 |
827 | | { |
828 | 667 | self.read_bitmasks()?; |
829 | | |
830 | | // Per https://learn.microsoft.com/en-us/windows/win32/gdi/bitmap-header-types, bitmaps |
831 | | // using the `BITMAPINFOHEADER`, `BITMAPV4HEADER`, or `BITMAPV5HEADER` structures with |
832 | | // an image type of `BI_BITFIELD` contain RGB bitfield masks immediately after the header. |
833 | | // |
834 | | // `read_bitmasks` correctly reads these from earlier in the header itself but we must |
835 | | // ensure the reader starts on the image data itself, not these extra mask bytes. |
836 | 284 | if matches!( |
837 | 565 | self.bmp_header_type, |
838 | | BMPHeaderType::Info | BMPHeaderType::V4 | BMPHeaderType::V5 |
839 | 281 | ) { |
840 | 281 | // This is `size_of::<u32>() * 3` (a red, green, and blue mask), but with less noise. |
841 | 281 | bitmask_bytes_offset = 12; |
842 | 284 | } |
843 | 3.07k | }; |
844 | | |
845 | 3.63k | self.reader |
846 | 3.63k | .seek(SeekFrom::Start(bmp_header_end + bitmask_bytes_offset))?; |
847 | | |
848 | 3.63k | match self.image_type { |
849 | 2.55k | ImageType::Palette | ImageType::RLE4 | ImageType::RLE8 => self.read_palette()?, |
850 | 1.08k | _ => {} |
851 | | } |
852 | | |
853 | 3.44k | if self.no_file_header { |
854 | | // Use the offset of the end of metadata instead of reading a BMP file header. |
855 | 1.91k | self.data_offset = self.reader.stream_position()?; |
856 | 1.53k | } |
857 | | |
858 | 3.44k | self.has_loaded_metadata = true; |
859 | 0 | } |
860 | 3.44k | Ok(()) |
861 | 4.55k | } |
862 | | |
863 | | #[cfg(feature = "ico")] |
864 | | #[doc(hidden)] |
865 | 2.49k | pub fn read_metadata_in_ico_format(&mut self) -> ImageResult<()> { |
866 | 2.49k | self.no_file_header = true; |
867 | 2.49k | self.add_alpha_channel = true; |
868 | 2.49k | self.read_metadata()?; |
869 | | |
870 | | // The height field in an ICO file is doubled to account for the AND mask |
871 | | // (whether or not an AND mask is actually present). |
872 | 1.91k | self.height /= 2; |
873 | 1.91k | Ok(()) |
874 | 2.49k | } |
875 | | |
876 | 2.55k | fn get_palette_size(&mut self) -> ImageResult<usize> { |
877 | 2.55k | match self.colors_used { |
878 | 837 | 0 => Ok(1 << self.bit_count), |
879 | | _ => { |
880 | 1.71k | if self.colors_used > 1 << self.bit_count { |
881 | 140 | return Err(DecoderError::PaletteSizeExceeded { |
882 | 140 | colors_used: self.colors_used, |
883 | 140 | bit_count: self.bit_count, |
884 | 140 | } |
885 | 140 | .into()); |
886 | 1.57k | } |
887 | 1.57k | Ok(self.colors_used as usize) |
888 | | } |
889 | | } |
890 | 2.55k | } |
891 | | |
892 | 2.55k | fn bytes_per_color(&self) -> usize { |
893 | 2.55k | match self.bmp_header_type { |
894 | 555 | BMPHeaderType::Core => 3, |
895 | 1.99k | _ => 4, |
896 | | } |
897 | 2.55k | } |
898 | | |
899 | 2.55k | fn read_palette(&mut self) -> ImageResult<()> { |
900 | | const MAX_PALETTE_SIZE: usize = 256; // Palette indices are u8. |
901 | | |
902 | 2.55k | let bytes_per_color = self.bytes_per_color(); |
903 | 2.55k | let palette_size = self.get_palette_size()?; |
904 | 2.41k | let max_length = MAX_PALETTE_SIZE * bytes_per_color; |
905 | | |
906 | 2.41k | let length = palette_size * bytes_per_color; |
907 | 2.41k | let mut buf = vec_try_with_capacity(max_length)?; |
908 | | |
909 | | // Resize and read the palette entries to the buffer. |
910 | | // We limit the buffer to at most 256 colours to avoid any oom issues as |
911 | | // 8-bit images can't reference more than 256 indexes anyhow. |
912 | 2.41k | buf.resize(cmp::min(length, max_length), 0); |
913 | 2.41k | self.reader.by_ref().read_exact(&mut buf)?; |
914 | | |
915 | | // Allocate 256 entries even if palette_size is smaller, to prevent corrupt files from |
916 | | // causing an out-of-bounds array access. |
917 | 2.36k | match length.cmp(&max_length) { |
918 | | Ordering::Greater => { |
919 | 0 | self.reader |
920 | 0 | .seek(SeekFrom::Current((length - max_length) as i64))?; |
921 | | } |
922 | 2.33k | Ordering::Less => buf.resize(max_length, 0), |
923 | 33 | Ordering::Equal => (), |
924 | | } |
925 | | |
926 | 2.36k | let p: Vec<[u8; 3]> = (0..MAX_PALETTE_SIZE) |
927 | 605k | .map(|i| { |
928 | 605k | let b = buf[bytes_per_color * i]; |
929 | 605k | let g = buf[bytes_per_color * i + 1]; |
930 | 605k | let r = buf[bytes_per_color * i + 2]; |
931 | 605k | [r, g, b] |
932 | 605k | }) |
933 | 2.36k | .collect(); |
934 | | |
935 | 2.36k | self.palette = Some(p); |
936 | | |
937 | 2.36k | Ok(()) |
938 | 2.55k | } |
939 | | |
940 | | /// Get the palette that is embedded in the BMP image, if any. |
941 | 0 | pub fn get_palette(&self) -> Option<&[[u8; 3]]> { |
942 | 0 | self.palette.as_ref().map(|vec| &vec[..]) |
943 | 0 | } |
944 | | |
945 | 8.98k | fn num_channels(&self) -> usize { |
946 | 8.98k | if self.indexed_color { |
947 | 0 | 1 |
948 | 8.98k | } else if self.add_alpha_channel { |
949 | 5.21k | 4 |
950 | | } else { |
951 | 3.77k | 3 |
952 | | } |
953 | 8.98k | } |
954 | | |
955 | 1.41k | fn rows<'a>(&self, pixel_data: &'a mut [u8]) -> RowIterator<'a> { |
956 | 1.41k | let stride = self.width as usize * self.num_channels(); |
957 | 1.41k | if self.top_down { |
958 | 0 | RowIterator { |
959 | 0 | chunks: Chunker::FromTop(pixel_data.chunks_exact_mut(stride)), |
960 | 0 | } |
961 | | } else { |
962 | 1.41k | RowIterator { |
963 | 1.41k | chunks: Chunker::FromBottom(pixel_data.chunks_exact_mut(stride).rev()), |
964 | 1.41k | } |
965 | | } |
966 | 1.41k | } |
967 | | |
968 | 905 | fn read_palettized_pixel_data(&mut self, buf: &mut [u8]) -> ImageResult<()> { |
969 | 905 | let num_channels = self.num_channels(); |
970 | 905 | let row_byte_length = ((i32::from(self.bit_count) * self.width + 31) / 32 * 4) as usize; |
971 | 905 | let mut indices = vec![0; row_byte_length]; |
972 | 905 | let palette = self.palette.as_ref().unwrap(); |
973 | 905 | let bit_count = self.bit_count; |
974 | 905 | let reader = &mut self.reader; |
975 | 905 | let width = self.width as usize; |
976 | 905 | let skip_palette = self.indexed_color; |
977 | | |
978 | 905 | reader.seek(SeekFrom::Start(self.data_offset))?; |
979 | | |
980 | 905 | if num_channels == 4 { |
981 | 4.42G | buf.chunks_exact_mut(4).for_each(|c| c[3] = 0xFF); |
982 | 451 | } |
983 | | |
984 | 905 | with_rows( |
985 | 905 | buf, |
986 | 905 | self.width, |
987 | 905 | self.height, |
988 | 905 | num_channels, |
989 | 905 | self.top_down, |
990 | 613k | |row| { |
991 | 613k | reader.read_exact(&mut indices)?; |
992 | 613k | if skip_palette { |
993 | 0 | row.clone_from_slice(&indices[0..width]); |
994 | 0 | } else { |
995 | 613k | let mut pixel_iter = row.chunks_exact_mut(num_channels); |
996 | 613k | match bit_count { |
997 | 605k | 1 => { |
998 | 605k | set_1bit_pixel_run(&mut pixel_iter, palette, indices.iter()); |
999 | 605k | } |
1000 | 4.41k | 2 => { |
1001 | 4.41k | set_2bit_pixel_run(&mut pixel_iter, palette, indices.iter(), width); |
1002 | 4.41k | } |
1003 | 2.28k | 4 => { |
1004 | 2.28k | set_4bit_pixel_run(&mut pixel_iter, palette, indices.iter(), width); |
1005 | 2.28k | } |
1006 | 1.37k | 8 => { |
1007 | 1.37k | set_8bit_pixel_run(&mut pixel_iter, palette, indices.iter(), width); |
1008 | 1.37k | } |
1009 | 0 | _ => panic!(), |
1010 | | } |
1011 | | } |
1012 | 613k | Ok(()) |
1013 | 613k | }, |
1014 | 745 | )?; |
1015 | | |
1016 | 160 | Ok(()) |
1017 | 905 | } |
1018 | | |
1019 | 334 | fn read_16_bit_pixel_data( |
1020 | 334 | &mut self, |
1021 | 334 | buf: &mut [u8], |
1022 | 334 | bitfields: Option<&Bitfields>, |
1023 | 334 | ) -> ImageResult<()> { |
1024 | 334 | let num_channels = self.num_channels(); |
1025 | 334 | let row_padding_len = self.width as usize % 2 * 2; |
1026 | 334 | let row_padding = &mut [0; 2][..row_padding_len]; |
1027 | 334 | let bitfields = match bitfields { |
1028 | 192 | Some(b) => b, |
1029 | 142 | None => self.bitfields.as_ref().unwrap(), |
1030 | | }; |
1031 | 334 | let reader = &mut self.reader; |
1032 | | |
1033 | 334 | reader.seek(SeekFrom::Start(self.data_offset))?; |
1034 | | |
1035 | 334 | with_rows( |
1036 | 334 | buf, |
1037 | 334 | self.width, |
1038 | 334 | self.height, |
1039 | 334 | num_channels, |
1040 | 334 | self.top_down, |
1041 | 1.67M | |row| { |
1042 | 2.29M | for pixel in row.chunks_mut(num_channels) { |
1043 | 2.29M | let data = u32::from(reader.read_u16::<LittleEndian>()?); |
1044 | | |
1045 | 2.29M | pixel[0] = bitfields.r.read(data); |
1046 | 2.29M | pixel[1] = bitfields.g.read(data); |
1047 | 2.29M | pixel[2] = bitfields.b.read(data); |
1048 | 2.29M | if num_channels == 4 { |
1049 | 994k | if bitfields.a.len != 0 { |
1050 | 359k | pixel[3] = bitfields.a.read(data); |
1051 | 634k | } else { |
1052 | 634k | pixel[3] = 0xFF; |
1053 | 634k | } |
1054 | 1.29M | } |
1055 | | } |
1056 | 1.67M | reader.read_exact(row_padding) |
1057 | 1.67M | }, |
1058 | 287 | )?; |
1059 | | |
1060 | 47 | Ok(()) |
1061 | 334 | } |
1062 | | |
1063 | | /// Read image data from a reader in 32-bit formats that use bitfields. |
1064 | 280 | fn read_32_bit_pixel_data(&mut self, buf: &mut [u8]) -> ImageResult<()> { |
1065 | 280 | let num_channels = self.num_channels(); |
1066 | | |
1067 | 280 | let bitfields = self.bitfields.as_ref().unwrap(); |
1068 | | |
1069 | 280 | let reader = &mut self.reader; |
1070 | 280 | reader.seek(SeekFrom::Start(self.data_offset))?; |
1071 | | |
1072 | 280 | with_rows( |
1073 | 280 | buf, |
1074 | 280 | self.width, |
1075 | 280 | self.height, |
1076 | 280 | num_channels, |
1077 | 280 | self.top_down, |
1078 | 116k | |row| { |
1079 | 314k | for pixel in row.chunks_mut(num_channels) { |
1080 | 314k | let data = reader.read_u32::<LittleEndian>()?; |
1081 | | |
1082 | 313k | pixel[0] = bitfields.r.read(data); |
1083 | 313k | pixel[1] = bitfields.g.read(data); |
1084 | 313k | pixel[2] = bitfields.b.read(data); |
1085 | 313k | if num_channels == 4 { |
1086 | 207k | if bitfields.a.len != 0 { |
1087 | 105k | pixel[3] = bitfields.a.read(data); |
1088 | 105k | } else { |
1089 | 101k | pixel[3] = 0xff; |
1090 | 101k | } |
1091 | 106k | } |
1092 | | } |
1093 | 115k | Ok(()) |
1094 | 116k | }, |
1095 | 262 | )?; |
1096 | | |
1097 | 18 | Ok(()) |
1098 | 280 | } |
1099 | | |
1100 | | /// Read image data from a reader where the colours are stored as 8-bit values (24 or 32-bit). |
1101 | 423 | fn read_full_byte_pixel_data( |
1102 | 423 | &mut self, |
1103 | 423 | buf: &mut [u8], |
1104 | 423 | format: &FormatFullBytes, |
1105 | 423 | ) -> ImageResult<()> { |
1106 | 423 | let num_channels = self.num_channels(); |
1107 | 423 | let row_padding_len = match *format { |
1108 | 191 | FormatFullBytes::RGB24 => (4 - (self.width as usize * 3) % 4) % 4, |
1109 | 232 | _ => 0, |
1110 | | }; |
1111 | 423 | let row_padding = &mut [0; 4][..row_padding_len]; |
1112 | | |
1113 | 423 | self.reader.seek(SeekFrom::Start(self.data_offset))?; |
1114 | | |
1115 | 423 | let reader = &mut self.reader; |
1116 | | |
1117 | 423 | with_rows( |
1118 | 423 | buf, |
1119 | 423 | self.width, |
1120 | 423 | self.height, |
1121 | 423 | num_channels, |
1122 | 423 | self.top_down, |
1123 | 2.90M | |row| { |
1124 | 5.17M | for pixel in row.chunks_mut(num_channels) { |
1125 | 5.17M | if *format == FormatFullBytes::Format888 { |
1126 | 992k | reader.read_u8()?; |
1127 | 4.17M | } |
1128 | | |
1129 | | // Read the colour values (b, g, r). |
1130 | | // Reading 3 bytes and reversing them is significantly faster than reading one |
1131 | | // at a time. |
1132 | 5.17M | reader.read_exact(&mut pixel[0..3])?; |
1133 | 5.17M | pixel[0..3].reverse(); |
1134 | | |
1135 | 5.17M | if *format == FormatFullBytes::RGB32 { |
1136 | 2.20M | reader.read_u8()?; |
1137 | 2.96M | } |
1138 | | |
1139 | | // Read the alpha channel if present |
1140 | 5.17M | if *format == FormatFullBytes::RGBA32 { |
1141 | 1.96M | reader.read_exact(&mut pixel[3..4])?; |
1142 | 3.21M | } else if num_channels == 4 { |
1143 | 390k | pixel[3] = 0xFF; |
1144 | 2.82M | } |
1145 | | } |
1146 | 2.90M | reader.read_exact(row_padding) |
1147 | 2.90M | }, |
1148 | 364 | )?; |
1149 | | |
1150 | 59 | Ok(()) |
1151 | 423 | } |
1152 | | |
1153 | 1.41k | fn read_rle_data(&mut self, buf: &mut [u8], image_type: ImageType) -> ImageResult<()> { |
1154 | | // Seek to the start of the actual image data. |
1155 | 1.41k | self.reader.seek(SeekFrom::Start(self.data_offset))?; |
1156 | | |
1157 | 1.41k | let num_channels = self.num_channels(); |
1158 | 1.41k | let p = self.palette.as_ref().unwrap(); |
1159 | | |
1160 | | // Handling deltas in the RLE scheme means that we need to manually |
1161 | | // iterate through rows and pixels. Even if we didn't have to handle |
1162 | | // deltas, we have to ensure that a single runlength doesn't straddle |
1163 | | // two rows. |
1164 | 1.41k | let mut row_iter = self.rows(buf); |
1165 | | |
1166 | 489k | while let Some(row) = row_iter.next() { |
1167 | 489k | let mut pixel_iter = row.chunks_exact_mut(num_channels); |
1168 | | |
1169 | 489k | let mut x = 0; |
1170 | | loop { |
1171 | 1.97M | let instruction = { |
1172 | 1.97M | let control_byte = self.reader.read_u8()?; |
1173 | 1.97M | match control_byte { |
1174 | | RLE_ESCAPE => { |
1175 | 1.04M | let op = self.reader.read_u8()?; |
1176 | | |
1177 | 1.04M | match op { |
1178 | 487k | RLE_ESCAPE_EOL => RLEInsn::EndOfRow, |
1179 | 437 | RLE_ESCAPE_EOF => RLEInsn::EndOfFile, |
1180 | | RLE_ESCAPE_DELTA => { |
1181 | 329k | let xdelta = self.reader.read_u8()?; |
1182 | 329k | let ydelta = self.reader.read_u8()?; |
1183 | 329k | RLEInsn::Delta(xdelta, ydelta) |
1184 | | } |
1185 | | _ => { |
1186 | 226k | let mut length = op as usize; |
1187 | 226k | if self.image_type == ImageType::RLE4 { |
1188 | 225k | length = length.div_ceil(2); |
1189 | 225k | } |
1190 | 226k | length += length & 1; |
1191 | 226k | let mut buffer = Vec::new(); |
1192 | 226k | self.reader.read_exact_vec(&mut buffer, length)?; |
1193 | 226k | RLEInsn::Absolute(op, buffer) |
1194 | | } |
1195 | | } |
1196 | | } |
1197 | | _ => { |
1198 | 933k | let palette_index = self.reader.read_u8()?; |
1199 | 933k | RLEInsn::PixelRun(control_byte, palette_index) |
1200 | | } |
1201 | | } |
1202 | | }; |
1203 | | |
1204 | 1.97M | match instruction { |
1205 | | RLEInsn::EndOfFile => { |
1206 | 4.37M | pixel_iter.for_each(|p| p.fill(0)); |
1207 | 3.53M | row_iter.for_each(|r| r.fill(0)); |
1208 | 437 | return Ok(()); |
1209 | | } |
1210 | | RLEInsn::EndOfRow => { |
1211 | 1.14G | pixel_iter.for_each(|p| p.fill(0)); |
1212 | 487k | break; |
1213 | | } |
1214 | 329k | RLEInsn::Delta(x_delta, y_delta) => { |
1215 | | // The msdn site on bitmap compression doesn't specify |
1216 | | // what happens to the values skipped when encountering |
1217 | | // a delta code, however IE and the windows image |
1218 | | // preview seems to replace them with black pixels, |
1219 | | // so we stick to that. |
1220 | | |
1221 | 329k | if y_delta > 0 { |
1222 | | // Zero out the remainder of the current row. |
1223 | 211M | pixel_iter.for_each(|p| p.fill(0)); |
1224 | | |
1225 | | // If any full rows are skipped, zero them out. |
1226 | 45.9k | for _ in 1..y_delta { |
1227 | 589k | let row = row_iter.next().ok_or(DecoderError::CorruptRleData)?; |
1228 | 589k | row.fill(0); |
1229 | | } |
1230 | | |
1231 | | // Set the pixel iterator to the start of the next row. |
1232 | 45.8k | pixel_iter = row_iter |
1233 | 45.8k | .next() |
1234 | 45.8k | .ok_or(DecoderError::CorruptRleData)? |
1235 | 45.8k | .chunks_exact_mut(num_channels); |
1236 | | |
1237 | | // Zero out the pixels up to the current point in the row. |
1238 | 45.8k | for _ in 0..x { |
1239 | 6.74M | pixel_iter |
1240 | 6.74M | .next() |
1241 | 6.74M | .ok_or(DecoderError::CorruptRleData)? |
1242 | 6.74M | .fill(0); |
1243 | | } |
1244 | 283k | } |
1245 | | |
1246 | 329k | for _ in 0..x_delta { |
1247 | 1.53M | let pixel = pixel_iter.next().ok_or(DecoderError::CorruptRleData)?; |
1248 | 1.53M | pixel.fill(0); |
1249 | | } |
1250 | 329k | x += x_delta as usize; |
1251 | | } |
1252 | 226k | RLEInsn::Absolute(length, indices) => { |
1253 | | // Absolute mode cannot span rows, so if we run |
1254 | | // out of pixels to process, we should stop |
1255 | | // processing the image. |
1256 | 226k | match image_type { |
1257 | | ImageType::RLE8 => { |
1258 | 1.54k | if !set_8bit_pixel_run( |
1259 | 1.54k | &mut pixel_iter, |
1260 | 1.54k | p, |
1261 | 1.54k | indices.iter(), |
1262 | 1.54k | length as usize, |
1263 | 1.54k | ) { |
1264 | 32 | return Err(DecoderError::CorruptRleData.into()); |
1265 | 1.51k | } |
1266 | | } |
1267 | | ImageType::RLE4 => { |
1268 | 224k | if !set_4bit_pixel_run( |
1269 | 224k | &mut pixel_iter, |
1270 | 224k | p, |
1271 | 224k | indices.iter(), |
1272 | 224k | length as usize, |
1273 | 224k | ) { |
1274 | 41 | return Err(DecoderError::CorruptRleData.into()); |
1275 | 224k | } |
1276 | | } |
1277 | 0 | _ => unreachable!(), |
1278 | | } |
1279 | 226k | x += length as usize; |
1280 | | } |
1281 | 933k | RLEInsn::PixelRun(n_pixels, palette_index) => { |
1282 | 933k | match image_type { |
1283 | | ImageType::RLE8 => { |
1284 | | // A pixel run isn't allowed to span rows. |
1285 | | // imagemagick produces invalid images where n_pixels exceeds row length, |
1286 | | // so we clamp n_pixels to the row length to display them properly: |
1287 | | // https://github.com/image-rs/image/issues/2321 |
1288 | | // |
1289 | | // This is like set_8bit_pixel_run() but doesn't fail when `n_pixels` is too large |
1290 | 110k | let repeat_pixel: [u8; 3] = p[palette_index as usize]; |
1291 | 1.02M | (&mut pixel_iter).take(n_pixels as usize).for_each(|p| { |
1292 | 1.02M | p[2] = repeat_pixel[2]; |
1293 | 1.02M | p[1] = repeat_pixel[1]; |
1294 | 1.02M | p[0] = repeat_pixel[0]; |
1295 | 1.02M | }); |
1296 | | } |
1297 | | ImageType::RLE4 => { |
1298 | 822k | if !set_4bit_pixel_run( |
1299 | 822k | &mut pixel_iter, |
1300 | 822k | p, |
1301 | 822k | repeat(&palette_index), |
1302 | 822k | n_pixels as usize, |
1303 | 822k | ) { |
1304 | 70 | return Err(DecoderError::CorruptRleData.into()); |
1305 | 822k | } |
1306 | | } |
1307 | 0 | _ => unreachable!(), |
1308 | | } |
1309 | 933k | x += n_pixels as usize; |
1310 | | } |
1311 | | } |
1312 | | } |
1313 | | } |
1314 | | |
1315 | 11 | Ok(()) |
1316 | 1.41k | } |
1317 | | |
1318 | | /// Read the actual data of the image. This function is deliberately not public because it |
1319 | | /// cannot be called multiple times without seeking back the underlying reader in between. |
1320 | 3.35k | pub(crate) fn read_image_data(&mut self, buf: &mut [u8]) -> ImageResult<()> { |
1321 | 3.35k | match self.image_type { |
1322 | 905 | ImageType::Palette => self.read_palettized_pixel_data(buf), |
1323 | 192 | ImageType::RGB16 => self.read_16_bit_pixel_data(buf, Some(&R5_G5_B5_COLOR_MASK)), |
1324 | 191 | ImageType::RGB24 => self.read_full_byte_pixel_data(buf, &FormatFullBytes::RGB24), |
1325 | 57 | ImageType::RGB32 => self.read_full_byte_pixel_data(buf, &FormatFullBytes::RGB32), |
1326 | 55 | ImageType::RGBA32 => self.read_full_byte_pixel_data(buf, &FormatFullBytes::RGBA32), |
1327 | 536 | ImageType::RLE8 => self.read_rle_data(buf, ImageType::RLE8), |
1328 | 880 | ImageType::RLE4 => self.read_rle_data(buf, ImageType::RLE4), |
1329 | 142 | ImageType::Bitfields16 => match self.bitfields { |
1330 | 142 | Some(_) => self.read_16_bit_pixel_data(buf, None), |
1331 | 0 | None => Err(DecoderError::BitfieldMasksMissing(16).into()), |
1332 | | }, |
1333 | 400 | ImageType::Bitfields32 => match self.bitfields { |
1334 | | Some(R8_G8_B8_COLOR_MASK) => { |
1335 | 73 | self.read_full_byte_pixel_data(buf, &FormatFullBytes::Format888) |
1336 | | } |
1337 | | Some(R8_G8_B8_A8_COLOR_MASK) => { |
1338 | 47 | self.read_full_byte_pixel_data(buf, &FormatFullBytes::RGBA32) |
1339 | | } |
1340 | 280 | Some(_) => self.read_32_bit_pixel_data(buf), |
1341 | 0 | None => Err(DecoderError::BitfieldMasksMissing(32).into()), |
1342 | | }, |
1343 | | } |
1344 | 3.35k | } |
1345 | | } |
1346 | | |
1347 | | impl<R: BufRead + Seek> ImageDecoder for BmpDecoder<R> { |
1348 | 19.0k | fn dimensions(&self) -> (u32, u32) { |
1349 | 19.0k | (self.width as u32, self.height as u32) |
1350 | 19.0k | } |
1351 | | |
1352 | 15.5k | fn color_type(&self) -> ColorType { |
1353 | 15.5k | if self.indexed_color { |
1354 | 0 | ColorType::L8 |
1355 | 15.5k | } else if self.add_alpha_channel { |
1356 | 10.2k | ColorType::Rgba8 |
1357 | | } else { |
1358 | 5.34k | ColorType::Rgb8 |
1359 | | } |
1360 | 15.5k | } |
1361 | | |
1362 | 1.50k | fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> { |
1363 | 1.50k | assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes())); |
1364 | 1.50k | self.read_image_data(buf) |
1365 | 1.50k | } |
1366 | | |
1367 | 1.50k | fn read_image_boxed(self: Box<Self>, buf: &mut [u8]) -> ImageResult<()> { |
1368 | 1.50k | (*self).read_image(buf) |
1369 | 1.50k | } |
1370 | | } |
1371 | | |
1372 | | impl<R: BufRead + Seek> ImageDecoderRect for BmpDecoder<R> { |
1373 | 0 | fn read_rect( |
1374 | 0 | &mut self, |
1375 | 0 | x: u32, |
1376 | 0 | y: u32, |
1377 | 0 | width: u32, |
1378 | 0 | height: u32, |
1379 | 0 | buf: &mut [u8], |
1380 | 0 | row_pitch: usize, |
1381 | 0 | ) -> ImageResult<()> { |
1382 | 0 | let start = self.reader.stream_position()?; |
1383 | 0 | load_rect( |
1384 | 0 | x, |
1385 | 0 | y, |
1386 | 0 | width, |
1387 | 0 | height, |
1388 | 0 | buf, |
1389 | 0 | row_pitch, |
1390 | 0 | self, |
1391 | 0 | self.total_bytes() as usize, |
1392 | 0 | |_, _| Ok(()), |
1393 | 0 | |s, buf| s.read_image_data(buf), |
1394 | 0 | )?; |
1395 | 0 | self.reader.seek(SeekFrom::Start(start))?; |
1396 | 0 | Ok(()) |
1397 | 0 | } |
1398 | | } |
1399 | | |
1400 | | #[cfg(test)] |
1401 | | mod 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 | | // skip the BITMAPFILEHEADER |
1474 | | 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 | | } |