/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.18M | fn next(&mut self) -> Option<&'a mut [u8]> { |
112 | 4.18M | match self.chunks { |
113 | 0 | Chunker::FromTop(ref mut chunks) => chunks.next(), |
114 | 4.18M | Chunker::FromBottom(ref mut chunks) => chunks.next(), |
115 | | } |
116 | 4.18M | } |
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 | 883 | fn from(e: DecoderError) -> ImageError { |
208 | 883 | ImageError::Decoding(DecodingError::new(ImageFormat::Bmp.into(), e)) |
209 | 883 | } |
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.04k | fn check_for_overflow(width: i32, length: i32, channels: usize) -> ImageResult<()> { |
241 | 4.04k | num_bytes(width, length, channels) |
242 | 4.04k | .map(|_| ()) |
243 | 4.04k | .ok_or_else(|| { |
244 | 11 | ImageError::Unsupported(UnsupportedError::from_format_and_kind( |
245 | 11 | ImageFormat::Bmp.into(), |
246 | 11 | UnsupportedErrorKind::GenericFeature(format!( |
247 | 11 | "Image dimensions ({width}x{length} w/{channels} channels) are too large" |
248 | 11 | )), |
249 | 11 | )) |
250 | 11 | }) |
251 | 4.04k | } |
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.04k | fn num_bytes(width: i32, length: i32, channels: usize) -> Option<usize> { |
256 | 4.04k | if width <= 0 || length <= 0 { |
257 | 11 | None |
258 | | } else { |
259 | 4.03k | match channels.checked_mul(width as usize) { |
260 | 4.03k | Some(n) => n.checked_mul(length as usize), |
261 | 0 | None => None, |
262 | | } |
263 | | } |
264 | 4.04k | } |
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.85k | fn with_rows<F>( |
269 | 1.85k | buffer: &mut [u8], |
270 | 1.85k | width: i32, |
271 | 1.85k | height: i32, |
272 | 1.85k | channels: usize, |
273 | 1.85k | top_down: bool, |
274 | 1.85k | mut func: F, |
275 | 1.85k | ) -> io::Result<()> |
276 | 1.85k | where |
277 | 1.85k | 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.85k | let row_width = channels.checked_mul(width as usize).unwrap(); |
282 | 1.85k | let full_image_size = row_width.checked_mul(height as usize).unwrap(); |
283 | 1.85k | assert_eq!(buffer.len(), full_image_size); |
284 | | |
285 | 1.85k | if !top_down { |
286 | 1.15M | for row in buffer.chunks_mut(row_width).rev() { |
287 | 1.15M | func(row)?; |
288 | | } |
289 | | } else { |
290 | 3.13M | for row in buffer.chunks_mut(row_width) { |
291 | 3.13M | func(row)?; |
292 | | } |
293 | | } |
294 | 285 | Ok(()) |
295 | 1.85k | } Unexecuted instantiation: image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_16_bit_pixel_data::{closure#0}>Unexecuted instantiation: image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_32_bit_pixel_data::{closure#0}>Unexecuted instantiation: image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_full_byte_pixel_data::{closure#0}>Unexecuted instantiation: image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data::{closure#1}>Unexecuted instantiation: image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_16_bit_pixel_data::{closure#0}>Unexecuted instantiation: image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_32_bit_pixel_data::{closure#0}>Unexecuted instantiation: image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_full_byte_pixel_data::{closure#0}>Unexecuted instantiation: image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data::{closure#1}>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 | 126 | fn with_rows<F>( | 269 | 126 | buffer: &mut [u8], | 270 | 126 | width: i32, | 271 | 126 | height: i32, | 272 | 126 | channels: usize, | 273 | 126 | top_down: bool, | 274 | 126 | mut func: F, | 275 | 126 | ) -> io::Result<()> | 276 | 126 | where | 277 | 126 | 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 | 126 | let row_width = channels.checked_mul(width as usize).unwrap(); | 282 | 126 | let full_image_size = row_width.checked_mul(height as usize).unwrap(); | 283 | 126 | assert_eq!(buffer.len(), full_image_size); | 284 | | | 285 | 126 | if !top_down { | 286 | 18.5k | for row in buffer.chunks_mut(row_width).rev() { | 287 | 18.5k | func(row)?; | 288 | | } | 289 | | } else { | 290 | 907k | for row in buffer.chunks_mut(row_width) { | 291 | 907k | func(row)?; | 292 | | } | 293 | | } | 294 | 26 | Ok(()) | 295 | 126 | } |
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 | 129 | fn with_rows<F>( | 269 | 129 | buffer: &mut [u8], | 270 | 129 | width: i32, | 271 | 129 | height: i32, | 272 | 129 | channels: usize, | 273 | 129 | top_down: bool, | 274 | 129 | mut func: F, | 275 | 129 | ) -> io::Result<()> | 276 | 129 | where | 277 | 129 | 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 | 129 | let row_width = channels.checked_mul(width as usize).unwrap(); | 282 | 129 | let full_image_size = row_width.checked_mul(height as usize).unwrap(); | 283 | 129 | assert_eq!(buffer.len(), full_image_size); | 284 | | | 285 | 129 | if !top_down { | 286 | 22.3k | for row in buffer.chunks_mut(row_width).rev() { | 287 | 22.3k | func(row)?; | 288 | | } | 289 | | } else { | 290 | 264k | for row in buffer.chunks_mut(row_width) { | 291 | 264k | func(row)?; | 292 | | } | 293 | | } | 294 | 5 | Ok(()) | 295 | 129 | } |
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 | 197 | fn with_rows<F>( | 269 | 197 | buffer: &mut [u8], | 270 | 197 | width: i32, | 271 | 197 | height: i32, | 272 | 197 | channels: usize, | 273 | 197 | top_down: bool, | 274 | 197 | mut func: F, | 275 | 197 | ) -> io::Result<()> | 276 | 197 | where | 277 | 197 | 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 | 197 | let row_width = channels.checked_mul(width as usize).unwrap(); | 282 | 197 | let full_image_size = row_width.checked_mul(height as usize).unwrap(); | 283 | 197 | assert_eq!(buffer.len(), full_image_size); | 284 | | | 285 | 197 | if !top_down { | 286 | 97.2k | for row in buffer.chunks_mut(row_width).rev() { | 287 | 97.2k | func(row)?; | 288 | | } | 289 | | } else { | 290 | 1.89M | for row in buffer.chunks_mut(row_width) { | 291 | 1.89M | func(row)?; | 292 | | } | 293 | | } | 294 | 15 | Ok(()) | 295 | 197 | } |
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 | 381 | fn with_rows<F>( | 269 | 381 | buffer: &mut [u8], | 270 | 381 | width: i32, | 271 | 381 | height: i32, | 272 | 381 | channels: usize, | 273 | 381 | top_down: bool, | 274 | 381 | mut func: F, | 275 | 381 | ) -> io::Result<()> | 276 | 381 | where | 277 | 381 | 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 | 381 | let row_width = channels.checked_mul(width as usize).unwrap(); | 282 | 381 | let full_image_size = row_width.checked_mul(height as usize).unwrap(); | 283 | 381 | assert_eq!(buffer.len(), full_image_size); | 284 | | | 285 | 381 | if !top_down { | 286 | 330k | for row in buffer.chunks_mut(row_width).rev() { | 287 | 330k | func(row)?; | 288 | | } | 289 | | } else { | 290 | 1.91k | for row in buffer.chunks_mut(row_width) { | 291 | 1.91k | func(row)?; | 292 | | } | 293 | | } | 294 | 55 | Ok(()) | 295 | 381 | } |
Unexecuted instantiation: image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_16_bit_pixel_data::{closure#0}>Unexecuted instantiation: image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_32_bit_pixel_data::{closure#0}>Unexecuted instantiation: image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_full_byte_pixel_data::{closure#0}>Unexecuted instantiation: image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data::{closure#1}>Unexecuted instantiation: image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_16_bit_pixel_data::{closure#0}>Unexecuted instantiation: image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_32_bit_pixel_data::{closure#0}>Unexecuted instantiation: image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_full_byte_pixel_data::{closure#0}>Unexecuted instantiation: image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data::{closure#1}>Unexecuted instantiation: image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_16_bit_pixel_data::{closure#0}>Unexecuted instantiation: image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_32_bit_pixel_data::{closure#0}>Unexecuted instantiation: image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_full_byte_pixel_data::{closure#0}>Unexecuted instantiation: image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data::{closure#1}>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 | 172 | fn with_rows<F>( | 269 | 172 | buffer: &mut [u8], | 270 | 172 | width: i32, | 271 | 172 | height: i32, | 272 | 172 | channels: usize, | 273 | 172 | top_down: bool, | 274 | 172 | mut func: F, | 275 | 172 | ) -> io::Result<()> | 276 | 172 | where | 277 | 172 | 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 | 172 | let row_width = channels.checked_mul(width as usize).unwrap(); | 282 | 172 | let full_image_size = row_width.checked_mul(height as usize).unwrap(); | 283 | 172 | assert_eq!(buffer.len(), full_image_size); | 284 | | | 285 | 172 | if !top_down { | 286 | 184k | for row in buffer.chunks_mut(row_width).rev() { | 287 | 184k | func(row)?; | 288 | | } | 289 | | } else { | 290 | 529 | for row in buffer.chunks_mut(row_width) { | 291 | 529 | func(row)?; | 292 | | } | 293 | | } | 294 | 12 | Ok(()) | 295 | 172 | } |
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 | 148 | fn with_rows<F>( | 269 | 148 | buffer: &mut [u8], | 270 | 148 | width: i32, | 271 | 148 | height: i32, | 272 | 148 | channels: usize, | 273 | 148 | top_down: bool, | 274 | 148 | mut func: F, | 275 | 148 | ) -> io::Result<()> | 276 | 148 | where | 277 | 148 | 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 | 148 | let row_width = channels.checked_mul(width as usize).unwrap(); | 282 | 148 | let full_image_size = row_width.checked_mul(height as usize).unwrap(); | 283 | 148 | assert_eq!(buffer.len(), full_image_size); | 284 | | | 285 | 148 | if !top_down { | 286 | 12.6k | for row in buffer.chunks_mut(row_width).rev() { | 287 | 12.6k | func(row)?; | 288 | | } | 289 | | } else { | 290 | 426 | for row in buffer.chunks_mut(row_width) { | 291 | 426 | func(row)?; | 292 | | } | 293 | | } | 294 | 16 | Ok(()) | 295 | 148 | } |
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 | 192 | fn with_rows<F>( | 269 | 192 | buffer: &mut [u8], | 270 | 192 | width: i32, | 271 | 192 | height: i32, | 272 | 192 | channels: usize, | 273 | 192 | top_down: bool, | 274 | 192 | mut func: F, | 275 | 192 | ) -> io::Result<()> | 276 | 192 | where | 277 | 192 | 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 | 192 | let row_width = channels.checked_mul(width as usize).unwrap(); | 282 | 192 | let full_image_size = row_width.checked_mul(height as usize).unwrap(); | 283 | 192 | assert_eq!(buffer.len(), full_image_size); | 284 | | | 285 | 192 | if !top_down { | 286 | 272k | for row in buffer.chunks_mut(row_width).rev() { | 287 | 272k | func(row)?; | 288 | | } | 289 | | } else { | 290 | 65.7k | for row in buffer.chunks_mut(row_width) { | 291 | 65.7k | func(row)?; | 292 | | } | 293 | | } | 294 | 42 | Ok(()) | 295 | 192 | } |
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 | 424 | fn with_rows<F>( | 269 | 424 | buffer: &mut [u8], | 270 | 424 | width: i32, | 271 | 424 | height: i32, | 272 | 424 | channels: usize, | 273 | 424 | top_down: bool, | 274 | 424 | mut func: F, | 275 | 424 | ) -> io::Result<()> | 276 | 424 | where | 277 | 424 | 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 | 424 | let row_width = channels.checked_mul(width as usize).unwrap(); | 282 | 424 | let full_image_size = row_width.checked_mul(height as usize).unwrap(); | 283 | 424 | assert_eq!(buffer.len(), full_image_size); | 284 | | | 285 | 424 | if !top_down { | 286 | 197k | for row in buffer.chunks_mut(row_width).rev() { | 287 | 197k | func(row)?; | 288 | | } | 289 | | } else { | 290 | 418 | for row in buffer.chunks_mut(row_width) { | 291 | 418 | func(row)?; | 292 | | } | 293 | | } | 294 | 107 | Ok(()) | 295 | 424 | } |
Unexecuted instantiation: image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_16_bit_pixel_data::{closure#0}>Unexecuted instantiation: image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_32_bit_pixel_data::{closure#0}>Unexecuted instantiation: image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_full_byte_pixel_data::{closure#0}>Unexecuted instantiation: image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data::{closure#1}>Unexecuted instantiation: image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_16_bit_pixel_data::{closure#0}>Unexecuted instantiation: image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_32_bit_pixel_data::{closure#0}>Unexecuted instantiation: image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_full_byte_pixel_data::{closure#0}>Unexecuted instantiation: image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data::{closure#1}>Unexecuted instantiation: image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_16_bit_pixel_data::{closure#0}>Unexecuted instantiation: image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_32_bit_pixel_data::{closure#0}>Unexecuted instantiation: image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_full_byte_pixel_data::{closure#0}>Unexecuted instantiation: image::codecs::bmp::decoder::with_rows::<<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data::{closure#1}>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 | 13 | fn with_rows<F>( | 269 | 13 | buffer: &mut [u8], | 270 | 13 | width: i32, | 271 | 13 | height: i32, | 272 | 13 | channels: usize, | 273 | 13 | top_down: bool, | 274 | 13 | mut func: F, | 275 | 13 | ) -> io::Result<()> | 276 | 13 | where | 277 | 13 | 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 | 13 | let row_width = channels.checked_mul(width as usize).unwrap(); | 282 | 13 | let full_image_size = row_width.checked_mul(height as usize).unwrap(); | 283 | 13 | assert_eq!(buffer.len(), full_image_size); | 284 | | | 285 | 13 | if !top_down { | 286 | 946 | for row in buffer.chunks_mut(row_width).rev() { | 287 | 946 | func(row)?; | 288 | | } | 289 | | } else { | 290 | 132 | for row in buffer.chunks_mut(row_width) { | 291 | 132 | func(row)?; | 292 | | } | 293 | | } | 294 | 2 | Ok(()) | 295 | 13 | } |
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 | 11 | fn with_rows<F>( | 269 | 11 | buffer: &mut [u8], | 270 | 11 | width: i32, | 271 | 11 | height: i32, | 272 | 11 | channels: usize, | 273 | 11 | top_down: bool, | 274 | 11 | mut func: F, | 275 | 11 | ) -> io::Result<()> | 276 | 11 | where | 277 | 11 | 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 | 11 | let row_width = channels.checked_mul(width as usize).unwrap(); | 282 | 11 | let full_image_size = row_width.checked_mul(height as usize).unwrap(); | 283 | 11 | assert_eq!(buffer.len(), full_image_size); | 284 | | | 285 | 11 | if !top_down { | 286 | 16.6k | for row in buffer.chunks_mut(row_width).rev() { | 287 | 16.6k | func(row)?; | 288 | | } | 289 | | } else { | 290 | 129 | for row in buffer.chunks_mut(row_width) { | 291 | 129 | func(row)?; | 292 | | } | 293 | | } | 294 | 1 | Ok(()) | 295 | 11 | } |
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 | 15 | fn with_rows<F>( | 269 | 15 | buffer: &mut [u8], | 270 | 15 | width: i32, | 271 | 15 | height: i32, | 272 | 15 | channels: usize, | 273 | 15 | top_down: bool, | 274 | 15 | mut func: F, | 275 | 15 | ) -> io::Result<()> | 276 | 15 | where | 277 | 15 | 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 | 15 | let row_width = channels.checked_mul(width as usize).unwrap(); | 282 | 15 | let full_image_size = row_width.checked_mul(height as usize).unwrap(); | 283 | 15 | assert_eq!(buffer.len(), full_image_size); | 284 | | | 285 | 15 | if !top_down { | 286 | 1.41k | for row in buffer.chunks_mut(row_width).rev() { | 287 | 1.41k | func(row)?; | 288 | | } | 289 | | } else { | 290 | 203 | for row in buffer.chunks_mut(row_width) { | 291 | 203 | func(row)?; | 292 | | } | 293 | | } | 294 | 2 | Ok(()) | 295 | 15 | } |
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 | 48 | fn with_rows<F>( | 269 | 48 | buffer: &mut [u8], | 270 | 48 | width: i32, | 271 | 48 | height: i32, | 272 | 48 | channels: usize, | 273 | 48 | top_down: bool, | 274 | 48 | mut func: F, | 275 | 48 | ) -> io::Result<()> | 276 | 48 | where | 277 | 48 | 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 | 48 | let row_width = channels.checked_mul(width as usize).unwrap(); | 282 | 48 | let full_image_size = row_width.checked_mul(height as usize).unwrap(); | 283 | 48 | assert_eq!(buffer.len(), full_image_size); | 284 | | | 285 | 48 | if !top_down { | 286 | 3.63k | for row in buffer.chunks_mut(row_width).rev() { | 287 | 3.63k | func(row)?; | 288 | | } | 289 | | } else { | 290 | 204 | for row in buffer.chunks_mut(row_width) { | 291 | 204 | func(row)?; | 292 | | } | 293 | | } | 294 | 2 | Ok(()) | 295 | 48 | } |
|
296 | | |
297 | 2.67k | fn set_8bit_pixel_run<'a, T: Iterator<Item = &'a u8>>( |
298 | 2.67k | pixel_iter: &mut ChunksExactMut<u8>, |
299 | 2.67k | palette: &[[u8; 3]], |
300 | 2.67k | indices: T, |
301 | 2.67k | n_pixels: usize, |
302 | 2.67k | ) -> bool { |
303 | 387k | for idx in indices.take(n_pixels) { |
304 | 387k | if let Some(pixel) = pixel_iter.next() { |
305 | 387k | let rgb = palette[*idx as usize]; |
306 | 387k | pixel[0] = rgb[0]; |
307 | 387k | pixel[1] = rgb[1]; |
308 | 387k | pixel[2] = rgb[2]; |
309 | 387k | } else { |
310 | 30 | return false; |
311 | | } |
312 | | } |
313 | 2.64k | true |
314 | 2.67k | } Unexecuted instantiation: image::codecs::bmp::decoder::set_8bit_pixel_run::<core::slice::iter::Iter<u8>> Unexecuted instantiation: image::codecs::bmp::decoder::set_8bit_pixel_run::<core::slice::iter::Iter<u8>> image::codecs::bmp::decoder::set_8bit_pixel_run::<core::slice::iter::Iter<u8>> Line | Count | Source | 297 | 1.12k | fn set_8bit_pixel_run<'a, T: Iterator<Item = &'a u8>>( | 298 | 1.12k | pixel_iter: &mut ChunksExactMut<u8>, | 299 | 1.12k | palette: &[[u8; 3]], | 300 | 1.12k | indices: T, | 301 | 1.12k | n_pixels: usize, | 302 | 1.12k | ) -> bool { | 303 | 298k | for idx in indices.take(n_pixels) { | 304 | 298k | if let Some(pixel) = pixel_iter.next() { | 305 | 298k | let rgb = palette[*idx as usize]; | 306 | 298k | pixel[0] = rgb[0]; | 307 | 298k | pixel[1] = rgb[1]; | 308 | 298k | pixel[2] = rgb[2]; | 309 | 298k | } else { | 310 | 12 | return false; | 311 | | } | 312 | | } | 313 | 1.11k | true | 314 | 1.12k | } |
Unexecuted instantiation: image::codecs::bmp::decoder::set_8bit_pixel_run::<core::slice::iter::Iter<u8>> Unexecuted instantiation: image::codecs::bmp::decoder::set_8bit_pixel_run::<core::slice::iter::Iter<u8>> Unexecuted instantiation: image::codecs::bmp::decoder::set_8bit_pixel_run::<core::slice::iter::Iter<u8>> image::codecs::bmp::decoder::set_8bit_pixel_run::<core::slice::iter::Iter<u8>> Line | Count | Source | 297 | 1.21k | fn set_8bit_pixel_run<'a, T: Iterator<Item = &'a u8>>( | 298 | 1.21k | pixel_iter: &mut ChunksExactMut<u8>, | 299 | 1.21k | palette: &[[u8; 3]], | 300 | 1.21k | indices: T, | 301 | 1.21k | n_pixels: usize, | 302 | 1.21k | ) -> bool { | 303 | 83.9k | for idx in indices.take(n_pixels) { | 304 | 83.9k | if let Some(pixel) = pixel_iter.next() { | 305 | 83.9k | let rgb = palette[*idx as usize]; | 306 | 83.9k | pixel[0] = rgb[0]; | 307 | 83.9k | pixel[1] = rgb[1]; | 308 | 83.9k | pixel[2] = rgb[2]; | 309 | 83.9k | } else { | 310 | 17 | return false; | 311 | | } | 312 | | } | 313 | 1.19k | true | 314 | 1.21k | } |
Unexecuted instantiation: image::codecs::bmp::decoder::set_8bit_pixel_run::<core::slice::iter::Iter<u8>> Unexecuted instantiation: image::codecs::bmp::decoder::set_8bit_pixel_run::<core::slice::iter::Iter<u8>> Unexecuted instantiation: image::codecs::bmp::decoder::set_8bit_pixel_run::<core::slice::iter::Iter<u8>> image::codecs::bmp::decoder::set_8bit_pixel_run::<core::slice::iter::Iter<u8>> Line | Count | Source | 297 | 333 | fn set_8bit_pixel_run<'a, T: Iterator<Item = &'a u8>>( | 298 | 333 | pixel_iter: &mut ChunksExactMut<u8>, | 299 | 333 | palette: &[[u8; 3]], | 300 | 333 | indices: T, | 301 | 333 | n_pixels: usize, | 302 | 333 | ) -> bool { | 303 | 4.68k | for idx in indices.take(n_pixels) { | 304 | 4.68k | if let Some(pixel) = pixel_iter.next() { | 305 | 4.68k | let rgb = palette[*idx as usize]; | 306 | 4.68k | pixel[0] = rgb[0]; | 307 | 4.68k | pixel[1] = rgb[1]; | 308 | 4.68k | pixel[2] = rgb[2]; | 309 | 4.68k | } else { | 310 | 1 | return false; | 311 | | } | 312 | | } | 313 | 332 | true | 314 | 333 | } |
|
315 | | |
316 | 963k | fn set_4bit_pixel_run<'a, T: Iterator<Item = &'a u8>>( |
317 | 963k | pixel_iter: &mut ChunksExactMut<u8>, |
318 | 963k | palette: &[[u8; 3]], |
319 | 963k | indices: T, |
320 | 963k | mut n_pixels: usize, |
321 | 963k | ) -> bool { |
322 | 6.64M | 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 | 6.46M | set_pixel!(idx >> 4); |
340 | 5.75M | set_pixel!(idx & 0xf); |
341 | | } |
342 | 963k | true |
343 | 963k | } Unexecuted instantiation: image::codecs::bmp::decoder::set_4bit_pixel_run::<core::slice::iter::Iter<u8>> Unexecuted instantiation: image::codecs::bmp::decoder::set_4bit_pixel_run::<core::iter::sources::repeat::Repeat<&u8>> Unexecuted instantiation: image::codecs::bmp::decoder::set_4bit_pixel_run::<core::slice::iter::Iter<u8>> Unexecuted instantiation: image::codecs::bmp::decoder::set_4bit_pixel_run::<core::iter::sources::repeat::Repeat<&u8>> image::codecs::bmp::decoder::set_4bit_pixel_run::<core::slice::iter::Iter<u8>> Line | Count | Source | 316 | 183k | fn set_4bit_pixel_run<'a, T: Iterator<Item = &'a u8>>( | 317 | 183k | pixel_iter: &mut ChunksExactMut<u8>, | 318 | 183k | palette: &[[u8; 3]], | 319 | 183k | indices: T, | 320 | 183k | mut n_pixels: usize, | 321 | 183k | ) -> bool { | 322 | 1.00M | 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 | 830k | set_pixel!(idx >> 4); | 340 | 826k | set_pixel!(idx & 0xf); | 341 | | } | 342 | 183k | true | 343 | 183k | } |
image::codecs::bmp::decoder::set_4bit_pixel_run::<core::iter::sources::repeat::Repeat<&u8>> Line | Count | Source | 316 | 678k | fn set_4bit_pixel_run<'a, T: Iterator<Item = &'a u8>>( | 317 | 678k | pixel_iter: &mut ChunksExactMut<u8>, | 318 | 678k | palette: &[[u8; 3]], | 319 | 678k | indices: T, | 320 | 678k | mut n_pixels: usize, | 321 | 678k | ) -> bool { | 322 | 3.65M | 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 | 3.65M | set_pixel!(idx >> 4); | 340 | 3.00M | set_pixel!(idx & 0xf); | 341 | | } | 342 | 678k | true | 343 | 678k | } |
Unexecuted instantiation: image::codecs::bmp::decoder::set_4bit_pixel_run::<core::slice::iter::Iter<u8>> Unexecuted instantiation: image::codecs::bmp::decoder::set_4bit_pixel_run::<core::iter::sources::repeat::Repeat<&u8>> Unexecuted instantiation: image::codecs::bmp::decoder::set_4bit_pixel_run::<core::slice::iter::Iter<u8>> Unexecuted instantiation: image::codecs::bmp::decoder::set_4bit_pixel_run::<core::iter::sources::repeat::Repeat<&u8>> Unexecuted instantiation: image::codecs::bmp::decoder::set_4bit_pixel_run::<core::slice::iter::Iter<u8>> Unexecuted instantiation: image::codecs::bmp::decoder::set_4bit_pixel_run::<core::iter::sources::repeat::Repeat<&u8>> image::codecs::bmp::decoder::set_4bit_pixel_run::<core::slice::iter::Iter<u8>> Line | Count | Source | 316 | 42.4k | fn set_4bit_pixel_run<'a, T: Iterator<Item = &'a u8>>( | 317 | 42.4k | pixel_iter: &mut ChunksExactMut<u8>, | 318 | 42.4k | palette: &[[u8; 3]], | 319 | 42.4k | indices: T, | 320 | 42.4k | mut n_pixels: usize, | 321 | 42.4k | ) -> bool { | 322 | 616k | 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 | 610k | set_pixel!(idx >> 4); | 340 | 581k | set_pixel!(idx & 0xf); | 341 | | } | 342 | 42.4k | true | 343 | 42.4k | } |
image::codecs::bmp::decoder::set_4bit_pixel_run::<core::iter::sources::repeat::Repeat<&u8>> Line | Count | Source | 316 | 49.1k | fn set_4bit_pixel_run<'a, T: Iterator<Item = &'a u8>>( | 317 | 49.1k | pixel_iter: &mut ChunksExactMut<u8>, | 318 | 49.1k | palette: &[[u8; 3]], | 319 | 49.1k | indices: T, | 320 | 49.1k | mut n_pixels: usize, | 321 | 49.1k | ) -> bool { | 322 | 1.10M | 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 | 1.10M | set_pixel!(idx >> 4); | 340 | 1.07M | set_pixel!(idx & 0xf); | 341 | | } | 342 | 49.1k | true | 343 | 49.1k | } |
Unexecuted instantiation: image::codecs::bmp::decoder::set_4bit_pixel_run::<core::slice::iter::Iter<u8>> Unexecuted instantiation: image::codecs::bmp::decoder::set_4bit_pixel_run::<core::iter::sources::repeat::Repeat<&u8>> Unexecuted instantiation: image::codecs::bmp::decoder::set_4bit_pixel_run::<core::slice::iter::Iter<u8>> Unexecuted instantiation: image::codecs::bmp::decoder::set_4bit_pixel_run::<core::iter::sources::repeat::Repeat<&u8>> Unexecuted instantiation: image::codecs::bmp::decoder::set_4bit_pixel_run::<core::slice::iter::Iter<u8>> Unexecuted instantiation: image::codecs::bmp::decoder::set_4bit_pixel_run::<core::iter::sources::repeat::Repeat<&u8>> image::codecs::bmp::decoder::set_4bit_pixel_run::<core::slice::iter::Iter<u8>> Line | Count | Source | 316 | 2.23k | fn set_4bit_pixel_run<'a, T: Iterator<Item = &'a u8>>( | 317 | 2.23k | pixel_iter: &mut ChunksExactMut<u8>, | 318 | 2.23k | palette: &[[u8; 3]], | 319 | 2.23k | indices: T, | 320 | 2.23k | mut n_pixels: usize, | 321 | 2.23k | ) -> bool { | 322 | 17.2k | 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 | 15.6k | set_pixel!(idx >> 4); | 340 | 15.4k | set_pixel!(idx & 0xf); | 341 | | } | 342 | 2.22k | true | 343 | 2.23k | } |
image::codecs::bmp::decoder::set_4bit_pixel_run::<core::iter::sources::repeat::Repeat<&u8>> Line | Count | Source | 316 | 7.67k | fn set_4bit_pixel_run<'a, T: Iterator<Item = &'a u8>>( | 317 | 7.67k | pixel_iter: &mut ChunksExactMut<u8>, | 318 | 7.67k | palette: &[[u8; 3]], | 319 | 7.67k | indices: T, | 320 | 7.67k | mut n_pixels: usize, | 321 | 7.67k | ) -> bool { | 322 | 257k | 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 | 257k | set_pixel!(idx >> 4); | 340 | 252k | set_pixel!(idx & 0xf); | 341 | | } | 342 | 7.67k | true | 343 | 7.67k | } |
|
344 | | |
345 | | #[rustfmt::skip] |
346 | 3.95k | fn set_2bit_pixel_run<'a, T: Iterator<Item = &'a u8>>( |
347 | 3.95k | pixel_iter: &mut ChunksExactMut<u8>, |
348 | 3.95k | palette: &[[u8; 3]], |
349 | 3.95k | indices: T, |
350 | 3.95k | mut n_pixels: usize, |
351 | 3.95k | ) -> bool { |
352 | 369k | 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 | 368k | set_pixel!((idx >> 6) & 0x3u8); |
370 | 367k | set_pixel!((idx >> 4) & 0x3u8); |
371 | 366k | set_pixel!((idx >> 2) & 0x3u8); |
372 | 366k | set_pixel!( idx & 0x3u8); |
373 | | } |
374 | 3.95k | true |
375 | 3.95k | } Unexecuted instantiation: image::codecs::bmp::decoder::set_2bit_pixel_run::<core::slice::iter::Iter<u8>> Unexecuted instantiation: image::codecs::bmp::decoder::set_2bit_pixel_run::<core::slice::iter::Iter<u8>> image::codecs::bmp::decoder::set_2bit_pixel_run::<core::slice::iter::Iter<u8>> Line | Count | Source | 346 | 1.55k | fn set_2bit_pixel_run<'a, T: Iterator<Item = &'a u8>>( | 347 | 1.55k | pixel_iter: &mut ChunksExactMut<u8>, | 348 | 1.55k | palette: &[[u8; 3]], | 349 | 1.55k | indices: T, | 350 | 1.55k | mut n_pixels: usize, | 351 | 1.55k | ) -> bool { | 352 | 220k | 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 | 220k | set_pixel!((idx >> 6) & 0x3u8); | 370 | 220k | set_pixel!((idx >> 4) & 0x3u8); | 371 | 220k | set_pixel!((idx >> 2) & 0x3u8); | 372 | 219k | set_pixel!( idx & 0x3u8); | 373 | | } | 374 | 1.55k | true | 375 | 1.55k | } |
Unexecuted instantiation: image::codecs::bmp::decoder::set_2bit_pixel_run::<core::slice::iter::Iter<u8>> Unexecuted instantiation: image::codecs::bmp::decoder::set_2bit_pixel_run::<core::slice::iter::Iter<u8>> Unexecuted instantiation: image::codecs::bmp::decoder::set_2bit_pixel_run::<core::slice::iter::Iter<u8>> image::codecs::bmp::decoder::set_2bit_pixel_run::<core::slice::iter::Iter<u8>> Line | Count | Source | 346 | 1.06k | fn set_2bit_pixel_run<'a, T: Iterator<Item = &'a u8>>( | 347 | 1.06k | pixel_iter: &mut ChunksExactMut<u8>, | 348 | 1.06k | palette: &[[u8; 3]], | 349 | 1.06k | indices: T, | 350 | 1.06k | mut n_pixels: usize, | 351 | 1.06k | ) -> bool { | 352 | 82.5k | 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 | 82.2k | set_pixel!((idx >> 6) & 0x3u8); | 370 | 82.0k | set_pixel!((idx >> 4) & 0x3u8); | 371 | 81.8k | set_pixel!((idx >> 2) & 0x3u8); | 372 | 81.6k | set_pixel!( idx & 0x3u8); | 373 | | } | 374 | 1.06k | true | 375 | 1.06k | } |
Unexecuted instantiation: image::codecs::bmp::decoder::set_2bit_pixel_run::<core::slice::iter::Iter<u8>> Unexecuted instantiation: image::codecs::bmp::decoder::set_2bit_pixel_run::<core::slice::iter::Iter<u8>> Unexecuted instantiation: image::codecs::bmp::decoder::set_2bit_pixel_run::<core::slice::iter::Iter<u8>> image::codecs::bmp::decoder::set_2bit_pixel_run::<core::slice::iter::Iter<u8>> Line | Count | Source | 346 | 1.34k | fn set_2bit_pixel_run<'a, T: Iterator<Item = &'a u8>>( | 347 | 1.34k | pixel_iter: &mut ChunksExactMut<u8>, | 348 | 1.34k | palette: &[[u8; 3]], | 349 | 1.34k | indices: T, | 350 | 1.34k | mut n_pixels: usize, | 351 | 1.34k | ) -> bool { | 352 | 66.0k | 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 | 65.8k | set_pixel!((idx >> 6) & 0x3u8); | 370 | 65.1k | set_pixel!((idx >> 4) & 0x3u8); | 371 | 64.9k | set_pixel!((idx >> 2) & 0x3u8); | 372 | 64.8k | set_pixel!( idx & 0x3u8); | 373 | | } | 374 | 1.34k | true | 375 | 1.34k | } |
|
376 | | |
377 | 497k | fn set_1bit_pixel_run<'a, T: Iterator<Item = &'a u8>>( |
378 | 497k | pixel_iter: &mut ChunksExactMut<u8>, |
379 | 497k | palette: &[[u8; 3]], |
380 | 497k | indices: T, |
381 | 497k | ) { |
382 | 1.53M | for idx in indices { |
383 | 1.52M | let mut bit = 0x80; |
384 | | loop { |
385 | 10.9M | if let Some(pixel) = pixel_iter.next() { |
386 | 10.4M | let rgb = palette[usize::from((idx & bit) != 0)]; |
387 | 10.4M | pixel[0] = rgb[0]; |
388 | 10.4M | pixel[1] = rgb[1]; |
389 | 10.4M | pixel[2] = rgb[2]; |
390 | 10.4M | } else { |
391 | 484k | return; |
392 | | } |
393 | | |
394 | 10.4M | bit >>= 1; |
395 | 10.4M | if bit == 0 { |
396 | 1.04M | break; |
397 | 9.40M | } |
398 | | } |
399 | | } |
400 | 497k | } Unexecuted instantiation: image::codecs::bmp::decoder::set_1bit_pixel_run::<core::slice::iter::Iter<u8>> Unexecuted instantiation: image::codecs::bmp::decoder::set_1bit_pixel_run::<core::slice::iter::Iter<u8>> image::codecs::bmp::decoder::set_1bit_pixel_run::<core::slice::iter::Iter<u8>> Line | Count | Source | 377 | 329k | fn set_1bit_pixel_run<'a, T: Iterator<Item = &'a u8>>( | 378 | 329k | pixel_iter: &mut ChunksExactMut<u8>, | 379 | 329k | palette: &[[u8; 3]], | 380 | 329k | indices: T, | 381 | 329k | ) { | 382 | 1.30M | for idx in indices { | 383 | 1.29M | let mut bit = 0x80; | 384 | | loop { | 385 | 9.76M | if let Some(pixel) = pixel_iter.next() { | 386 | 9.44M | let rgb = palette[usize::from((idx & bit) != 0)]; | 387 | 9.44M | pixel[0] = rgb[0]; | 388 | 9.44M | pixel[1] = rgb[1]; | 389 | 9.44M | pixel[2] = rgb[2]; | 390 | 9.44M | } else { | 391 | 317k | return; | 392 | | } | 393 | | | 394 | 9.44M | bit >>= 1; | 395 | 9.44M | if bit == 0 { | 396 | 979k | break; | 397 | 8.46M | } | 398 | | } | 399 | | } | 400 | 329k | } |
Unexecuted instantiation: image::codecs::bmp::decoder::set_1bit_pixel_run::<core::slice::iter::Iter<u8>> Unexecuted instantiation: image::codecs::bmp::decoder::set_1bit_pixel_run::<core::slice::iter::Iter<u8>> Unexecuted instantiation: image::codecs::bmp::decoder::set_1bit_pixel_run::<core::slice::iter::Iter<u8>> image::codecs::bmp::decoder::set_1bit_pixel_run::<core::slice::iter::Iter<u8>> Line | Count | Source | 377 | 166k | fn set_1bit_pixel_run<'a, T: Iterator<Item = &'a u8>>( | 378 | 166k | pixel_iter: &mut ChunksExactMut<u8>, | 379 | 166k | palette: &[[u8; 3]], | 380 | 166k | indices: T, | 381 | 166k | ) { | 382 | 209k | for idx in indices { | 383 | 208k | let mut bit = 0x80; | 384 | | loop { | 385 | 1.00M | if let Some(pixel) = pixel_iter.next() { | 386 | 839k | let rgb = palette[usize::from((idx & bit) != 0)]; | 387 | 839k | pixel[0] = rgb[0]; | 388 | 839k | pixel[1] = rgb[1]; | 389 | 839k | pixel[2] = rgb[2]; | 390 | 839k | } else { | 391 | 166k | return; | 392 | | } | 393 | | | 394 | 839k | bit >>= 1; | 395 | 839k | if bit == 0 { | 396 | 42.4k | break; | 397 | 797k | } | 398 | | } | 399 | | } | 400 | 166k | } |
Unexecuted instantiation: image::codecs::bmp::decoder::set_1bit_pixel_run::<core::slice::iter::Iter<u8>> Unexecuted instantiation: image::codecs::bmp::decoder::set_1bit_pixel_run::<core::slice::iter::Iter<u8>> Unexecuted instantiation: image::codecs::bmp::decoder::set_1bit_pixel_run::<core::slice::iter::Iter<u8>> image::codecs::bmp::decoder::set_1bit_pixel_run::<core::slice::iter::Iter<u8>> Line | Count | Source | 377 | 1.79k | fn set_1bit_pixel_run<'a, T: Iterator<Item = &'a u8>>( | 378 | 1.79k | pixel_iter: &mut ChunksExactMut<u8>, | 379 | 1.79k | palette: &[[u8; 3]], | 380 | 1.79k | indices: T, | 381 | 1.79k | ) { | 382 | 21.0k | for idx in indices { | 383 | 20.9k | let mut bit = 0x80; | 384 | | loop { | 385 | 162k | if let Some(pixel) = pixel_iter.next() { | 386 | 161k | let rgb = palette[usize::from((idx & bit) != 0)]; | 387 | 161k | pixel[0] = rgb[0]; | 388 | 161k | pixel[1] = rgb[1]; | 389 | 161k | pixel[2] = rgb[2]; | 390 | 161k | } else { | 391 | 1.66k | return; | 392 | | } | 393 | | | 394 | 161k | bit >>= 1; | 395 | 161k | if bit == 0 { | 396 | 19.2k | break; | 397 | 141k | } | 398 | | } | 399 | | } | 400 | 1.79k | } |
|
401 | | |
402 | | #[derive(PartialEq, Eq)] |
403 | | struct Bitfield { |
404 | | shift: u32, |
405 | | len: u32, |
406 | | } |
407 | | |
408 | | impl Bitfield { |
409 | 2.38k | fn from_mask(mask: u32, max_len: u32) -> ImageResult<Bitfield> { |
410 | 2.38k | if mask == 0 { |
411 | 363 | return Ok(Bitfield { shift: 0, len: 0 }); |
412 | 2.02k | } |
413 | 2.02k | let mut shift = mask.trailing_zeros(); |
414 | 2.02k | let mut len = (!(mask >> shift)).trailing_zeros(); |
415 | 2.02k | if len != mask.count_ones() { |
416 | 64 | return Err(DecoderError::BitfieldMaskNonContiguous.into()); |
417 | 1.95k | } |
418 | 1.95k | if len + shift > max_len { |
419 | 12 | return Err(DecoderError::BitfieldMaskInvalid.into()); |
420 | 1.94k | } |
421 | 1.94k | if len > 8 { |
422 | 692 | shift += len - 8; |
423 | 692 | len = 8; |
424 | 1.25k | } |
425 | 1.94k | Ok(Bitfield { shift, len }) |
426 | 2.38k | } |
427 | | |
428 | 7.95M | fn read(&self, data: u32) -> u8 { |
429 | 7.95M | let data = data >> self.shift; |
430 | 7.95M | match self.len { |
431 | 115k | 1 => ((data & 0b1) * 0xff) as u8, |
432 | 54.1k | 2 => ((data & 0b11) * 0x55) as u8, |
433 | 520k | 3 => LOOKUP_TABLE_3_BIT_TO_8_BIT[(data & 0b00_0111) as usize], |
434 | 44.6k | 4 => LOOKUP_TABLE_4_BIT_TO_8_BIT[(data & 0b00_1111) as usize], |
435 | 3.50M | 5 => LOOKUP_TABLE_5_BIT_TO_8_BIT[(data & 0b01_1111) as usize], |
436 | 767k | 6 => LOOKUP_TABLE_6_BIT_TO_8_BIT[(data & 0b11_1111) as usize], |
437 | 9.80k | 7 => (((data & 0x7f) << 1) | ((data & 0x7f) >> 6)) as u8, |
438 | 2.94M | 8 => (data & 0xff) as u8, |
439 | 0 | _ => panic!(), |
440 | | } |
441 | 7.95M | } |
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 | 640 | fn from_mask( |
454 | 640 | r_mask: u32, |
455 | 640 | g_mask: u32, |
456 | 640 | b_mask: u32, |
457 | 640 | a_mask: u32, |
458 | 640 | max_len: u32, |
459 | 640 | ) -> ImageResult<Bitfields> { |
460 | 564 | let bitfields = Bitfields { |
461 | 640 | r: Bitfield::from_mask(r_mask, max_len)?, |
462 | 595 | g: Bitfield::from_mask(g_mask, max_len)?, |
463 | 581 | b: Bitfield::from_mask(b_mask, max_len)?, |
464 | 569 | a: Bitfield::from_mask(a_mask, max_len)?, |
465 | | }; |
466 | 564 | if bitfields.r.len == 0 || bitfields.g.len == 0 || bitfields.b.len == 0 { |
467 | 17 | return Err(DecoderError::BitfieldMaskMissing(max_len).into()); |
468 | 547 | } |
469 | 547 | Ok(bitfields) |
470 | 640 | } |
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.39k | fn new_decoder(reader: R) -> BmpDecoder<R> { |
505 | 4.39k | BmpDecoder { |
506 | 4.39k | reader, |
507 | 4.39k | |
508 | 4.39k | bmp_header_type: BMPHeaderType::Info, |
509 | 4.39k | indexed_color: false, |
510 | 4.39k | |
511 | 4.39k | width: 0, |
512 | 4.39k | height: 0, |
513 | 4.39k | data_offset: 0, |
514 | 4.39k | top_down: false, |
515 | 4.39k | no_file_header: false, |
516 | 4.39k | add_alpha_channel: false, |
517 | 4.39k | has_loaded_metadata: false, |
518 | 4.39k | image_type: ImageType::Palette, |
519 | 4.39k | |
520 | 4.39k | bit_count: 0, |
521 | 4.39k | colors_used: 0, |
522 | 4.39k | palette: None, |
523 | 4.39k | bitfields: None, |
524 | 4.39k | } |
525 | 4.39k | } Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::new_decoder Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::new_decoder <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::new_decoder Line | Count | Source | 504 | 1.85k | fn new_decoder(reader: R) -> BmpDecoder<R> { | 505 | 1.85k | BmpDecoder { | 506 | 1.85k | reader, | 507 | 1.85k | | 508 | 1.85k | bmp_header_type: BMPHeaderType::Info, | 509 | 1.85k | indexed_color: false, | 510 | 1.85k | | 511 | 1.85k | width: 0, | 512 | 1.85k | height: 0, | 513 | 1.85k | data_offset: 0, | 514 | 1.85k | top_down: false, | 515 | 1.85k | no_file_header: false, | 516 | 1.85k | add_alpha_channel: false, | 517 | 1.85k | has_loaded_metadata: false, | 518 | 1.85k | image_type: ImageType::Palette, | 519 | 1.85k | | 520 | 1.85k | bit_count: 0, | 521 | 1.85k | colors_used: 0, | 522 | 1.85k | palette: None, | 523 | 1.85k | bitfields: None, | 524 | 1.85k | } | 525 | 1.85k | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::new_decoder Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::new_decoder Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::new_decoder <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::new_decoder Line | Count | Source | 504 | 2.29k | fn new_decoder(reader: R) -> BmpDecoder<R> { | 505 | 2.29k | BmpDecoder { | 506 | 2.29k | reader, | 507 | 2.29k | | 508 | 2.29k | bmp_header_type: BMPHeaderType::Info, | 509 | 2.29k | indexed_color: false, | 510 | 2.29k | | 511 | 2.29k | width: 0, | 512 | 2.29k | height: 0, | 513 | 2.29k | data_offset: 0, | 514 | 2.29k | top_down: false, | 515 | 2.29k | no_file_header: false, | 516 | 2.29k | add_alpha_channel: false, | 517 | 2.29k | has_loaded_metadata: false, | 518 | 2.29k | image_type: ImageType::Palette, | 519 | 2.29k | | 520 | 2.29k | bit_count: 0, | 521 | 2.29k | colors_used: 0, | 522 | 2.29k | palette: None, | 523 | 2.29k | bitfields: None, | 524 | 2.29k | } | 525 | 2.29k | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::new_decoder Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::new_decoder Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::new_decoder <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::new_decoder Line | Count | Source | 504 | 253 | fn new_decoder(reader: R) -> BmpDecoder<R> { | 505 | 253 | BmpDecoder { | 506 | 253 | reader, | 507 | 253 | | 508 | 253 | bmp_header_type: BMPHeaderType::Info, | 509 | 253 | indexed_color: false, | 510 | 253 | | 511 | 253 | width: 0, | 512 | 253 | height: 0, | 513 | 253 | data_offset: 0, | 514 | 253 | top_down: false, | 515 | 253 | no_file_header: false, | 516 | 253 | add_alpha_channel: false, | 517 | 253 | has_loaded_metadata: false, | 518 | 253 | image_type: ImageType::Palette, | 519 | 253 | | 520 | 253 | bit_count: 0, | 521 | 253 | colors_used: 0, | 522 | 253 | palette: None, | 523 | 253 | bitfields: None, | 524 | 253 | } | 525 | 253 | } |
|
526 | | |
527 | | /// Create a new decoder that decodes from the stream ```r``` |
528 | 2.00k | pub fn new(reader: R) -> ImageResult<BmpDecoder<R>> { |
529 | 2.00k | let mut decoder = Self::new_decoder(reader); |
530 | 2.00k | decoder.read_metadata()?; |
531 | 1.46k | Ok(decoder) |
532 | 2.00k | } Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::new Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::new <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::new Line | Count | Source | 528 | 1.85k | pub fn new(reader: R) -> ImageResult<BmpDecoder<R>> { | 529 | 1.85k | let mut decoder = Self::new_decoder(reader); | 530 | 1.85k | decoder.read_metadata()?; | 531 | 1.31k | Ok(decoder) | 532 | 1.85k | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::new Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::new Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::new Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::new Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::new Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::new Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::new <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::new Line | Count | Source | 528 | 153 | pub fn new(reader: R) -> ImageResult<BmpDecoder<R>> { | 529 | 153 | let mut decoder = Self::new_decoder(reader); | 530 | 153 | decoder.read_metadata()?; | 531 | 147 | Ok(decoder) | 532 | 153 | } |
|
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 | | pub fn new_without_file_header(reader: R) -> ImageResult<BmpDecoder<R>> { |
538 | | let mut decoder = Self::new_decoder(reader); |
539 | | decoder.no_file_header = true; |
540 | | decoder.read_metadata()?; |
541 | | Ok(decoder) |
542 | | } |
543 | | |
544 | | #[cfg(feature = "ico")] |
545 | 2.39k | pub(crate) fn new_with_ico_format(reader: R) -> ImageResult<BmpDecoder<R>> { |
546 | 2.39k | let mut decoder = Self::new_decoder(reader); |
547 | 2.39k | decoder.read_metadata_in_ico_format()?; |
548 | 1.81k | Ok(decoder) |
549 | 2.39k | } Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::new_with_ico_format Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::new_with_ico_format Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::new_with_ico_format Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::new_with_ico_format Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::new_with_ico_format Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::new_with_ico_format <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::new_with_ico_format Line | Count | Source | 545 | 2.29k | pub(crate) fn new_with_ico_format(reader: R) -> ImageResult<BmpDecoder<R>> { | 546 | 2.29k | let mut decoder = Self::new_decoder(reader); | 547 | 2.29k | decoder.read_metadata_in_ico_format()?; | 548 | 1.73k | Ok(decoder) | 549 | 2.29k | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::new_with_ico_format Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::new_with_ico_format Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::new_with_ico_format <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::new_with_ico_format Line | Count | Source | 545 | 100 | pub(crate) fn new_with_ico_format(reader: R) -> ImageResult<BmpDecoder<R>> { | 546 | 100 | let mut decoder = Self::new_decoder(reader); | 547 | 100 | decoder.read_metadata_in_ico_format()?; | 548 | 83 | Ok(decoder) | 549 | 100 | } |
|
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 | | pub fn set_indexed_color(&mut self, indexed_color: bool) { |
554 | | self.indexed_color = indexed_color; |
555 | | } |
556 | | |
557 | | #[cfg(feature = "ico")] |
558 | 470 | pub(crate) fn reader(&mut self) -> &mut R { |
559 | 470 | &mut self.reader |
560 | 470 | } Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::reader Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::reader Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::reader Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::reader Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::reader Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::reader <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::reader Line | Count | Source | 558 | 403 | pub(crate) fn reader(&mut self) -> &mut R { | 559 | 403 | &mut self.reader | 560 | 403 | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::reader Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::reader Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::reader <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::reader Line | Count | Source | 558 | 67 | pub(crate) fn reader(&mut self) -> &mut R { | 559 | 67 | &mut self.reader | 560 | 67 | } |
|
561 | | |
562 | 4.39k | fn read_file_header(&mut self) -> ImageResult<()> { |
563 | 4.39k | if self.no_file_header { |
564 | 2.39k | return Ok(()); |
565 | 2.00k | } |
566 | 2.00k | let mut signature = [0; 2]; |
567 | 2.00k | self.reader.read_exact(&mut signature)?; |
568 | | |
569 | 1.99k | if signature != b"BM"[..] { |
570 | 28 | return Err(DecoderError::BmpSignatureInvalid.into()); |
571 | 1.96k | } |
572 | | |
573 | | // The next 8 bytes represent file size, followed the 4 reserved bytes |
574 | | // We're not interesting these values |
575 | 1.96k | self.reader.read_u32::<LittleEndian>()?; |
576 | 1.96k | self.reader.read_u32::<LittleEndian>()?; |
577 | | |
578 | 1.96k | self.data_offset = u64::from(self.reader.read_u32::<LittleEndian>()?); |
579 | | |
580 | 1.95k | Ok(()) |
581 | 4.39k | } Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_file_header Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_file_header <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_file_header Line | Count | Source | 562 | 1.85k | fn read_file_header(&mut self) -> ImageResult<()> { | 563 | 1.85k | if self.no_file_header { | 564 | 0 | return Ok(()); | 565 | 1.85k | } | 566 | 1.85k | let mut signature = [0; 2]; | 567 | 1.85k | self.reader.read_exact(&mut signature)?; | 568 | | | 569 | 1.84k | if signature != b"BM"[..] { | 570 | 28 | return Err(DecoderError::BmpSignatureInvalid.into()); | 571 | 1.81k | } | 572 | | | 573 | | // The next 8 bytes represent file size, followed the 4 reserved bytes | 574 | | // We're not interesting these values | 575 | 1.81k | self.reader.read_u32::<LittleEndian>()?; | 576 | 1.81k | self.reader.read_u32::<LittleEndian>()?; | 577 | | | 578 | 1.80k | self.data_offset = u64::from(self.reader.read_u32::<LittleEndian>()?); | 579 | | | 580 | 1.80k | Ok(()) | 581 | 1.85k | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_file_header Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_file_header Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_file_header <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_file_header Line | Count | Source | 562 | 2.29k | fn read_file_header(&mut self) -> ImageResult<()> { | 563 | 2.29k | if self.no_file_header { | 564 | 2.29k | return Ok(()); | 565 | 0 | } | 566 | 0 | let mut signature = [0; 2]; | 567 | 0 | self.reader.read_exact(&mut signature)?; | 568 | | | 569 | 0 | if signature != b"BM"[..] { | 570 | 0 | return Err(DecoderError::BmpSignatureInvalid.into()); | 571 | 0 | } | 572 | | | 573 | | // The next 8 bytes represent file size, followed the 4 reserved bytes | 574 | | // We're not interesting these values | 575 | 0 | self.reader.read_u32::<LittleEndian>()?; | 576 | 0 | self.reader.read_u32::<LittleEndian>()?; | 577 | | | 578 | 0 | self.data_offset = u64::from(self.reader.read_u32::<LittleEndian>()?); | 579 | | | 580 | 0 | Ok(()) | 581 | 2.29k | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_file_header Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_file_header Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_file_header <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_file_header Line | Count | Source | 562 | 253 | fn read_file_header(&mut self) -> ImageResult<()> { | 563 | 253 | if self.no_file_header { | 564 | 100 | return Ok(()); | 565 | 153 | } | 566 | 153 | let mut signature = [0; 2]; | 567 | 153 | self.reader.read_exact(&mut signature)?; | 568 | | | 569 | 153 | if signature != b"BM"[..] { | 570 | 0 | return Err(DecoderError::BmpSignatureInvalid.into()); | 571 | 153 | } | 572 | | | 573 | | // The next 8 bytes represent file size, followed the 4 reserved bytes | 574 | | // We're not interesting these values | 575 | 153 | self.reader.read_u32::<LittleEndian>()?; | 576 | 153 | self.reader.read_u32::<LittleEndian>()?; | 577 | | | 578 | 153 | self.data_offset = u64::from(self.reader.read_u32::<LittleEndian>()?); | 579 | | | 580 | 153 | Ok(()) | 581 | 253 | } |
|
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 | 778 | 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 | 778 | self.width = i32::from(self.reader.read_u16::<LittleEndian>()?); |
590 | 776 | self.height = i32::from(self.reader.read_u16::<LittleEndian>()?); |
591 | | |
592 | 774 | check_for_overflow(self.width, self.height, self.num_channels())?; |
593 | | |
594 | | // Number of planes (format specifies that this should be 1). |
595 | 769 | if self.reader.read_u16::<LittleEndian>()? != 1 { |
596 | 46 | return Err(DecoderError::MoreThanOnePlane.into()); |
597 | 702 | } |
598 | | |
599 | 702 | self.bit_count = self.reader.read_u16::<LittleEndian>()?; |
600 | 699 | self.image_type = match self.bit_count { |
601 | 521 | 1 | 4 | 8 => ImageType::Palette, |
602 | 171 | 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 | 692 | Ok(()) |
613 | 778 | } Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_bitmap_core_header Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_bitmap_core_header <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_bitmap_core_header Line | Count | Source | 586 | 337 | 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 | 337 | self.width = i32::from(self.reader.read_u16::<LittleEndian>()?); | 590 | 335 | self.height = i32::from(self.reader.read_u16::<LittleEndian>()?); | 591 | | | 592 | 333 | check_for_overflow(self.width, self.height, self.num_channels())?; | 593 | | | 594 | | // Number of planes (format specifies that this should be 1). | 595 | 331 | if self.reader.read_u16::<LittleEndian>()? != 1 { | 596 | 21 | return Err(DecoderError::MoreThanOnePlane.into()); | 597 | 292 | } | 598 | | | 599 | 292 | self.bit_count = self.reader.read_u16::<LittleEndian>()?; | 600 | 290 | self.image_type = match self.bit_count { | 601 | 220 | 1 | 4 | 8 => ImageType::Palette, | 602 | 66 | 24 => ImageType::RGB24, | 603 | | _ => { | 604 | 4 | return Err(DecoderError::InvalidChannelWidth( | 605 | 4 | ChannelWidthError::Rgb, | 606 | 4 | self.bit_count, | 607 | 4 | ) | 608 | 4 | .into()) | 609 | | } | 610 | | }; | 611 | | | 612 | 286 | Ok(()) | 613 | 337 | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_bitmap_core_header Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_bitmap_core_header Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_bitmap_core_header <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_bitmap_core_header Line | Count | Source | 586 | 421 | 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 | 421 | self.width = i32::from(self.reader.read_u16::<LittleEndian>()?); | 590 | 421 | self.height = i32::from(self.reader.read_u16::<LittleEndian>()?); | 591 | | | 592 | 421 | check_for_overflow(self.width, self.height, self.num_channels())?; | 593 | | | 594 | | // Number of planes (format specifies that this should be 1). | 595 | 418 | if self.reader.read_u16::<LittleEndian>()? != 1 { | 596 | 25 | return Err(DecoderError::MoreThanOnePlane.into()); | 597 | 390 | } | 598 | | | 599 | 390 | self.bit_count = self.reader.read_u16::<LittleEndian>()?; | 600 | 389 | self.image_type = match self.bit_count { | 601 | 281 | 1 | 4 | 8 => ImageType::Palette, | 602 | 105 | 24 => ImageType::RGB24, | 603 | | _ => { | 604 | 3 | return Err(DecoderError::InvalidChannelWidth( | 605 | 3 | ChannelWidthError::Rgb, | 606 | 3 | self.bit_count, | 607 | 3 | ) | 608 | 3 | .into()) | 609 | | } | 610 | | }; | 611 | | | 612 | 386 | Ok(()) | 613 | 421 | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_bitmap_core_header Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_bitmap_core_header Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_bitmap_core_header <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_bitmap_core_header Line | Count | Source | 586 | 20 | 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 | 20 | self.width = i32::from(self.reader.read_u16::<LittleEndian>()?); | 590 | 20 | self.height = i32::from(self.reader.read_u16::<LittleEndian>()?); | 591 | | | 592 | 20 | check_for_overflow(self.width, self.height, self.num_channels())?; | 593 | | | 594 | | // Number of planes (format specifies that this should be 1). | 595 | 20 | if self.reader.read_u16::<LittleEndian>()? != 1 { | 596 | 0 | return Err(DecoderError::MoreThanOnePlane.into()); | 597 | 20 | } | 598 | | | 599 | 20 | self.bit_count = self.reader.read_u16::<LittleEndian>()?; | 600 | 20 | self.image_type = match self.bit_count { | 601 | 20 | 1 | 4 | 8 => ImageType::Palette, | 602 | 0 | 24 => ImageType::RGB24, | 603 | | _ => { | 604 | 0 | return Err(DecoderError::InvalidChannelWidth( | 605 | 0 | ChannelWidthError::Rgb, | 606 | 0 | self.bit_count, | 607 | 0 | ) | 608 | 0 | .into()) | 609 | | } | 610 | | }; | 611 | | | 612 | 20 | Ok(()) | 613 | 20 | } |
|
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.39k | fn read_bitmap_info_header(&mut self) -> ImageResult<()> { |
620 | 3.39k | self.width = self.reader.read_i32::<LittleEndian>()?; |
621 | 3.38k | self.height = self.reader.read_i32::<LittleEndian>()?; |
622 | | |
623 | | // Width can not be negative |
624 | 3.37k | if self.width < 0 { |
625 | 66 | return Err(DecoderError::NegativeWidth(self.width).into()); |
626 | 3.31k | } 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 | 39 | return Err(DecoderError::ImageTooLarge(self.width, self.height).into()); |
630 | 3.27k | } |
631 | | |
632 | 3.27k | if self.height == i32::MIN { |
633 | 2 | return Err(DecoderError::InvalidHeight.into()); |
634 | 3.26k | } |
635 | | |
636 | | // A negative height indicates a top-down DIB. |
637 | 3.26k | if self.height < 0 { |
638 | 591 | self.height *= -1; |
639 | 591 | self.top_down = true; |
640 | 2.67k | } |
641 | | |
642 | 3.26k | check_for_overflow(self.width, self.height, self.num_channels())?; |
643 | | |
644 | | // Number of planes (format specifies that this should be 1). |
645 | 3.26k | if self.reader.read_u16::<LittleEndian>()? != 1 { |
646 | 72 | return Err(DecoderError::MoreThanOnePlane.into()); |
647 | 3.11k | } |
648 | | |
649 | 3.11k | self.bit_count = self.reader.read_u16::<LittleEndian>()?; |
650 | 3.10k | let image_type_u32 = self.reader.read_u32::<LittleEndian>()?; |
651 | | |
652 | | // Top-down dibs can not be compressed. |
653 | 3.10k | if self.top_down && image_type_u32 != 0 && image_type_u32 != 3 { |
654 | 2 | return Err(DecoderError::ImageTypeInvalidForTopDown(image_type_u32).into()); |
655 | 3.09k | } |
656 | 3.09k | self.image_type = match image_type_u32 { |
657 | 121 | 0 => match self.bit_count { |
658 | 464 | 1 | 2 | 4 | 8 => ImageType::Palette, |
659 | 193 | 16 => ImageType::RGB16, |
660 | 32 | 24 => ImageType::RGB24, |
661 | 56 | 32 if self.add_alpha_channel => ImageType::RGBA32, |
662 | 65 | 32 => ImageType::RGB32, |
663 | | _ => { |
664 | 4 | return Err(DecoderError::InvalidChannelWidth( |
665 | 4 | ChannelWidthError::Rgb, |
666 | 4 | self.bit_count, |
667 | 4 | ) |
668 | 4 | .into()) |
669 | | } |
670 | | }, |
671 | 555 | 1 => match self.bit_count { |
672 | 524 | 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 | 949 | 2 => match self.bit_count { |
682 | 924 | 4 => ImageType::RLE4, |
683 | | _ => { |
684 | 25 | return Err(DecoderError::InvalidChannelWidth( |
685 | 25 | ChannelWidthError::Rle4, |
686 | 25 | self.bit_count, |
687 | 25 | ) |
688 | 25 | .into()) |
689 | | } |
690 | | }, |
691 | 679 | 3 => match self.bit_count { |
692 | 173 | 16 => ImageType::Bitfields16, |
693 | 503 | 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 | 93 | 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 | 95 | 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 | 2.93k | self.reader.read_u32::<LittleEndian>()?; |
740 | 2.90k | self.reader.read_u32::<LittleEndian>()?; |
741 | 2.90k | self.reader.read_u32::<LittleEndian>()?; |
742 | | |
743 | 2.89k | 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 | 2.89k | self.reader.read_u32::<LittleEndian>()?; |
748 | | |
749 | 2.88k | Ok(()) |
750 | 3.39k | } Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_bitmap_info_header Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_bitmap_info_header <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_bitmap_info_header Line | Count | Source | 619 | 1.42k | fn read_bitmap_info_header(&mut self) -> ImageResult<()> { | 620 | 1.42k | self.width = self.reader.read_i32::<LittleEndian>()?; | 621 | 1.41k | self.height = self.reader.read_i32::<LittleEndian>()?; | 622 | | | 623 | | // Width can not be negative | 624 | 1.41k | if self.width < 0 { | 625 | 32 | return Err(DecoderError::NegativeWidth(self.width).into()); | 626 | 1.38k | } 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 | 16 | return Err(DecoderError::ImageTooLarge(self.width, self.height).into()); | 630 | 1.36k | } | 631 | | | 632 | 1.36k | if self.height == i32::MIN { | 633 | 1 | return Err(DecoderError::InvalidHeight.into()); | 634 | 1.36k | } | 635 | | | 636 | | // A negative height indicates a top-down DIB. | 637 | 1.36k | if self.height < 0 { | 638 | 398 | self.height *= -1; | 639 | 398 | self.top_down = true; | 640 | 965 | } | 641 | | | 642 | 1.36k | check_for_overflow(self.width, self.height, self.num_channels())?; | 643 | | | 644 | | // Number of planes (format specifies that this should be 1). | 645 | 1.36k | if self.reader.read_u16::<LittleEndian>()? != 1 { | 646 | 17 | return Err(DecoderError::MoreThanOnePlane.into()); | 647 | 1.28k | } | 648 | | | 649 | 1.28k | self.bit_count = self.reader.read_u16::<LittleEndian>()?; | 650 | 1.28k | let image_type_u32 = self.reader.read_u32::<LittleEndian>()?; | 651 | | | 652 | | // Top-down dibs can not be compressed. | 653 | 1.27k | if self.top_down && image_type_u32 != 0 && image_type_u32 != 3 { | 654 | 1 | return Err(DecoderError::ImageTypeInvalidForTopDown(image_type_u32).into()); | 655 | 1.27k | } | 656 | 1.27k | self.image_type = match image_type_u32 { | 657 | 62 | 0 => match self.bit_count { | 658 | 208 | 1 | 2 | 4 | 8 => ImageType::Palette, | 659 | 75 | 16 => ImageType::RGB16, | 660 | 8 | 24 => ImageType::RGB24, | 661 | 0 | 32 if self.add_alpha_channel => ImageType::RGBA32, | 662 | 62 | 32 => ImageType::RGB32, | 663 | | _ => { | 664 | 1 | return Err(DecoderError::InvalidChannelWidth( | 665 | 1 | ChannelWidthError::Rgb, | 666 | 1 | self.bit_count, | 667 | 1 | ) | 668 | 1 | .into()) | 669 | | } | 670 | | }, | 671 | 172 | 1 => match self.bit_count { | 672 | 156 | 8 => ImageType::RLE8, | 673 | | _ => { | 674 | 16 | return Err(DecoderError::InvalidChannelWidth( | 675 | 16 | ChannelWidthError::Rle8, | 676 | 16 | self.bit_count, | 677 | 16 | ) | 678 | 16 | .into()) | 679 | | } | 680 | | }, | 681 | 371 | 2 => match self.bit_count { | 682 | 357 | 4 => ImageType::RLE4, | 683 | | _ => { | 684 | 14 | return Err(DecoderError::InvalidChannelWidth( | 685 | 14 | ChannelWidthError::Rle4, | 686 | 14 | self.bit_count, | 687 | 14 | ) | 688 | 14 | .into()) | 689 | | } | 690 | | }, | 691 | 334 | 3 => match self.bit_count { | 692 | 71 | 16 => ImageType::Bitfields16, | 693 | 262 | 32 => ImageType::Bitfields32, | 694 | | _ => { | 695 | 1 | return Err(DecoderError::InvalidChannelWidth( | 696 | 1 | ChannelWidthError::Bitfields, | 697 | 1 | self.bit_count, | 698 | 1 | ) | 699 | 1 | .into()) | 700 | | } | 701 | | }, | 702 | | 4 => { | 703 | | // JPEG compression is not implemented yet. | 704 | 1 | return Err(ImageError::Unsupported( | 705 | 1 | UnsupportedError::from_format_and_kind( | 706 | 1 | ImageFormat::Bmp.into(), | 707 | 1 | UnsupportedErrorKind::GenericFeature("JPEG compression".to_owned()), | 708 | 1 | ), | 709 | 1 | )); | 710 | | } | 711 | | 5 => { | 712 | | // PNG compression is not implemented yet. | 713 | 1 | return Err(ImageError::Unsupported( | 714 | 1 | UnsupportedError::from_format_and_kind( | 715 | 1 | ImageFormat::Bmp.into(), | 716 | 1 | UnsupportedErrorKind::GenericFeature("PNG compression".to_owned()), | 717 | 1 | ), | 718 | 1 | )); | 719 | | } | 720 | 42 | 11..=13 => { | 721 | | // CMYK types are not implemented yet. | 722 | 2 | return Err(ImageError::Unsupported( | 723 | 2 | UnsupportedError::from_format_and_kind( | 724 | 2 | ImageFormat::Bmp.into(), | 725 | 2 | UnsupportedErrorKind::GenericFeature("CMYK format".to_owned()), | 726 | 2 | ), | 727 | 2 | )); | 728 | | } | 729 | | _ => { | 730 | | // Unknown compression type. | 731 | 43 | 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 | 1.19k | self.reader.read_u32::<LittleEndian>()?; | 740 | 1.18k | self.reader.read_u32::<LittleEndian>()?; | 741 | 1.18k | self.reader.read_u32::<LittleEndian>()?; | 742 | | | 743 | 1.17k | 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 | 1.17k | self.reader.read_u32::<LittleEndian>()?; | 748 | | | 749 | 1.17k | Ok(()) | 750 | 1.42k | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_bitmap_info_header Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_bitmap_info_header Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_bitmap_info_header <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_bitmap_info_header Line | Count | Source | 619 | 1.75k | fn read_bitmap_info_header(&mut self) -> ImageResult<()> { | 620 | 1.75k | self.width = self.reader.read_i32::<LittleEndian>()?; | 621 | 1.75k | self.height = self.reader.read_i32::<LittleEndian>()?; | 622 | | | 623 | | // Width can not be negative | 624 | 1.74k | if self.width < 0 { | 625 | 34 | return Err(DecoderError::NegativeWidth(self.width).into()); | 626 | 1.71k | } 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 | 22 | return Err(DecoderError::ImageTooLarge(self.width, self.height).into()); | 630 | 1.69k | } | 631 | | | 632 | 1.69k | if self.height == i32::MIN { | 633 | 1 | return Err(DecoderError::InvalidHeight.into()); | 634 | 1.68k | } | 635 | | | 636 | | // A negative height indicates a top-down DIB. | 637 | 1.68k | if self.height < 0 { | 638 | 182 | self.height *= -1; | 639 | 182 | self.top_down = true; | 640 | 1.50k | } | 641 | | | 642 | 1.68k | check_for_overflow(self.width, self.height, self.num_channels())?; | 643 | | | 644 | | // Number of planes (format specifies that this should be 1). | 645 | 1.68k | if self.reader.read_u16::<LittleEndian>()? != 1 { | 646 | 55 | return Err(DecoderError::MoreThanOnePlane.into()); | 647 | 1.60k | } | 648 | | | 649 | 1.60k | self.bit_count = self.reader.read_u16::<LittleEndian>()?; | 650 | 1.60k | let image_type_u32 = self.reader.read_u32::<LittleEndian>()?; | 651 | | | 652 | | // Top-down dibs can not be compressed. | 653 | 1.60k | if self.top_down && image_type_u32 != 0 && image_type_u32 != 3 { | 654 | 1 | return Err(DecoderError::ImageTypeInvalidForTopDown(image_type_u32).into()); | 655 | 1.60k | } | 656 | 1.60k | self.image_type = match image_type_u32 { | 657 | 55 | 0 => match self.bit_count { | 658 | 227 | 1 | 2 | 4 | 8 => ImageType::Palette, | 659 | 110 | 16 => ImageType::RGB16, | 660 | 17 | 24 => ImageType::RGB24, | 661 | 55 | 32 if self.add_alpha_channel => ImageType::RGBA32, | 662 | 0 | 32 => ImageType::RGB32, | 663 | | _ => { | 664 | 3 | return Err(DecoderError::InvalidChannelWidth( | 665 | 3 | ChannelWidthError::Rgb, | 666 | 3 | self.bit_count, | 667 | 3 | ) | 668 | 3 | .into()) | 669 | | } | 670 | | }, | 671 | 368 | 1 => match self.bit_count { | 672 | 353 | 8 => ImageType::RLE8, | 673 | | _ => { | 674 | 15 | return Err(DecoderError::InvalidChannelWidth( | 675 | 15 | ChannelWidthError::Rle8, | 676 | 15 | self.bit_count, | 677 | 15 | ) | 678 | 15 | .into()) | 679 | | } | 680 | | }, | 681 | 447 | 2 => match self.bit_count { | 682 | 436 | 4 => ImageType::RLE4, | 683 | | _ => { | 684 | 11 | return Err(DecoderError::InvalidChannelWidth( | 685 | 11 | ChannelWidthError::Rle4, | 686 | 11 | self.bit_count, | 687 | 11 | ) | 688 | 11 | .into()) | 689 | | } | 690 | | }, | 691 | 322 | 3 => match self.bit_count { | 692 | 97 | 16 => ImageType::Bitfields16, | 693 | 223 | 32 => ImageType::Bitfields32, | 694 | | _ => { | 695 | 2 | return Err(DecoderError::InvalidChannelWidth( | 696 | 2 | ChannelWidthError::Bitfields, | 697 | 2 | self.bit_count, | 698 | 2 | ) | 699 | 2 | .into()) | 700 | | } | 701 | | }, | 702 | | 4 => { | 703 | | // JPEG compression is not implemented yet. | 704 | 1 | return Err(ImageError::Unsupported( | 705 | 1 | UnsupportedError::from_format_and_kind( | 706 | 1 | ImageFormat::Bmp.into(), | 707 | 1 | UnsupportedErrorKind::GenericFeature("JPEG compression".to_owned()), | 708 | 1 | ), | 709 | 1 | )); | 710 | | } | 711 | | 5 => { | 712 | | // PNG compression is not implemented yet. | 713 | 1 | return Err(ImageError::Unsupported( | 714 | 1 | UnsupportedError::from_format_and_kind( | 715 | 1 | ImageFormat::Bmp.into(), | 716 | 1 | UnsupportedErrorKind::GenericFeature("PNG compression".to_owned()), | 717 | 1 | ), | 718 | 1 | )); | 719 | | } | 720 | 51 | 11..=13 => { | 721 | | // CMYK types are not implemented yet. | 722 | 1 | return Err(ImageError::Unsupported( | 723 | 1 | UnsupportedError::from_format_and_kind( | 724 | 1 | ImageFormat::Bmp.into(), | 725 | 1 | UnsupportedErrorKind::GenericFeature("CMYK format".to_owned()), | 726 | 1 | ), | 727 | 1 | )); | 728 | | } | 729 | | _ => { | 730 | | // Unknown compression type. | 731 | 52 | 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 | 1.51k | self.reader.read_u32::<LittleEndian>()?; | 740 | 1.50k | self.reader.read_u32::<LittleEndian>()?; | 741 | 1.50k | self.reader.read_u32::<LittleEndian>()?; | 742 | | | 743 | 1.50k | 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 | 1.49k | self.reader.read_u32::<LittleEndian>()?; | 748 | | | 749 | 1.49k | Ok(()) | 750 | 1.75k | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_bitmap_info_header Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_bitmap_info_header Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_bitmap_info_header <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_bitmap_info_header Line | Count | Source | 619 | 218 | fn read_bitmap_info_header(&mut self) -> ImageResult<()> { | 620 | 218 | self.width = self.reader.read_i32::<LittleEndian>()?; | 621 | 218 | self.height = self.reader.read_i32::<LittleEndian>()?; | 622 | | | 623 | | // Width can not be negative | 624 | 218 | if self.width < 0 { | 625 | 0 | return Err(DecoderError::NegativeWidth(self.width).into()); | 626 | 218 | } 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 | 1 | return Err(DecoderError::ImageTooLarge(self.width, self.height).into()); | 630 | 217 | } | 631 | | | 632 | 217 | if self.height == i32::MIN { | 633 | 0 | return Err(DecoderError::InvalidHeight.into()); | 634 | 217 | } | 635 | | | 636 | | // A negative height indicates a top-down DIB. | 637 | 217 | if self.height < 0 { | 638 | 11 | self.height *= -1; | 639 | 11 | self.top_down = true; | 640 | 206 | } | 641 | | | 642 | 217 | check_for_overflow(self.width, self.height, self.num_channels())?; | 643 | | | 644 | | // Number of planes (format specifies that this should be 1). | 645 | 217 | if self.reader.read_u16::<LittleEndian>()? != 1 { | 646 | 0 | return Err(DecoderError::MoreThanOnePlane.into()); | 647 | 217 | } | 648 | | | 649 | 217 | self.bit_count = self.reader.read_u16::<LittleEndian>()?; | 650 | 217 | let image_type_u32 = self.reader.read_u32::<LittleEndian>()?; | 651 | | | 652 | | // Top-down dibs can not be compressed. | 653 | 217 | if self.top_down && image_type_u32 != 0 && image_type_u32 != 3 { | 654 | 0 | return Err(DecoderError::ImageTypeInvalidForTopDown(image_type_u32).into()); | 655 | 217 | } | 656 | 217 | self.image_type = match image_type_u32 { | 657 | 4 | 0 => match self.bit_count { | 658 | 29 | 1 | 2 | 4 | 8 => ImageType::Palette, | 659 | 8 | 16 => ImageType::RGB16, | 660 | 7 | 24 => ImageType::RGB24, | 661 | 1 | 32 if self.add_alpha_channel => ImageType::RGBA32, | 662 | 3 | 32 => ImageType::RGB32, | 663 | | _ => { | 664 | 0 | return Err(DecoderError::InvalidChannelWidth( | 665 | 0 | ChannelWidthError::Rgb, | 666 | 0 | self.bit_count, | 667 | 0 | ) | 668 | 0 | .into()) | 669 | | } | 670 | | }, | 671 | 15 | 1 => match self.bit_count { | 672 | 15 | 8 => ImageType::RLE8, | 673 | | _ => { | 674 | 0 | return Err(DecoderError::InvalidChannelWidth( | 675 | 0 | ChannelWidthError::Rle8, | 676 | 0 | self.bit_count, | 677 | 0 | ) | 678 | 0 | .into()) | 679 | | } | 680 | | }, | 681 | 131 | 2 => match self.bit_count { | 682 | 131 | 4 => ImageType::RLE4, | 683 | | _ => { | 684 | 0 | return Err(DecoderError::InvalidChannelWidth( | 685 | 0 | ChannelWidthError::Rle4, | 686 | 0 | self.bit_count, | 687 | 0 | ) | 688 | 0 | .into()) | 689 | | } | 690 | | }, | 691 | 23 | 3 => match self.bit_count { | 692 | 5 | 16 => ImageType::Bitfields16, | 693 | 18 | 32 => ImageType::Bitfields32, | 694 | | _ => { | 695 | 0 | return Err(DecoderError::InvalidChannelWidth( | 696 | 0 | ChannelWidthError::Bitfields, | 697 | 0 | self.bit_count, | 698 | 0 | ) | 699 | 0 | .into()) | 700 | | } | 701 | | }, | 702 | | 4 => { | 703 | | // JPEG compression is not implemented yet. | 704 | 0 | return Err(ImageError::Unsupported( | 705 | 0 | UnsupportedError::from_format_and_kind( | 706 | 0 | ImageFormat::Bmp.into(), | 707 | 0 | UnsupportedErrorKind::GenericFeature("JPEG compression".to_owned()), | 708 | 0 | ), | 709 | 0 | )); | 710 | | } | 711 | | 5 => { | 712 | | // PNG compression is not implemented yet. | 713 | 0 | return Err(ImageError::Unsupported( | 714 | 0 | UnsupportedError::from_format_and_kind( | 715 | 0 | ImageFormat::Bmp.into(), | 716 | 0 | UnsupportedErrorKind::GenericFeature("PNG compression".to_owned()), | 717 | 0 | ), | 718 | 0 | )); | 719 | | } | 720 | 0 | 11..=13 => { | 721 | | // CMYK types are not implemented yet. | 722 | 0 | return Err(ImageError::Unsupported( | 723 | 0 | UnsupportedError::from_format_and_kind( | 724 | 0 | ImageFormat::Bmp.into(), | 725 | 0 | UnsupportedErrorKind::GenericFeature("CMYK format".to_owned()), | 726 | 0 | ), | 727 | 0 | )); | 728 | | } | 729 | | _ => { | 730 | | // Unknown compression type. | 731 | 0 | 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 | 217 | self.reader.read_u32::<LittleEndian>()?; | 740 | 217 | self.reader.read_u32::<LittleEndian>()?; | 741 | 217 | self.reader.read_u32::<LittleEndian>()?; | 742 | | | 743 | 217 | 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 | 217 | self.reader.read_u32::<LittleEndian>()?; | 748 | | | 749 | 217 | Ok(()) | 750 | 218 | } |
|
751 | | |
752 | 664 | fn read_bitmasks(&mut self) -> ImageResult<()> { |
753 | 664 | let r_mask = self.reader.read_u32::<LittleEndian>()?; |
754 | 656 | let g_mask = self.reader.read_u32::<LittleEndian>()?; |
755 | 651 | let b_mask = self.reader.read_u32::<LittleEndian>()?; |
756 | | |
757 | 642 | let a_mask = match self.bmp_header_type { |
758 | | BMPHeaderType::V3 | BMPHeaderType::V4 | BMPHeaderType::V5 => { |
759 | 281 | self.reader.read_u32::<LittleEndian>()? |
760 | | } |
761 | 361 | _ => 0, |
762 | | }; |
763 | | |
764 | 640 | self.bitfields = match self.image_type { |
765 | | ImageType::Bitfields16 => { |
766 | 161 | Some(Bitfields::from_mask(r_mask, g_mask, b_mask, a_mask, 16)?) |
767 | | } |
768 | | ImageType::Bitfields32 => { |
769 | 479 | Some(Bitfields::from_mask(r_mask, g_mask, b_mask, a_mask, 32)?) |
770 | | } |
771 | 0 | _ => None, |
772 | | }; |
773 | | |
774 | 547 | if self.bitfields.is_some() && a_mask != 0 { |
775 | 239 | self.add_alpha_channel = true; |
776 | 308 | } |
777 | | |
778 | 547 | Ok(()) |
779 | 664 | } Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_bitmasks Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_bitmasks <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_bitmasks Line | Count | Source | 752 | 323 | fn read_bitmasks(&mut self) -> ImageResult<()> { | 753 | 323 | let r_mask = self.reader.read_u32::<LittleEndian>()?; | 754 | 319 | let g_mask = self.reader.read_u32::<LittleEndian>()?; | 755 | 317 | let b_mask = self.reader.read_u32::<LittleEndian>()?; | 756 | | | 757 | 313 | let a_mask = match self.bmp_header_type { | 758 | | BMPHeaderType::V3 | BMPHeaderType::V4 | BMPHeaderType::V5 => { | 759 | 188 | self.reader.read_u32::<LittleEndian>()? | 760 | | } | 761 | 125 | _ => 0, | 762 | | }; | 763 | | | 764 | 312 | self.bitfields = match self.image_type { | 765 | | ImageType::Bitfields16 => { | 766 | 67 | Some(Bitfields::from_mask(r_mask, g_mask, b_mask, a_mask, 16)?) | 767 | | } | 768 | | ImageType::Bitfields32 => { | 769 | 245 | Some(Bitfields::from_mask(r_mask, g_mask, b_mask, a_mask, 32)?) | 770 | | } | 771 | 0 | _ => None, | 772 | | }; | 773 | | | 774 | 272 | if self.bitfields.is_some() && a_mask != 0 { | 775 | 157 | self.add_alpha_channel = true; | 776 | 157 | } | 777 | | | 778 | 272 | Ok(()) | 779 | 323 | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_bitmasks Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_bitmasks Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_bitmasks <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_bitmasks Line | Count | Source | 752 | 318 | fn read_bitmasks(&mut self) -> ImageResult<()> { | 753 | 318 | let r_mask = self.reader.read_u32::<LittleEndian>()?; | 754 | 314 | let g_mask = self.reader.read_u32::<LittleEndian>()?; | 755 | 311 | let b_mask = self.reader.read_u32::<LittleEndian>()?; | 756 | | | 757 | 306 | let a_mask = match self.bmp_header_type { | 758 | | BMPHeaderType::V3 | BMPHeaderType::V4 | BMPHeaderType::V5 => { | 759 | 83 | self.reader.read_u32::<LittleEndian>()? | 760 | | } | 761 | 223 | _ => 0, | 762 | | }; | 763 | | | 764 | 305 | self.bitfields = match self.image_type { | 765 | | ImageType::Bitfields16 => { | 766 | 89 | Some(Bitfields::from_mask(r_mask, g_mask, b_mask, a_mask, 16)?) | 767 | | } | 768 | | ImageType::Bitfields32 => { | 769 | 216 | Some(Bitfields::from_mask(r_mask, g_mask, b_mask, a_mask, 32)?) | 770 | | } | 771 | 0 | _ => None, | 772 | | }; | 773 | | | 774 | 255 | if self.bitfields.is_some() && a_mask != 0 { | 775 | 74 | self.add_alpha_channel = true; | 776 | 181 | } | 777 | | | 778 | 255 | Ok(()) | 779 | 318 | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_bitmasks Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_bitmasks Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_bitmasks <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_bitmasks Line | Count | Source | 752 | 23 | fn read_bitmasks(&mut self) -> ImageResult<()> { | 753 | 23 | let r_mask = self.reader.read_u32::<LittleEndian>()?; | 754 | 23 | let g_mask = self.reader.read_u32::<LittleEndian>()?; | 755 | 23 | let b_mask = self.reader.read_u32::<LittleEndian>()?; | 756 | | | 757 | 23 | let a_mask = match self.bmp_header_type { | 758 | | BMPHeaderType::V3 | BMPHeaderType::V4 | BMPHeaderType::V5 => { | 759 | 10 | self.reader.read_u32::<LittleEndian>()? | 760 | | } | 761 | 13 | _ => 0, | 762 | | }; | 763 | | | 764 | 23 | self.bitfields = match self.image_type { | 765 | | ImageType::Bitfields16 => { | 766 | 5 | Some(Bitfields::from_mask(r_mask, g_mask, b_mask, a_mask, 16)?) | 767 | | } | 768 | | ImageType::Bitfields32 => { | 769 | 18 | Some(Bitfields::from_mask(r_mask, g_mask, b_mask, a_mask, 32)?) | 770 | | } | 771 | 0 | _ => None, | 772 | | }; | 773 | | | 774 | 20 | if self.bitfields.is_some() && a_mask != 0 { | 775 | 8 | self.add_alpha_channel = true; | 776 | 12 | } | 777 | | | 778 | 20 | Ok(()) | 779 | 23 | } |
|
780 | | |
781 | 4.39k | fn read_metadata(&mut self) -> ImageResult<()> { |
782 | 4.39k | if !self.has_loaded_metadata { |
783 | 4.39k | self.read_file_header()?; |
784 | 4.34k | let bmp_header_offset = self.reader.stream_position()?; |
785 | 4.34k | let bmp_header_size = self.reader.read_u32::<LittleEndian>()?; |
786 | 4.34k | let bmp_header_end = bmp_header_offset + u64::from(bmp_header_size); |
787 | | |
788 | 176 | self.bmp_header_type = match bmp_header_size { |
789 | 778 | BITMAPCOREHEADER_SIZE => BMPHeaderType::Core, |
790 | 2.61k | BITMAPINFOHEADER_SIZE => BMPHeaderType::Info, |
791 | 185 | BITMAPV2HEADER_SIZE => BMPHeaderType::V2, |
792 | 428 | BITMAPV3HEADER_SIZE => BMPHeaderType::V3, |
793 | 126 | BITMAPV4HEADER_SIZE => BMPHeaderType::V4, |
794 | 42 | BITMAPV5HEADER_SIZE => BMPHeaderType::V5, |
795 | 176 | _ if bmp_header_size < BITMAPCOREHEADER_SIZE => { |
796 | | // Size of any valid header types won't be smaller than core header type. |
797 | 16 | return Err(DecoderError::HeaderTooSmall(bmp_header_size).into()); |
798 | | } |
799 | | _ => { |
800 | 160 | return Err(ImageError::Unsupported( |
801 | 160 | UnsupportedError::from_format_and_kind( |
802 | 160 | ImageFormat::Bmp.into(), |
803 | 160 | UnsupportedErrorKind::GenericFeature(format!( |
804 | 160 | "Unknown bitmap header type (size={bmp_header_size})" |
805 | 160 | )), |
806 | 160 | ), |
807 | 160 | )) |
808 | | } |
809 | | }; |
810 | | |
811 | 4.16k | match self.bmp_header_type { |
812 | | BMPHeaderType::Core => { |
813 | 778 | self.read_bitmap_core_header()?; |
814 | | } |
815 | | BMPHeaderType::Info |
816 | | | BMPHeaderType::V2 |
817 | | | BMPHeaderType::V3 |
818 | | | BMPHeaderType::V4 |
819 | | | BMPHeaderType::V5 => { |
820 | 3.39k | self.read_bitmap_info_header()?; |
821 | | } |
822 | | } |
823 | | |
824 | 3.57k | let mut bitmask_bytes_offset = 0; |
825 | 3.57k | if self.image_type == ImageType::Bitfields16 |
826 | 3.40k | || self.image_type == ImageType::Bitfields32 |
827 | | { |
828 | 664 | 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 | 288 | if matches!( |
837 | 547 | self.bmp_header_type, |
838 | | BMPHeaderType::Info | BMPHeaderType::V4 | BMPHeaderType::V5 |
839 | 259 | ) { |
840 | 259 | // This is `size_of::<u32>() * 3` (a red, green, and blue mask), but with less noise. |
841 | 259 | bitmask_bytes_offset = 12; |
842 | 288 | } |
843 | 2.91k | }; |
844 | | |
845 | 3.45k | self.reader |
846 | 3.45k | .seek(SeekFrom::Start(bmp_header_end + bitmask_bytes_offset))?; |
847 | | |
848 | 3.45k | match self.image_type { |
849 | 2.40k | ImageType::Palette | ImageType::RLE4 | ImageType::RLE8 => self.read_palette()?, |
850 | 1.05k | _ => {} |
851 | | } |
852 | | |
853 | 3.28k | if self.no_file_header { |
854 | | // Use the offset of the end of metadata instead of reading a BMP file header. |
855 | 1.81k | self.data_offset = self.reader.stream_position()?; |
856 | 1.46k | } |
857 | | |
858 | 3.28k | self.has_loaded_metadata = true; |
859 | 0 | } |
860 | 3.28k | Ok(()) |
861 | 4.39k | } Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_metadata Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_metadata <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_metadata Line | Count | Source | 781 | 1.85k | fn read_metadata(&mut self) -> ImageResult<()> { | 782 | 1.85k | if !self.has_loaded_metadata { | 783 | 1.85k | self.read_file_header()?; | 784 | 1.80k | let bmp_header_offset = self.reader.stream_position()?; | 785 | 1.80k | let bmp_header_size = self.reader.read_u32::<LittleEndian>()?; | 786 | 1.80k | let bmp_header_end = bmp_header_offset + u64::from(bmp_header_size); | 787 | | | 788 | 40 | self.bmp_header_type = match bmp_header_size { | 789 | 337 | BITMAPCOREHEADER_SIZE => BMPHeaderType::Core, | 790 | 973 | BITMAPINFOHEADER_SIZE => BMPHeaderType::Info, | 791 | 127 | BITMAPV2HEADER_SIZE => BMPHeaderType::V2, | 792 | 273 | BITMAPV3HEADER_SIZE => BMPHeaderType::V3, | 793 | 44 | BITMAPV4HEADER_SIZE => BMPHeaderType::V4, | 794 | 6 | BITMAPV5HEADER_SIZE => BMPHeaderType::V5, | 795 | 40 | _ if bmp_header_size < BITMAPCOREHEADER_SIZE => { | 796 | | // Size of any valid header types won't be smaller than core header type. | 797 | 4 | return Err(DecoderError::HeaderTooSmall(bmp_header_size).into()); | 798 | | } | 799 | | _ => { | 800 | 36 | return Err(ImageError::Unsupported( | 801 | 36 | UnsupportedError::from_format_and_kind( | 802 | 36 | ImageFormat::Bmp.into(), | 803 | 36 | UnsupportedErrorKind::GenericFeature(format!( | 804 | 36 | "Unknown bitmap header type (size={bmp_header_size})" | 805 | 36 | )), | 806 | 36 | ), | 807 | 36 | )) | 808 | | } | 809 | | }; | 810 | | | 811 | 1.76k | match self.bmp_header_type { | 812 | | BMPHeaderType::Core => { | 813 | 337 | self.read_bitmap_core_header()?; | 814 | | } | 815 | | BMPHeaderType::Info | 816 | | | BMPHeaderType::V2 | 817 | | | BMPHeaderType::V3 | 818 | | | BMPHeaderType::V4 | 819 | | | BMPHeaderType::V5 => { | 820 | 1.42k | self.read_bitmap_info_header()?; | 821 | | } | 822 | | } | 823 | | | 824 | 1.45k | let mut bitmask_bytes_offset = 0; | 825 | 1.45k | if self.image_type == ImageType::Bitfields16 | 826 | 1.38k | || self.image_type == ImageType::Bitfields32 | 827 | | { | 828 | 323 | 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 | 197 | if matches!( | 837 | 272 | self.bmp_header_type, | 838 | | BMPHeaderType::Info | BMPHeaderType::V4 | BMPHeaderType::V5 | 839 | 75 | ) { | 840 | 75 | // This is `size_of::<u32>() * 3` (a red, green, and blue mask), but with less noise. | 841 | 75 | bitmask_bytes_offset = 12; | 842 | 197 | } | 843 | 1.13k | }; | 844 | | | 845 | 1.40k | self.reader | 846 | 1.40k | .seek(SeekFrom::Start(bmp_header_end + bitmask_bytes_offset))?; | 847 | | | 848 | 1.40k | match self.image_type { | 849 | 931 | ImageType::Palette | ImageType::RLE4 | ImageType::RLE8 => self.read_palette()?, | 850 | 477 | _ => {} | 851 | | } | 852 | | | 853 | 1.31k | if self.no_file_header { | 854 | | // Use the offset of the end of metadata instead of reading a BMP file header. | 855 | 0 | self.data_offset = self.reader.stream_position()?; | 856 | 1.31k | } | 857 | | | 858 | 1.31k | self.has_loaded_metadata = true; | 859 | 0 | } | 860 | 1.31k | Ok(()) | 861 | 1.85k | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_metadata Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_metadata Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_metadata <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_metadata Line | Count | Source | 781 | 2.29k | fn read_metadata(&mut self) -> ImageResult<()> { | 782 | 2.29k | if !self.has_loaded_metadata { | 783 | 2.29k | self.read_file_header()?; | 784 | 2.29k | let bmp_header_offset = self.reader.stream_position()?; | 785 | 2.29k | let bmp_header_size = self.reader.read_u32::<LittleEndian>()?; | 786 | 2.29k | let bmp_header_end = bmp_header_offset + u64::from(bmp_header_size); | 787 | | | 788 | 121 | self.bmp_header_type = match bmp_header_size { | 789 | 421 | BITMAPCOREHEADER_SIZE => BMPHeaderType::Core, | 790 | 1.45k | BITMAPINFOHEADER_SIZE => BMPHeaderType::Info, | 791 | 56 | BITMAPV2HEADER_SIZE => BMPHeaderType::V2, | 792 | 144 | BITMAPV3HEADER_SIZE => BMPHeaderType::V3, | 793 | 73 | BITMAPV4HEADER_SIZE => BMPHeaderType::V4, | 794 | 27 | BITMAPV5HEADER_SIZE => BMPHeaderType::V5, | 795 | 121 | _ if bmp_header_size < BITMAPCOREHEADER_SIZE => { | 796 | | // Size of any valid header types won't be smaller than core header type. | 797 | 10 | return Err(DecoderError::HeaderTooSmall(bmp_header_size).into()); | 798 | | } | 799 | | _ => { | 800 | 111 | return Err(ImageError::Unsupported( | 801 | 111 | UnsupportedError::from_format_and_kind( | 802 | 111 | ImageFormat::Bmp.into(), | 803 | 111 | UnsupportedErrorKind::GenericFeature(format!( | 804 | 111 | "Unknown bitmap header type (size={bmp_header_size})" | 805 | 111 | )), | 806 | 111 | ), | 807 | 111 | )) | 808 | | } | 809 | | }; | 810 | | | 811 | 2.17k | match self.bmp_header_type { | 812 | | BMPHeaderType::Core => { | 813 | 421 | self.read_bitmap_core_header()?; | 814 | | } | 815 | | BMPHeaderType::Info | 816 | | | BMPHeaderType::V2 | 817 | | | BMPHeaderType::V3 | 818 | | | BMPHeaderType::V4 | 819 | | | BMPHeaderType::V5 => { | 820 | 1.75k | self.read_bitmap_info_header()?; | 821 | | } | 822 | | } | 823 | | | 824 | 1.88k | let mut bitmask_bytes_offset = 0; | 825 | 1.88k | if self.image_type == ImageType::Bitfields16 | 826 | 1.78k | || self.image_type == ImageType::Bitfields32 | 827 | | { | 828 | 318 | 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 | 85 | if matches!( | 837 | 255 | self.bmp_header_type, | 838 | | BMPHeaderType::Info | BMPHeaderType::V4 | BMPHeaderType::V5 | 839 | 170 | ) { | 840 | 170 | // This is `size_of::<u32>() * 3` (a red, green, and blue mask), but with less noise. | 841 | 170 | bitmask_bytes_offset = 12; | 842 | 170 | } | 843 | 1.56k | }; | 844 | | | 845 | 1.81k | self.reader | 846 | 1.81k | .seek(SeekFrom::Start(bmp_header_end + bitmask_bytes_offset))?; | 847 | | | 848 | 1.81k | match self.image_type { | 849 | 1.27k | ImageType::Palette | ImageType::RLE4 | ImageType::RLE8 => self.read_palette()?, | 850 | 538 | _ => {} | 851 | | } | 852 | | | 853 | 1.73k | if self.no_file_header { | 854 | | // Use the offset of the end of metadata instead of reading a BMP file header. | 855 | 1.73k | self.data_offset = self.reader.stream_position()?; | 856 | 0 | } | 857 | | | 858 | 1.73k | self.has_loaded_metadata = true; | 859 | 0 | } | 860 | 1.73k | Ok(()) | 861 | 2.29k | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_metadata Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_metadata Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_metadata <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_metadata Line | Count | Source | 781 | 253 | fn read_metadata(&mut self) -> ImageResult<()> { | 782 | 253 | if !self.has_loaded_metadata { | 783 | 253 | self.read_file_header()?; | 784 | 253 | let bmp_header_offset = self.reader.stream_position()?; | 785 | 253 | let bmp_header_size = self.reader.read_u32::<LittleEndian>()?; | 786 | 253 | let bmp_header_end = bmp_header_offset + u64::from(bmp_header_size); | 787 | | | 788 | 15 | self.bmp_header_type = match bmp_header_size { | 789 | 20 | BITMAPCOREHEADER_SIZE => BMPHeaderType::Core, | 790 | 187 | BITMAPINFOHEADER_SIZE => BMPHeaderType::Info, | 791 | 2 | BITMAPV2HEADER_SIZE => BMPHeaderType::V2, | 792 | 11 | BITMAPV3HEADER_SIZE => BMPHeaderType::V3, | 793 | 9 | BITMAPV4HEADER_SIZE => BMPHeaderType::V4, | 794 | 9 | BITMAPV5HEADER_SIZE => BMPHeaderType::V5, | 795 | 15 | _ if bmp_header_size < BITMAPCOREHEADER_SIZE => { | 796 | | // Size of any valid header types won't be smaller than core header type. | 797 | 2 | return Err(DecoderError::HeaderTooSmall(bmp_header_size).into()); | 798 | | } | 799 | | _ => { | 800 | 13 | return Err(ImageError::Unsupported( | 801 | 13 | UnsupportedError::from_format_and_kind( | 802 | 13 | ImageFormat::Bmp.into(), | 803 | 13 | UnsupportedErrorKind::GenericFeature(format!( | 804 | 13 | "Unknown bitmap header type (size={bmp_header_size})" | 805 | 13 | )), | 806 | 13 | ), | 807 | 13 | )) | 808 | | } | 809 | | }; | 810 | | | 811 | 238 | match self.bmp_header_type { | 812 | | BMPHeaderType::Core => { | 813 | 20 | self.read_bitmap_core_header()?; | 814 | | } | 815 | | BMPHeaderType::Info | 816 | | | BMPHeaderType::V2 | 817 | | | BMPHeaderType::V3 | 818 | | | BMPHeaderType::V4 | 819 | | | BMPHeaderType::V5 => { | 820 | 218 | self.read_bitmap_info_header()?; | 821 | | } | 822 | | } | 823 | | | 824 | 237 | let mut bitmask_bytes_offset = 0; | 825 | 237 | if self.image_type == ImageType::Bitfields16 | 826 | 232 | || self.image_type == ImageType::Bitfields32 | 827 | | { | 828 | 23 | 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 | 6 | if matches!( | 837 | 20 | self.bmp_header_type, | 838 | | BMPHeaderType::Info | BMPHeaderType::V4 | BMPHeaderType::V5 | 839 | 14 | ) { | 840 | 14 | // This is `size_of::<u32>() * 3` (a red, green, and blue mask), but with less noise. | 841 | 14 | bitmask_bytes_offset = 12; | 842 | 14 | } | 843 | 214 | }; | 844 | | | 845 | 234 | self.reader | 846 | 234 | .seek(SeekFrom::Start(bmp_header_end + bitmask_bytes_offset))?; | 847 | | | 848 | 234 | match self.image_type { | 849 | 195 | ImageType::Palette | ImageType::RLE4 | ImageType::RLE8 => self.read_palette()?, | 850 | 39 | _ => {} | 851 | | } | 852 | | | 853 | 230 | if self.no_file_header { | 854 | | // Use the offset of the end of metadata instead of reading a BMP file header. | 855 | 83 | self.data_offset = self.reader.stream_position()?; | 856 | 147 | } | 857 | | | 858 | 230 | self.has_loaded_metadata = true; | 859 | 0 | } | 860 | 230 | Ok(()) | 861 | 253 | } |
|
862 | | |
863 | | #[cfg(feature = "ico")] |
864 | | #[doc(hidden)] |
865 | 2.39k | pub fn read_metadata_in_ico_format(&mut self) -> ImageResult<()> { |
866 | 2.39k | self.no_file_header = true; |
867 | 2.39k | self.add_alpha_channel = true; |
868 | 2.39k | 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.81k | self.height /= 2; |
873 | 1.81k | Ok(()) |
874 | 2.39k | } Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_metadata_in_ico_format Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_metadata_in_ico_format Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_metadata_in_ico_format Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_metadata_in_ico_format Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_metadata_in_ico_format Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_metadata_in_ico_format <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_metadata_in_ico_format Line | Count | Source | 865 | 2.29k | pub fn read_metadata_in_ico_format(&mut self) -> ImageResult<()> { | 866 | 2.29k | self.no_file_header = true; | 867 | 2.29k | self.add_alpha_channel = true; | 868 | 2.29k | 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.73k | self.height /= 2; | 873 | 1.73k | Ok(()) | 874 | 2.29k | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_metadata_in_ico_format Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_metadata_in_ico_format Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_metadata_in_ico_format <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_metadata_in_ico_format Line | Count | Source | 865 | 100 | pub fn read_metadata_in_ico_format(&mut self) -> ImageResult<()> { | 866 | 100 | self.no_file_header = true; | 867 | 100 | self.add_alpha_channel = true; | 868 | 100 | 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 | 83 | self.height /= 2; | 873 | 83 | Ok(()) | 874 | 100 | } |
|
875 | | |
876 | 2.40k | fn get_palette_size(&mut self) -> ImageResult<usize> { |
877 | 2.40k | match self.colors_used { |
878 | 781 | 0 => Ok(1 << self.bit_count), |
879 | | _ => { |
880 | 1.62k | if self.colors_used > 1 << self.bit_count { |
881 | 132 | return Err(DecoderError::PaletteSizeExceeded { |
882 | 132 | colors_used: self.colors_used, |
883 | 132 | bit_count: self.bit_count, |
884 | 132 | } |
885 | 132 | .into()); |
886 | 1.49k | } |
887 | 1.49k | Ok(self.colors_used as usize) |
888 | | } |
889 | | } |
890 | 2.40k | } Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::get_palette_size Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::get_palette_size <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::get_palette_size Line | Count | Source | 876 | 931 | fn get_palette_size(&mut self) -> ImageResult<usize> { | 877 | 931 | match self.colors_used { | 878 | 367 | 0 => Ok(1 << self.bit_count), | 879 | | _ => { | 880 | 564 | if self.colors_used > 1 << self.bit_count { | 881 | 66 | return Err(DecoderError::PaletteSizeExceeded { | 882 | 66 | colors_used: self.colors_used, | 883 | 66 | bit_count: self.bit_count, | 884 | 66 | } | 885 | 66 | .into()); | 886 | 498 | } | 887 | 498 | Ok(self.colors_used as usize) | 888 | | } | 889 | | } | 890 | 931 | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::get_palette_size Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::get_palette_size Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::get_palette_size <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::get_palette_size Line | Count | Source | 876 | 1.27k | fn get_palette_size(&mut self) -> ImageResult<usize> { | 877 | 1.27k | match self.colors_used { | 878 | 325 | 0 => Ok(1 << self.bit_count), | 879 | | _ => { | 880 | 954 | if self.colors_used > 1 << self.bit_count { | 881 | 62 | return Err(DecoderError::PaletteSizeExceeded { | 882 | 62 | colors_used: self.colors_used, | 883 | 62 | bit_count: self.bit_count, | 884 | 62 | } | 885 | 62 | .into()); | 886 | 892 | } | 887 | 892 | Ok(self.colors_used as usize) | 888 | | } | 889 | | } | 890 | 1.27k | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::get_palette_size Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::get_palette_size Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::get_palette_size <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::get_palette_size Line | Count | Source | 876 | 195 | fn get_palette_size(&mut self) -> ImageResult<usize> { | 877 | 195 | match self.colors_used { | 878 | 89 | 0 => Ok(1 << self.bit_count), | 879 | | _ => { | 880 | 106 | if self.colors_used > 1 << self.bit_count { | 881 | 4 | return Err(DecoderError::PaletteSizeExceeded { | 882 | 4 | colors_used: self.colors_used, | 883 | 4 | bit_count: self.bit_count, | 884 | 4 | } | 885 | 4 | .into()); | 886 | 102 | } | 887 | 102 | Ok(self.colors_used as usize) | 888 | | } | 889 | | } | 890 | 195 | } |
|
891 | | |
892 | 2.40k | fn bytes_per_color(&self) -> usize { |
893 | 2.40k | match self.bmp_header_type { |
894 | 521 | BMPHeaderType::Core => 3, |
895 | 1.88k | _ => 4, |
896 | | } |
897 | 2.40k | } Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::bytes_per_color Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::bytes_per_color <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::bytes_per_color Line | Count | Source | 892 | 931 | fn bytes_per_color(&self) -> usize { | 893 | 931 | match self.bmp_header_type { | 894 | 220 | BMPHeaderType::Core => 3, | 895 | 711 | _ => 4, | 896 | | } | 897 | 931 | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::bytes_per_color Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::bytes_per_color Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::bytes_per_color <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::bytes_per_color Line | Count | Source | 892 | 1.27k | fn bytes_per_color(&self) -> usize { | 893 | 1.27k | match self.bmp_header_type { | 894 | 281 | BMPHeaderType::Core => 3, | 895 | 998 | _ => 4, | 896 | | } | 897 | 1.27k | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::bytes_per_color Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::bytes_per_color Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::bytes_per_color <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::bytes_per_color Line | Count | Source | 892 | 195 | fn bytes_per_color(&self) -> usize { | 893 | 195 | match self.bmp_header_type { | 894 | 20 | BMPHeaderType::Core => 3, | 895 | 175 | _ => 4, | 896 | | } | 897 | 195 | } |
|
898 | | |
899 | 2.40k | fn read_palette(&mut self) -> ImageResult<()> { |
900 | | const MAX_PALETTE_SIZE: usize = 256; // Palette indices are u8. |
901 | | |
902 | 2.40k | let bytes_per_color = self.bytes_per_color(); |
903 | 2.40k | let palette_size = self.get_palette_size()?; |
904 | 2.27k | let max_length = MAX_PALETTE_SIZE * bytes_per_color; |
905 | | |
906 | 2.27k | let length = palette_size * bytes_per_color; |
907 | 2.27k | 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.27k | buf.resize(cmp::min(length, max_length), 0); |
913 | 2.27k | 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.23k | 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.20k | Ordering::Less => buf.resize(max_length, 0), |
923 | 22 | Ordering::Equal => (), |
924 | | } |
925 | | |
926 | 2.23k | let p: Vec<[u8; 3]> = (0..MAX_PALETTE_SIZE) |
927 | 570k | .map(|i| { |
928 | 570k | let b = buf[bytes_per_color * i]; |
929 | 570k | let g = buf[bytes_per_color * i + 1]; |
930 | 570k | let r = buf[bytes_per_color * i + 2]; |
931 | 570k | [r, g, b] |
932 | 570k | }) Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palette::{closure#0}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palette::{closure#0}<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palette::{closure#0}Line | Count | Source | 927 | 215k | .map(|i| { | 928 | 215k | let b = buf[bytes_per_color * i]; | 929 | 215k | let g = buf[bytes_per_color * i + 1]; | 930 | 215k | let r = buf[bytes_per_color * i + 2]; | 931 | 215k | [r, g, b] | 932 | 215k | }) |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palette::{closure#0}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palette::{closure#0}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palette::{closure#0}<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palette::{closure#0}Line | Count | Source | 927 | 306k | .map(|i| { | 928 | 306k | let b = buf[bytes_per_color * i]; | 929 | 306k | let g = buf[bytes_per_color * i + 1]; | 930 | 306k | let r = buf[bytes_per_color * i + 2]; | 931 | 306k | [r, g, b] | 932 | 306k | }) |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palette::{closure#0}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palette::{closure#0}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palette::{closure#0}<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palette::{closure#0}Line | Count | Source | 927 | 48.8k | .map(|i| { | 928 | 48.8k | let b = buf[bytes_per_color * i]; | 929 | 48.8k | let g = buf[bytes_per_color * i + 1]; | 930 | 48.8k | let r = buf[bytes_per_color * i + 2]; | 931 | 48.8k | [r, g, b] | 932 | 48.8k | }) |
|
933 | 2.23k | .collect(); |
934 | | |
935 | 2.23k | self.palette = Some(p); |
936 | | |
937 | 2.23k | Ok(()) |
938 | 2.40k | } Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palette Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palette <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palette Line | Count | Source | 899 | 931 | fn read_palette(&mut self) -> ImageResult<()> { | 900 | | const MAX_PALETTE_SIZE: usize = 256; // Palette indices are u8. | 901 | | | 902 | 931 | let bytes_per_color = self.bytes_per_color(); | 903 | 931 | let palette_size = self.get_palette_size()?; | 904 | 865 | let max_length = MAX_PALETTE_SIZE * bytes_per_color; | 905 | | | 906 | 865 | let length = palette_size * bytes_per_color; | 907 | 865 | 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 | 865 | buf.resize(cmp::min(length, max_length), 0); | 913 | 865 | 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 | 842 | match length.cmp(&max_length) { | 918 | | Ordering::Greater => { | 919 | 0 | self.reader | 920 | 0 | .seek(SeekFrom::Current((length - max_length) as i64))?; | 921 | | } | 922 | 831 | Ordering::Less => buf.resize(max_length, 0), | 923 | 11 | Ordering::Equal => (), | 924 | | } | 925 | | | 926 | 842 | let p: Vec<[u8; 3]> = (0..MAX_PALETTE_SIZE) | 927 | 842 | .map(|i| { | 928 | | let b = buf[bytes_per_color * i]; | 929 | | let g = buf[bytes_per_color * i + 1]; | 930 | | let r = buf[bytes_per_color * i + 2]; | 931 | | [r, g, b] | 932 | | }) | 933 | 842 | .collect(); | 934 | | | 935 | 842 | self.palette = Some(p); | 936 | | | 937 | 842 | Ok(()) | 938 | 931 | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palette Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palette Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palette <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palette Line | Count | Source | 899 | 1.27k | fn read_palette(&mut self) -> ImageResult<()> { | 900 | | const MAX_PALETTE_SIZE: usize = 256; // Palette indices are u8. | 901 | | | 902 | 1.27k | let bytes_per_color = self.bytes_per_color(); | 903 | 1.27k | let palette_size = self.get_palette_size()?; | 904 | 1.21k | let max_length = MAX_PALETTE_SIZE * bytes_per_color; | 905 | | | 906 | 1.21k | let length = palette_size * bytes_per_color; | 907 | 1.21k | 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 | 1.21k | buf.resize(cmp::min(length, max_length), 0); | 913 | 1.21k | 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 | 1.19k | match length.cmp(&max_length) { | 918 | | Ordering::Greater => { | 919 | 0 | self.reader | 920 | 0 | .seek(SeekFrom::Current((length - max_length) as i64))?; | 921 | | } | 922 | 1.18k | Ordering::Less => buf.resize(max_length, 0), | 923 | 10 | Ordering::Equal => (), | 924 | | } | 925 | | | 926 | 1.19k | let p: Vec<[u8; 3]> = (0..MAX_PALETTE_SIZE) | 927 | 1.19k | .map(|i| { | 928 | | let b = buf[bytes_per_color * i]; | 929 | | let g = buf[bytes_per_color * i + 1]; | 930 | | let r = buf[bytes_per_color * i + 2]; | 931 | | [r, g, b] | 932 | | }) | 933 | 1.19k | .collect(); | 934 | | | 935 | 1.19k | self.palette = Some(p); | 936 | | | 937 | 1.19k | Ok(()) | 938 | 1.27k | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palette Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palette Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palette <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palette Line | Count | Source | 899 | 195 | fn read_palette(&mut self) -> ImageResult<()> { | 900 | | const MAX_PALETTE_SIZE: usize = 256; // Palette indices are u8. | 901 | | | 902 | 195 | let bytes_per_color = self.bytes_per_color(); | 903 | 195 | let palette_size = self.get_palette_size()?; | 904 | 191 | let max_length = MAX_PALETTE_SIZE * bytes_per_color; | 905 | | | 906 | 191 | let length = palette_size * bytes_per_color; | 907 | 191 | 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 | 191 | buf.resize(cmp::min(length, max_length), 0); | 913 | 191 | 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 | 191 | match length.cmp(&max_length) { | 918 | | Ordering::Greater => { | 919 | 0 | self.reader | 920 | 0 | .seek(SeekFrom::Current((length - max_length) as i64))?; | 921 | | } | 922 | 190 | Ordering::Less => buf.resize(max_length, 0), | 923 | 1 | Ordering::Equal => (), | 924 | | } | 925 | | | 926 | 191 | let p: Vec<[u8; 3]> = (0..MAX_PALETTE_SIZE) | 927 | 191 | .map(|i| { | 928 | | let b = buf[bytes_per_color * i]; | 929 | | let g = buf[bytes_per_color * i + 1]; | 930 | | let r = buf[bytes_per_color * i + 2]; | 931 | | [r, g, b] | 932 | | }) | 933 | 191 | .collect(); | 934 | | | 935 | 191 | self.palette = Some(p); | 936 | | | 937 | 191 | Ok(()) | 938 | 195 | } |
|
939 | | |
940 | | /// Get the palette that is embedded in the BMP image, if any. |
941 | | pub fn get_palette(&self) -> Option<&[[u8; 3]]> { |
942 | | self.palette.as_ref().map(|vec| &vec[..]) |
943 | | } |
944 | | |
945 | 8.58k | fn num_channels(&self) -> usize { |
946 | 8.58k | if self.indexed_color { |
947 | 0 | 1 |
948 | 8.58k | } else if self.add_alpha_channel { |
949 | 4.93k | 4 |
950 | | } else { |
951 | 3.65k | 3 |
952 | | } |
953 | 8.58k | } Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::num_channels Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::num_channels <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::num_channels Line | Count | Source | 945 | 3.44k | fn num_channels(&self) -> usize { | 946 | 3.44k | if self.indexed_color { | 947 | 0 | 1 | 948 | 3.44k | } else if self.add_alpha_channel { | 949 | 148 | 4 | 950 | | } else { | 951 | 3.29k | 3 | 952 | | } | 953 | 3.44k | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::num_channels Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::num_channels Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::num_channels <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::num_channels Line | Count | Source | 945 | 4.53k | fn num_channels(&self) -> usize { | 946 | 4.53k | if self.indexed_color { | 947 | 0 | 1 | 948 | 4.53k | } else if self.add_alpha_channel { | 949 | 4.53k | 4 | 950 | | } else { | 951 | 0 | 3 | 952 | | } | 953 | 4.53k | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::num_channels Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::num_channels Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::num_channels <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::num_channels Line | Count | Source | 945 | 610 | fn num_channels(&self) -> usize { | 946 | 610 | if self.indexed_color { | 947 | 0 | 1 | 948 | 610 | } else if self.add_alpha_channel { | 949 | 246 | 4 | 950 | | } else { | 951 | 364 | 3 | 952 | | } | 953 | 610 | } |
|
954 | | |
955 | 1.34k | fn rows<'a>(&self, pixel_data: &'a mut [u8]) -> RowIterator<'a> { |
956 | 1.34k | let stride = self.width as usize * self.num_channels(); |
957 | 1.34k | if self.top_down { |
958 | 0 | RowIterator { |
959 | 0 | chunks: Chunker::FromTop(pixel_data.chunks_exact_mut(stride)), |
960 | 0 | } |
961 | | } else { |
962 | 1.34k | RowIterator { |
963 | 1.34k | chunks: Chunker::FromBottom(pixel_data.chunks_exact_mut(stride).rev()), |
964 | 1.34k | } |
965 | | } |
966 | 1.34k | } Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::rows Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::rows <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::rows Line | Count | Source | 955 | 456 | fn rows<'a>(&self, pixel_data: &'a mut [u8]) -> RowIterator<'a> { | 956 | 456 | let stride = self.width as usize * self.num_channels(); | 957 | 456 | if self.top_down { | 958 | 0 | RowIterator { | 959 | 0 | chunks: Chunker::FromTop(pixel_data.chunks_exact_mut(stride)), | 960 | 0 | } | 961 | | } else { | 962 | 456 | RowIterator { | 963 | 456 | chunks: Chunker::FromBottom(pixel_data.chunks_exact_mut(stride).rev()), | 964 | 456 | } | 965 | | } | 966 | 456 | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::rows Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::rows Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::rows <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::rows Line | Count | Source | 955 | 746 | fn rows<'a>(&self, pixel_data: &'a mut [u8]) -> RowIterator<'a> { | 956 | 746 | let stride = self.width as usize * self.num_channels(); | 957 | 746 | if self.top_down { | 958 | 0 | RowIterator { | 959 | 0 | chunks: Chunker::FromTop(pixel_data.chunks_exact_mut(stride)), | 960 | 0 | } | 961 | | } else { | 962 | 746 | RowIterator { | 963 | 746 | chunks: Chunker::FromBottom(pixel_data.chunks_exact_mut(stride).rev()), | 964 | 746 | } | 965 | | } | 966 | 746 | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::rows Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::rows Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::rows <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::rows Line | Count | Source | 955 | 143 | fn rows<'a>(&self, pixel_data: &'a mut [u8]) -> RowIterator<'a> { | 956 | 143 | let stride = self.width as usize * self.num_channels(); | 957 | 143 | if self.top_down { | 958 | 0 | RowIterator { | 959 | 0 | chunks: Chunker::FromTop(pixel_data.chunks_exact_mut(stride)), | 960 | 0 | } | 961 | | } else { | 962 | 143 | RowIterator { | 963 | 143 | chunks: Chunker::FromBottom(pixel_data.chunks_exact_mut(stride).rev()), | 964 | 143 | } | 965 | | } | 966 | 143 | } |
|
967 | | |
968 | 853 | fn read_palettized_pixel_data(&mut self, buf: &mut [u8]) -> ImageResult<()> { |
969 | 853 | let num_channels = self.num_channels(); |
970 | 853 | let row_byte_length = ((i32::from(self.bit_count) * self.width + 31) / 32 * 4) as usize; |
971 | 853 | let mut indices = vec![0; row_byte_length]; |
972 | 853 | let palette = self.palette.as_ref().unwrap(); |
973 | 853 | let bit_count = self.bit_count; |
974 | 853 | let reader = &mut self.reader; |
975 | 853 | let width = self.width as usize; |
976 | 853 | let skip_palette = self.indexed_color; |
977 | | |
978 | 853 | reader.seek(SeekFrom::Start(self.data_offset))?; |
979 | | |
980 | 853 | if num_channels == 4 { |
981 | 4.27G | buf.chunks_exact_mut(4).for_each(|c| c[3] = 0xFF); Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data::{closure#0}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data::{closure#0}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data::{closure#0}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data::{closure#0}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data::{closure#0}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data::{closure#0}<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data::{closure#0}Line | Count | Source | 981 | 4.20G | buf.chunks_exact_mut(4).for_each(|c| c[3] = 0xFF); |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data::{closure#0}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data::{closure#0}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data::{closure#0}<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data::{closure#0}Line | Count | Source | 981 | 70.4M | buf.chunks_exact_mut(4).for_each(|c| c[3] = 0xFF); |
|
982 | 426 | } |
983 | | |
984 | 853 | with_rows( |
985 | 853 | buf, |
986 | 853 | self.width, |
987 | 853 | self.height, |
988 | 853 | num_channels, |
989 | 853 | self.top_down, |
990 | 534k | |row| { |
991 | 534k | reader.read_exact(&mut indices)?; |
992 | 533k | if skip_palette { |
993 | 0 | row.clone_from_slice(&indices[0..width]); |
994 | 0 | } else { |
995 | 533k | let mut pixel_iter = row.chunks_exact_mut(num_channels); |
996 | 533k | match bit_count { |
997 | 497k | 1 => { |
998 | 497k | set_1bit_pixel_run(&mut pixel_iter, palette, indices.iter()); |
999 | 497k | } |
1000 | 3.95k | 2 => { |
1001 | 3.95k | set_2bit_pixel_run(&mut pixel_iter, palette, indices.iter(), width); |
1002 | 3.95k | } |
1003 | 30.4k | 4 => { |
1004 | 30.4k | set_4bit_pixel_run(&mut pixel_iter, palette, indices.iter(), width); |
1005 | 30.4k | } |
1006 | 1.15k | 8 => { |
1007 | 1.15k | set_8bit_pixel_run(&mut pixel_iter, palette, indices.iter(), width); |
1008 | 1.15k | } |
1009 | 0 | _ => panic!(), |
1010 | | } |
1011 | | } |
1012 | 533k | Ok(()) |
1013 | 534k | }, Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data::{closure#1}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data::{closure#1}<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data::{closure#1}Line | Count | Source | 990 | 332k | |row| { | 991 | 332k | reader.read_exact(&mut indices)?; | 992 | 332k | if skip_palette { | 993 | 0 | row.clone_from_slice(&indices[0..width]); | 994 | 0 | } else { | 995 | 332k | let mut pixel_iter = row.chunks_exact_mut(num_channels); | 996 | 332k | match bit_count { | 997 | 329k | 1 => { | 998 | 329k | set_1bit_pixel_run(&mut pixel_iter, palette, indices.iter()); | 999 | 329k | } | 1000 | 1.55k | 2 => { | 1001 | 1.55k | set_2bit_pixel_run(&mut pixel_iter, palette, indices.iter(), width); | 1002 | 1.55k | } | 1003 | 1.18k | 4 => { | 1004 | 1.18k | set_4bit_pixel_run(&mut pixel_iter, palette, indices.iter(), width); | 1005 | 1.18k | } | 1006 | 224 | 8 => { | 1007 | 224 | set_8bit_pixel_run(&mut pixel_iter, palette, indices.iter(), width); | 1008 | 224 | } | 1009 | 0 | _ => panic!(), | 1010 | | } | 1011 | | } | 1012 | 332k | Ok(()) | 1013 | 332k | }, |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data::{closure#1}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data::{closure#1}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data::{closure#1}<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data::{closure#1}Line | Count | Source | 990 | 197k | |row| { | 991 | 197k | reader.read_exact(&mut indices)?; | 992 | 197k | if skip_palette { | 993 | 0 | row.clone_from_slice(&indices[0..width]); | 994 | 0 | } else { | 995 | 197k | let mut pixel_iter = row.chunks_exact_mut(num_channels); | 996 | 197k | match bit_count { | 997 | 166k | 1 => { | 998 | 166k | set_1bit_pixel_run(&mut pixel_iter, palette, indices.iter()); | 999 | 166k | } | 1000 | 1.06k | 2 => { | 1001 | 1.06k | set_2bit_pixel_run(&mut pixel_iter, palette, indices.iter(), width); | 1002 | 1.06k | } | 1003 | 28.7k | 4 => { | 1004 | 28.7k | set_4bit_pixel_run(&mut pixel_iter, palette, indices.iter(), width); | 1005 | 28.7k | } | 1006 | 801 | 8 => { | 1007 | 801 | set_8bit_pixel_run(&mut pixel_iter, palette, indices.iter(), width); | 1008 | 801 | } | 1009 | 0 | _ => panic!(), | 1010 | | } | 1011 | | } | 1012 | 197k | Ok(()) | 1013 | 197k | }, |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data::{closure#1}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data::{closure#1}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data::{closure#1}<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data::{closure#1}Line | Count | Source | 990 | 3.83k | |row| { | 991 | 3.83k | reader.read_exact(&mut indices)?; | 992 | 3.78k | if skip_palette { | 993 | 0 | row.clone_from_slice(&indices[0..width]); | 994 | 0 | } else { | 995 | 3.78k | let mut pixel_iter = row.chunks_exact_mut(num_channels); | 996 | 3.78k | match bit_count { | 997 | 1.79k | 1 => { | 998 | 1.79k | set_1bit_pixel_run(&mut pixel_iter, palette, indices.iter()); | 999 | 1.79k | } | 1000 | 1.34k | 2 => { | 1001 | 1.34k | set_2bit_pixel_run(&mut pixel_iter, palette, indices.iter(), width); | 1002 | 1.34k | } | 1003 | 519 | 4 => { | 1004 | 519 | set_4bit_pixel_run(&mut pixel_iter, palette, indices.iter(), width); | 1005 | 519 | } | 1006 | 134 | 8 => { | 1007 | 134 | set_8bit_pixel_run(&mut pixel_iter, palette, indices.iter(), width); | 1008 | 134 | } | 1009 | 0 | _ => panic!(), | 1010 | | } | 1011 | | } | 1012 | 3.78k | Ok(()) | 1013 | 3.83k | }, |
|
1014 | 689 | )?; |
1015 | | |
1016 | 164 | Ok(()) |
1017 | 853 | } Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data Line | Count | Source | 968 | 381 | fn read_palettized_pixel_data(&mut self, buf: &mut [u8]) -> ImageResult<()> { | 969 | 381 | let num_channels = self.num_channels(); | 970 | 381 | let row_byte_length = ((i32::from(self.bit_count) * self.width + 31) / 32 * 4) as usize; | 971 | 381 | let mut indices = vec![0; row_byte_length]; | 972 | 381 | let palette = self.palette.as_ref().unwrap(); | 973 | 381 | let bit_count = self.bit_count; | 974 | 381 | let reader = &mut self.reader; | 975 | 381 | let width = self.width as usize; | 976 | 381 | let skip_palette = self.indexed_color; | 977 | | | 978 | 381 | reader.seek(SeekFrom::Start(self.data_offset))?; | 979 | | | 980 | 381 | if num_channels == 4 { | 981 | 0 | buf.chunks_exact_mut(4).for_each(|c| c[3] = 0xFF); | 982 | 381 | } | 983 | | | 984 | 381 | with_rows( | 985 | 381 | buf, | 986 | 381 | self.width, | 987 | 381 | self.height, | 988 | 381 | num_channels, | 989 | 381 | self.top_down, | 990 | | |row| { | 991 | | reader.read_exact(&mut indices)?; | 992 | | if skip_palette { | 993 | | row.clone_from_slice(&indices[0..width]); | 994 | | } else { | 995 | | let mut pixel_iter = row.chunks_exact_mut(num_channels); | 996 | | match bit_count { | 997 | | 1 => { | 998 | | set_1bit_pixel_run(&mut pixel_iter, palette, indices.iter()); | 999 | | } | 1000 | | 2 => { | 1001 | | set_2bit_pixel_run(&mut pixel_iter, palette, indices.iter(), width); | 1002 | | } | 1003 | | 4 => { | 1004 | | set_4bit_pixel_run(&mut pixel_iter, palette, indices.iter(), width); | 1005 | | } | 1006 | | 8 => { | 1007 | | set_8bit_pixel_run(&mut pixel_iter, palette, indices.iter(), width); | 1008 | | } | 1009 | | _ => panic!(), | 1010 | | } | 1011 | | } | 1012 | | Ok(()) | 1013 | | }, | 1014 | 326 | )?; | 1015 | | | 1016 | 55 | Ok(()) | 1017 | 381 | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data Line | Count | Source | 968 | 424 | fn read_palettized_pixel_data(&mut self, buf: &mut [u8]) -> ImageResult<()> { | 969 | 424 | let num_channels = self.num_channels(); | 970 | 424 | let row_byte_length = ((i32::from(self.bit_count) * self.width + 31) / 32 * 4) as usize; | 971 | 424 | let mut indices = vec![0; row_byte_length]; | 972 | 424 | let palette = self.palette.as_ref().unwrap(); | 973 | 424 | let bit_count = self.bit_count; | 974 | 424 | let reader = &mut self.reader; | 975 | 424 | let width = self.width as usize; | 976 | 424 | let skip_palette = self.indexed_color; | 977 | | | 978 | 424 | reader.seek(SeekFrom::Start(self.data_offset))?; | 979 | | | 980 | 424 | if num_channels == 4 { | 981 | 424 | buf.chunks_exact_mut(4).for_each(|c| c[3] = 0xFF); | 982 | 0 | } | 983 | | | 984 | 424 | with_rows( | 985 | 424 | buf, | 986 | 424 | self.width, | 987 | 424 | self.height, | 988 | 424 | num_channels, | 989 | 424 | self.top_down, | 990 | | |row| { | 991 | | reader.read_exact(&mut indices)?; | 992 | | if skip_palette { | 993 | | row.clone_from_slice(&indices[0..width]); | 994 | | } else { | 995 | | let mut pixel_iter = row.chunks_exact_mut(num_channels); | 996 | | match bit_count { | 997 | | 1 => { | 998 | | set_1bit_pixel_run(&mut pixel_iter, palette, indices.iter()); | 999 | | } | 1000 | | 2 => { | 1001 | | set_2bit_pixel_run(&mut pixel_iter, palette, indices.iter(), width); | 1002 | | } | 1003 | | 4 => { | 1004 | | set_4bit_pixel_run(&mut pixel_iter, palette, indices.iter(), width); | 1005 | | } | 1006 | | 8 => { | 1007 | | set_8bit_pixel_run(&mut pixel_iter, palette, indices.iter(), width); | 1008 | | } | 1009 | | _ => panic!(), | 1010 | | } | 1011 | | } | 1012 | | Ok(()) | 1013 | | }, | 1014 | 317 | )?; | 1015 | | | 1016 | 107 | Ok(()) | 1017 | 424 | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_palettized_pixel_data Line | Count | Source | 968 | 48 | fn read_palettized_pixel_data(&mut self, buf: &mut [u8]) -> ImageResult<()> { | 969 | 48 | let num_channels = self.num_channels(); | 970 | 48 | let row_byte_length = ((i32::from(self.bit_count) * self.width + 31) / 32 * 4) as usize; | 971 | 48 | let mut indices = vec![0; row_byte_length]; | 972 | 48 | let palette = self.palette.as_ref().unwrap(); | 973 | 48 | let bit_count = self.bit_count; | 974 | 48 | let reader = &mut self.reader; | 975 | 48 | let width = self.width as usize; | 976 | 48 | let skip_palette = self.indexed_color; | 977 | | | 978 | 48 | reader.seek(SeekFrom::Start(self.data_offset))?; | 979 | | | 980 | 48 | if num_channels == 4 { | 981 | 3 | buf.chunks_exact_mut(4).for_each(|c| c[3] = 0xFF); | 982 | 45 | } | 983 | | | 984 | 48 | with_rows( | 985 | 48 | buf, | 986 | 48 | self.width, | 987 | 48 | self.height, | 988 | 48 | num_channels, | 989 | 48 | self.top_down, | 990 | | |row| { | 991 | | reader.read_exact(&mut indices)?; | 992 | | if skip_palette { | 993 | | row.clone_from_slice(&indices[0..width]); | 994 | | } else { | 995 | | let mut pixel_iter = row.chunks_exact_mut(num_channels); | 996 | | match bit_count { | 997 | | 1 => { | 998 | | set_1bit_pixel_run(&mut pixel_iter, palette, indices.iter()); | 999 | | } | 1000 | | 2 => { | 1001 | | set_2bit_pixel_run(&mut pixel_iter, palette, indices.iter(), width); | 1002 | | } | 1003 | | 4 => { | 1004 | | set_4bit_pixel_run(&mut pixel_iter, palette, indices.iter(), width); | 1005 | | } | 1006 | | 8 => { | 1007 | | set_8bit_pixel_run(&mut pixel_iter, palette, indices.iter(), width); | 1008 | | } | 1009 | | _ => panic!(), | 1010 | | } | 1011 | | } | 1012 | | Ok(()) | 1013 | | }, | 1014 | 46 | )?; | 1015 | | | 1016 | 2 | Ok(()) | 1017 | 48 | } |
|
1018 | | |
1019 | 311 | fn read_16_bit_pixel_data( |
1020 | 311 | &mut self, |
1021 | 311 | buf: &mut [u8], |
1022 | 311 | bitfields: Option<&Bitfields>, |
1023 | 311 | ) -> ImageResult<()> { |
1024 | 311 | let num_channels = self.num_channels(); |
1025 | 311 | let row_padding_len = self.width as usize % 2 * 2; |
1026 | 311 | let row_padding = &mut [0; 2][..row_padding_len]; |
1027 | 311 | let bitfields = match bitfields { |
1028 | 184 | Some(b) => b, |
1029 | 127 | None => self.bitfields.as_ref().unwrap(), |
1030 | | }; |
1031 | 311 | let reader = &mut self.reader; |
1032 | | |
1033 | 311 | reader.seek(SeekFrom::Start(self.data_offset))?; |
1034 | | |
1035 | 311 | with_rows( |
1036 | 311 | buf, |
1037 | 311 | self.width, |
1038 | 311 | self.height, |
1039 | 311 | num_channels, |
1040 | 311 | self.top_down, |
1041 | 1.11M | |row| { |
1042 | 1.54M | for pixel in row.chunks_mut(num_channels) { |
1043 | 1.54M | let data = u32::from(reader.read_u16::<LittleEndian>()?); |
1044 | | |
1045 | 1.54M | pixel[0] = bitfields.r.read(data); |
1046 | 1.54M | pixel[1] = bitfields.g.read(data); |
1047 | 1.54M | pixel[2] = bitfields.b.read(data); |
1048 | 1.54M | if num_channels == 4 { |
1049 | 672k | if bitfields.a.len != 0 { |
1050 | 284k | pixel[3] = bitfields.a.read(data); |
1051 | 387k | } else { |
1052 | 387k | pixel[3] = 0xFF; |
1053 | 387k | } |
1054 | 876k | } |
1055 | | } |
1056 | 1.11M | reader.read_exact(row_padding) |
1057 | 1.11M | }, Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_16_bit_pixel_data::{closure#0}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_16_bit_pixel_data::{closure#0}<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_16_bit_pixel_data::{closure#0}Line | Count | Source | 1041 | 925k | |row| { | 1042 | 1.15M | for pixel in row.chunks_mut(num_channels) { | 1043 | 1.15M | let data = u32::from(reader.read_u16::<LittleEndian>()?); | 1044 | | | 1045 | 1.15M | pixel[0] = bitfields.r.read(data); | 1046 | 1.15M | pixel[1] = bitfields.g.read(data); | 1047 | 1.15M | pixel[2] = bitfields.b.read(data); | 1048 | 1.15M | if num_channels == 4 { | 1049 | 281k | if bitfields.a.len != 0 { | 1050 | 281k | pixel[3] = bitfields.a.read(data); | 1051 | 281k | } else { | 1052 | 0 | pixel[3] = 0xFF; | 1053 | 0 | } | 1054 | 875k | } | 1055 | | } | 1056 | 925k | reader.read_exact(row_padding) | 1057 | 925k | }, |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_16_bit_pixel_data::{closure#0}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_16_bit_pixel_data::{closure#0}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_16_bit_pixel_data::{closure#0}<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_16_bit_pixel_data::{closure#0}Line | Count | Source | 1041 | 185k | |row| { | 1042 | 386k | for pixel in row.chunks_mut(num_channels) { | 1043 | 386k | let data = u32::from(reader.read_u16::<LittleEndian>()?); | 1044 | | | 1045 | 386k | pixel[0] = bitfields.r.read(data); | 1046 | 386k | pixel[1] = bitfields.g.read(data); | 1047 | 386k | pixel[2] = bitfields.b.read(data); | 1048 | 386k | if num_channels == 4 { | 1049 | 386k | if bitfields.a.len != 0 { | 1050 | 3.28k | pixel[3] = bitfields.a.read(data); | 1051 | 382k | } else { | 1052 | 382k | pixel[3] = 0xFF; | 1053 | 382k | } | 1054 | 0 | } | 1055 | | } | 1056 | 185k | reader.read_exact(row_padding) | 1057 | 185k | }, |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_16_bit_pixel_data::{closure#0}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_16_bit_pixel_data::{closure#0}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_16_bit_pixel_data::{closure#0}<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_16_bit_pixel_data::{closure#0}Line | Count | Source | 1041 | 1.07k | |row| { | 1042 | 5.94k | for pixel in row.chunks_mut(num_channels) { | 1043 | 5.94k | let data = u32::from(reader.read_u16::<LittleEndian>()?); | 1044 | | | 1045 | 5.93k | pixel[0] = bitfields.r.read(data); | 1046 | 5.93k | pixel[1] = bitfields.g.read(data); | 1047 | 5.93k | pixel[2] = bitfields.b.read(data); | 1048 | 5.93k | if num_channels == 4 { | 1049 | 4.91k | if bitfields.a.len != 0 { | 1050 | 174 | pixel[3] = bitfields.a.read(data); | 1051 | 4.73k | } else { | 1052 | 4.73k | pixel[3] = 0xFF; | 1053 | 4.73k | } | 1054 | 1.02k | } | 1055 | | } | 1056 | 1.06k | reader.read_exact(row_padding) | 1057 | 1.07k | }, |
|
1058 | 271 | )?; |
1059 | | |
1060 | 40 | Ok(()) |
1061 | 311 | } Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_16_bit_pixel_data Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_16_bit_pixel_data <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_16_bit_pixel_data Line | Count | Source | 1019 | 126 | fn read_16_bit_pixel_data( | 1020 | 126 | &mut self, | 1021 | 126 | buf: &mut [u8], | 1022 | 126 | bitfields: Option<&Bitfields>, | 1023 | 126 | ) -> ImageResult<()> { | 1024 | 126 | let num_channels = self.num_channels(); | 1025 | 126 | let row_padding_len = self.width as usize % 2 * 2; | 1026 | 126 | let row_padding = &mut [0; 2][..row_padding_len]; | 1027 | 126 | let bitfields = match bitfields { | 1028 | 70 | Some(b) => b, | 1029 | 56 | None => self.bitfields.as_ref().unwrap(), | 1030 | | }; | 1031 | 126 | let reader = &mut self.reader; | 1032 | | | 1033 | 126 | reader.seek(SeekFrom::Start(self.data_offset))?; | 1034 | | | 1035 | 126 | with_rows( | 1036 | 126 | buf, | 1037 | 126 | self.width, | 1038 | 126 | self.height, | 1039 | 126 | num_channels, | 1040 | 126 | self.top_down, | 1041 | | |row| { | 1042 | | for pixel in row.chunks_mut(num_channels) { | 1043 | | let data = u32::from(reader.read_u16::<LittleEndian>()?); | 1044 | | | 1045 | | pixel[0] = bitfields.r.read(data); | 1046 | | pixel[1] = bitfields.g.read(data); | 1047 | | pixel[2] = bitfields.b.read(data); | 1048 | | if num_channels == 4 { | 1049 | | if bitfields.a.len != 0 { | 1050 | | pixel[3] = bitfields.a.read(data); | 1051 | | } else { | 1052 | | pixel[3] = 0xFF; | 1053 | | } | 1054 | | } | 1055 | | } | 1056 | | reader.read_exact(row_padding) | 1057 | | }, | 1058 | 100 | )?; | 1059 | | | 1060 | 26 | Ok(()) | 1061 | 126 | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_16_bit_pixel_data Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_16_bit_pixel_data Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_16_bit_pixel_data <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_16_bit_pixel_data Line | Count | Source | 1019 | 172 | fn read_16_bit_pixel_data( | 1020 | 172 | &mut self, | 1021 | 172 | buf: &mut [u8], | 1022 | 172 | bitfields: Option<&Bitfields>, | 1023 | 172 | ) -> ImageResult<()> { | 1024 | 172 | let num_channels = self.num_channels(); | 1025 | 172 | let row_padding_len = self.width as usize % 2 * 2; | 1026 | 172 | let row_padding = &mut [0; 2][..row_padding_len]; | 1027 | 172 | let bitfields = match bitfields { | 1028 | 106 | Some(b) => b, | 1029 | 66 | None => self.bitfields.as_ref().unwrap(), | 1030 | | }; | 1031 | 172 | let reader = &mut self.reader; | 1032 | | | 1033 | 172 | reader.seek(SeekFrom::Start(self.data_offset))?; | 1034 | | | 1035 | 172 | with_rows( | 1036 | 172 | buf, | 1037 | 172 | self.width, | 1038 | 172 | self.height, | 1039 | 172 | num_channels, | 1040 | 172 | self.top_down, | 1041 | | |row| { | 1042 | | for pixel in row.chunks_mut(num_channels) { | 1043 | | let data = u32::from(reader.read_u16::<LittleEndian>()?); | 1044 | | | 1045 | | pixel[0] = bitfields.r.read(data); | 1046 | | pixel[1] = bitfields.g.read(data); | 1047 | | pixel[2] = bitfields.b.read(data); | 1048 | | if num_channels == 4 { | 1049 | | if bitfields.a.len != 0 { | 1050 | | pixel[3] = bitfields.a.read(data); | 1051 | | } else { | 1052 | | pixel[3] = 0xFF; | 1053 | | } | 1054 | | } | 1055 | | } | 1056 | | reader.read_exact(row_padding) | 1057 | | }, | 1058 | 160 | )?; | 1059 | | | 1060 | 12 | Ok(()) | 1061 | 172 | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_16_bit_pixel_data Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_16_bit_pixel_data Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_16_bit_pixel_data <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_16_bit_pixel_data Line | Count | Source | 1019 | 13 | fn read_16_bit_pixel_data( | 1020 | 13 | &mut self, | 1021 | 13 | buf: &mut [u8], | 1022 | 13 | bitfields: Option<&Bitfields>, | 1023 | 13 | ) -> ImageResult<()> { | 1024 | 13 | let num_channels = self.num_channels(); | 1025 | 13 | let row_padding_len = self.width as usize % 2 * 2; | 1026 | 13 | let row_padding = &mut [0; 2][..row_padding_len]; | 1027 | 13 | let bitfields = match bitfields { | 1028 | 8 | Some(b) => b, | 1029 | 5 | None => self.bitfields.as_ref().unwrap(), | 1030 | | }; | 1031 | 13 | let reader = &mut self.reader; | 1032 | | | 1033 | 13 | reader.seek(SeekFrom::Start(self.data_offset))?; | 1034 | | | 1035 | 13 | with_rows( | 1036 | 13 | buf, | 1037 | 13 | self.width, | 1038 | 13 | self.height, | 1039 | 13 | num_channels, | 1040 | 13 | self.top_down, | 1041 | | |row| { | 1042 | | for pixel in row.chunks_mut(num_channels) { | 1043 | | let data = u32::from(reader.read_u16::<LittleEndian>()?); | 1044 | | | 1045 | | pixel[0] = bitfields.r.read(data); | 1046 | | pixel[1] = bitfields.g.read(data); | 1047 | | pixel[2] = bitfields.b.read(data); | 1048 | | if num_channels == 4 { | 1049 | | if bitfields.a.len != 0 { | 1050 | | pixel[3] = bitfields.a.read(data); | 1051 | | } else { | 1052 | | pixel[3] = 0xFF; | 1053 | | } | 1054 | | } | 1055 | | } | 1056 | | reader.read_exact(row_padding) | 1057 | | }, | 1058 | 11 | )?; | 1059 | | | 1060 | 2 | Ok(()) | 1061 | 13 | } |
|
1062 | | |
1063 | | /// Read image data from a reader in 32-bit formats that use bitfields. |
1064 | 288 | fn read_32_bit_pixel_data(&mut self, buf: &mut [u8]) -> ImageResult<()> { |
1065 | 288 | let num_channels = self.num_channels(); |
1066 | | |
1067 | 288 | let bitfields = self.bitfields.as_ref().unwrap(); |
1068 | | |
1069 | 288 | let reader = &mut self.reader; |
1070 | 288 | reader.seek(SeekFrom::Start(self.data_offset))?; |
1071 | | |
1072 | 288 | with_rows( |
1073 | 288 | buf, |
1074 | 288 | self.width, |
1075 | 288 | self.height, |
1076 | 288 | num_channels, |
1077 | 288 | self.top_down, |
1078 | 316k | |row| { |
1079 | 863k | for pixel in row.chunks_mut(num_channels) { |
1080 | 863k | let data = reader.read_u32::<LittleEndian>()?; |
1081 | | |
1082 | 862k | pixel[0] = bitfields.r.read(data); |
1083 | 862k | pixel[1] = bitfields.g.read(data); |
1084 | 862k | pixel[2] = bitfields.b.read(data); |
1085 | 862k | if num_channels == 4 { |
1086 | 483k | if bitfields.a.len != 0 { |
1087 | 438k | pixel[3] = bitfields.a.read(data); |
1088 | 438k | } else { |
1089 | 45.0k | pixel[3] = 0xff; |
1090 | 45.0k | } |
1091 | 379k | } |
1092 | | } |
1093 | 316k | Ok(()) |
1094 | 316k | }, Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_32_bit_pixel_data::{closure#0}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_32_bit_pixel_data::{closure#0}<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_32_bit_pixel_data::{closure#0}Line | Count | Source | 1078 | 286k | |row| { | 1079 | 799k | for pixel in row.chunks_mut(num_channels) { | 1080 | 799k | let data = reader.read_u32::<LittleEndian>()?; | 1081 | | | 1082 | 799k | pixel[0] = bitfields.r.read(data); | 1083 | 799k | pixel[1] = bitfields.g.read(data); | 1084 | 799k | pixel[2] = bitfields.b.read(data); | 1085 | 799k | if num_channels == 4 { | 1086 | 436k | if bitfields.a.len != 0 { | 1087 | 436k | pixel[3] = bitfields.a.read(data); | 1088 | 436k | } else { | 1089 | 0 | pixel[3] = 0xff; | 1090 | 0 | } | 1091 | 363k | } | 1092 | | } | 1093 | 286k | Ok(()) | 1094 | 286k | }, |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_32_bit_pixel_data::{closure#0}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_32_bit_pixel_data::{closure#0}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_32_bit_pixel_data::{closure#0}<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_32_bit_pixel_data::{closure#0}Line | Count | Source | 1078 | 13.0k | |row| { | 1079 | 45.6k | for pixel in row.chunks_mut(num_channels) { | 1080 | 45.6k | let data = reader.read_u32::<LittleEndian>()?; | 1081 | | | 1082 | 45.5k | pixel[0] = bitfields.r.read(data); | 1083 | 45.5k | pixel[1] = bitfields.g.read(data); | 1084 | 45.5k | pixel[2] = bitfields.b.read(data); | 1085 | 45.5k | if num_channels == 4 { | 1086 | 45.5k | if bitfields.a.len != 0 { | 1087 | 1.24k | pixel[3] = bitfields.a.read(data); | 1088 | 44.3k | } else { | 1089 | 44.3k | pixel[3] = 0xff; | 1090 | 44.3k | } | 1091 | 0 | } | 1092 | | } | 1093 | 12.9k | Ok(()) | 1094 | 13.0k | }, |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_32_bit_pixel_data::{closure#0}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_32_bit_pixel_data::{closure#0}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_32_bit_pixel_data::{closure#0}<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_32_bit_pixel_data::{closure#0}Line | Count | Source | 1078 | 16.7k | |row| { | 1079 | 17.6k | for pixel in row.chunks_mut(num_channels) { | 1080 | 17.6k | let data = reader.read_u32::<LittleEndian>()?; | 1081 | | | 1082 | 17.6k | pixel[0] = bitfields.r.read(data); | 1083 | 17.6k | pixel[1] = bitfields.g.read(data); | 1084 | 17.6k | pixel[2] = bitfields.b.read(data); | 1085 | 17.6k | if num_channels == 4 { | 1086 | 1.08k | if bitfields.a.len != 0 { | 1087 | 383 | pixel[3] = bitfields.a.read(data); | 1088 | 706 | } else { | 1089 | 706 | pixel[3] = 0xff; | 1090 | 706 | } | 1091 | 16.5k | } | 1092 | | } | 1093 | 16.7k | Ok(()) | 1094 | 16.7k | }, |
|
1095 | 266 | )?; |
1096 | | |
1097 | 22 | Ok(()) |
1098 | 288 | } Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_32_bit_pixel_data Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_32_bit_pixel_data <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_32_bit_pixel_data Line | Count | Source | 1064 | 129 | fn read_32_bit_pixel_data(&mut self, buf: &mut [u8]) -> ImageResult<()> { | 1065 | 129 | let num_channels = self.num_channels(); | 1066 | | | 1067 | 129 | let bitfields = self.bitfields.as_ref().unwrap(); | 1068 | | | 1069 | 129 | let reader = &mut self.reader; | 1070 | 129 | reader.seek(SeekFrom::Start(self.data_offset))?; | 1071 | | | 1072 | 129 | with_rows( | 1073 | 129 | buf, | 1074 | 129 | self.width, | 1075 | 129 | self.height, | 1076 | 129 | num_channels, | 1077 | 129 | self.top_down, | 1078 | | |row| { | 1079 | | for pixel in row.chunks_mut(num_channels) { | 1080 | | let data = reader.read_u32::<LittleEndian>()?; | 1081 | | | 1082 | | pixel[0] = bitfields.r.read(data); | 1083 | | pixel[1] = bitfields.g.read(data); | 1084 | | pixel[2] = bitfields.b.read(data); | 1085 | | if num_channels == 4 { | 1086 | | if bitfields.a.len != 0 { | 1087 | | pixel[3] = bitfields.a.read(data); | 1088 | | } else { | 1089 | | pixel[3] = 0xff; | 1090 | | } | 1091 | | } | 1092 | | } | 1093 | | Ok(()) | 1094 | | }, | 1095 | 124 | )?; | 1096 | | | 1097 | 5 | Ok(()) | 1098 | 129 | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_32_bit_pixel_data Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_32_bit_pixel_data Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_32_bit_pixel_data <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_32_bit_pixel_data Line | Count | Source | 1064 | 148 | fn read_32_bit_pixel_data(&mut self, buf: &mut [u8]) -> ImageResult<()> { | 1065 | 148 | let num_channels = self.num_channels(); | 1066 | | | 1067 | 148 | let bitfields = self.bitfields.as_ref().unwrap(); | 1068 | | | 1069 | 148 | let reader = &mut self.reader; | 1070 | 148 | reader.seek(SeekFrom::Start(self.data_offset))?; | 1071 | | | 1072 | 148 | with_rows( | 1073 | 148 | buf, | 1074 | 148 | self.width, | 1075 | 148 | self.height, | 1076 | 148 | num_channels, | 1077 | 148 | self.top_down, | 1078 | | |row| { | 1079 | | for pixel in row.chunks_mut(num_channels) { | 1080 | | let data = reader.read_u32::<LittleEndian>()?; | 1081 | | | 1082 | | pixel[0] = bitfields.r.read(data); | 1083 | | pixel[1] = bitfields.g.read(data); | 1084 | | pixel[2] = bitfields.b.read(data); | 1085 | | if num_channels == 4 { | 1086 | | if bitfields.a.len != 0 { | 1087 | | pixel[3] = bitfields.a.read(data); | 1088 | | } else { | 1089 | | pixel[3] = 0xff; | 1090 | | } | 1091 | | } | 1092 | | } | 1093 | | Ok(()) | 1094 | | }, | 1095 | 132 | )?; | 1096 | | | 1097 | 16 | Ok(()) | 1098 | 148 | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_32_bit_pixel_data Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_32_bit_pixel_data Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_32_bit_pixel_data <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_32_bit_pixel_data Line | Count | Source | 1064 | 11 | fn read_32_bit_pixel_data(&mut self, buf: &mut [u8]) -> ImageResult<()> { | 1065 | 11 | let num_channels = self.num_channels(); | 1066 | | | 1067 | 11 | let bitfields = self.bitfields.as_ref().unwrap(); | 1068 | | | 1069 | 11 | let reader = &mut self.reader; | 1070 | 11 | reader.seek(SeekFrom::Start(self.data_offset))?; | 1071 | | | 1072 | 11 | with_rows( | 1073 | 11 | buf, | 1074 | 11 | self.width, | 1075 | 11 | self.height, | 1076 | 11 | num_channels, | 1077 | 11 | self.top_down, | 1078 | | |row| { | 1079 | | for pixel in row.chunks_mut(num_channels) { | 1080 | | let data = reader.read_u32::<LittleEndian>()?; | 1081 | | | 1082 | | pixel[0] = bitfields.r.read(data); | 1083 | | pixel[1] = bitfields.g.read(data); | 1084 | | pixel[2] = bitfields.b.read(data); | 1085 | | if num_channels == 4 { | 1086 | | if bitfields.a.len != 0 { | 1087 | | pixel[3] = bitfields.a.read(data); | 1088 | | } else { | 1089 | | pixel[3] = 0xff; | 1090 | | } | 1091 | | } | 1092 | | } | 1093 | | Ok(()) | 1094 | | }, | 1095 | 10 | )?; | 1096 | | | 1097 | 1 | Ok(()) | 1098 | 11 | } |
|
1099 | | |
1100 | | /// Read image data from a reader where the colours are stored as 8-bit values (24 or 32-bit). |
1101 | 404 | fn read_full_byte_pixel_data( |
1102 | 404 | &mut self, |
1103 | 404 | buf: &mut [u8], |
1104 | 404 | format: &FormatFullBytes, |
1105 | 404 | ) -> ImageResult<()> { |
1106 | 404 | let num_channels = self.num_channels(); |
1107 | 404 | let row_padding_len = match *format { |
1108 | 192 | FormatFullBytes::RGB24 => (4 - (self.width as usize * 3) % 4) % 4, |
1109 | 212 | _ => 0, |
1110 | | }; |
1111 | 404 | let row_padding = &mut [0; 4][..row_padding_len]; |
1112 | | |
1113 | 404 | self.reader.seek(SeekFrom::Start(self.data_offset))?; |
1114 | | |
1115 | 404 | let reader = &mut self.reader; |
1116 | | |
1117 | 404 | with_rows( |
1118 | 404 | buf, |
1119 | 404 | self.width, |
1120 | 404 | self.height, |
1121 | 404 | num_channels, |
1122 | 404 | self.top_down, |
1123 | 2.33M | |row| { |
1124 | 4.29M | for pixel in row.chunks_mut(num_channels) { |
1125 | 4.29M | if *format == FormatFullBytes::Format888 { |
1126 | 1.21M | reader.read_u8()?; |
1127 | 3.07M | } |
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 | 4.29M | reader.read_exact(&mut pixel[0..3])?; |
1133 | 4.29M | pixel[0..3].reverse(); |
1134 | | |
1135 | 4.29M | if *format == FormatFullBytes::RGB32 { |
1136 | 1.75M | reader.read_u8()?; |
1137 | 2.54M | } |
1138 | | |
1139 | | // Read the alpha channel if present |
1140 | 4.29M | if *format == FormatFullBytes::RGBA32 { |
1141 | 1.29M | reader.read_exact(&mut pixel[3..4])?; |
1142 | 2.99M | } else if num_channels == 4 { |
1143 | 418k | pixel[3] = 0xFF; |
1144 | 2.58M | } |
1145 | | } |
1146 | 2.33M | reader.read_exact(row_padding) |
1147 | 2.33M | }, Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_full_byte_pixel_data::{closure#0}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_full_byte_pixel_data::{closure#0}<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_full_byte_pixel_data::{closure#0}Line | Count | Source | 1123 | 1.99M | |row| { | 1124 | 3.61M | for pixel in row.chunks_mut(num_channels) { | 1125 | 3.61M | if *format == FormatFullBytes::Format888 { | 1126 | 799k | reader.read_u8()?; | 1127 | 2.81M | } | 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 | 3.61M | reader.read_exact(&mut pixel[0..3])?; | 1133 | 3.61M | pixel[0..3].reverse(); | 1134 | | | 1135 | 3.61M | if *format == FormatFullBytes::RGB32 { | 1136 | 1.74M | reader.read_u8()?; | 1137 | 1.86M | } | 1138 | | | 1139 | | // Read the alpha channel if present | 1140 | 3.61M | if *format == FormatFullBytes::RGBA32 { | 1141 | 1.03M | reader.read_exact(&mut pixel[3..4])?; | 1142 | 2.57M | } else if num_channels == 4 { | 1143 | 0 | pixel[3] = 0xFF; | 1144 | 2.57M | } | 1145 | | } | 1146 | 1.99M | reader.read_exact(row_padding) | 1147 | 1.99M | }, |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_full_byte_pixel_data::{closure#0}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_full_byte_pixel_data::{closure#0}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_full_byte_pixel_data::{closure#0}<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_full_byte_pixel_data::{closure#0}Line | Count | Source | 1123 | 338k | |row| { | 1124 | 677k | for pixel in row.chunks_mut(num_channels) { | 1125 | 677k | if *format == FormatFullBytes::Format888 { | 1126 | 416k | reader.read_u8()?; | 1127 | 261k | } | 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 | 677k | reader.read_exact(&mut pixel[0..3])?; | 1133 | 677k | pixel[0..3].reverse(); | 1134 | | | 1135 | 677k | if *format == FormatFullBytes::RGB32 { | 1136 | 0 | reader.read_u8()?; | 1137 | 677k | } | 1138 | | | 1139 | | // Read the alpha channel if present | 1140 | 677k | if *format == FormatFullBytes::RGBA32 { | 1141 | 259k | reader.read_exact(&mut pixel[3..4])?; | 1142 | 418k | } else if num_channels == 4 { | 1143 | 418k | pixel[3] = 0xFF; | 1144 | 418k | } | 1145 | | } | 1146 | 338k | reader.read_exact(row_padding) | 1147 | 338k | }, |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_full_byte_pixel_data::{closure#0}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_full_byte_pixel_data::{closure#0}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_full_byte_pixel_data::{closure#0}<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_full_byte_pixel_data::{closure#0}Line | Count | Source | 1123 | 1.62k | |row| { | 1124 | 4.08k | for pixel in row.chunks_mut(num_channels) { | 1125 | 4.08k | if *format == FormatFullBytes::Format888 { | 1126 | 129 | reader.read_u8()?; | 1127 | 3.95k | } | 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 | 4.08k | reader.read_exact(&mut pixel[0..3])?; | 1133 | 4.07k | pixel[0..3].reverse(); | 1134 | | | 1135 | 4.07k | if *format == FormatFullBytes::RGB32 { | 1136 | 1.97k | reader.read_u8()?; | 1137 | 2.09k | } | 1138 | | | 1139 | | // Read the alpha channel if present | 1140 | 4.07k | if *format == FormatFullBytes::RGBA32 { | 1141 | 274 | reader.read_exact(&mut pixel[3..4])?; | 1142 | 3.80k | } else if num_channels == 4 { | 1143 | 162 | pixel[3] = 0xFF; | 1144 | 3.64k | } | 1145 | | } | 1146 | 1.60k | reader.read_exact(row_padding) | 1147 | 1.62k | }, |
|
1148 | 345 | )?; |
1149 | | |
1150 | 59 | Ok(()) |
1151 | 404 | } Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_full_byte_pixel_data Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_full_byte_pixel_data <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_full_byte_pixel_data Line | Count | Source | 1101 | 197 | fn read_full_byte_pixel_data( | 1102 | 197 | &mut self, | 1103 | 197 | buf: &mut [u8], | 1104 | 197 | format: &FormatFullBytes, | 1105 | 197 | ) -> ImageResult<()> { | 1106 | 197 | let num_channels = self.num_channels(); | 1107 | 197 | let row_padding_len = match *format { | 1108 | 72 | FormatFullBytes::RGB24 => (4 - (self.width as usize * 3) % 4) % 4, | 1109 | 125 | _ => 0, | 1110 | | }; | 1111 | 197 | let row_padding = &mut [0; 4][..row_padding_len]; | 1112 | | | 1113 | 197 | self.reader.seek(SeekFrom::Start(self.data_offset))?; | 1114 | | | 1115 | 197 | let reader = &mut self.reader; | 1116 | | | 1117 | 197 | with_rows( | 1118 | 197 | buf, | 1119 | 197 | self.width, | 1120 | 197 | self.height, | 1121 | 197 | num_channels, | 1122 | 197 | self.top_down, | 1123 | | |row| { | 1124 | | for pixel in row.chunks_mut(num_channels) { | 1125 | | if *format == FormatFullBytes::Format888 { | 1126 | | reader.read_u8()?; | 1127 | | } | 1128 | | | 1129 | | // 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 | | reader.read_exact(&mut pixel[0..3])?; | 1133 | | pixel[0..3].reverse(); | 1134 | | | 1135 | | if *format == FormatFullBytes::RGB32 { | 1136 | | reader.read_u8()?; | 1137 | | } | 1138 | | | 1139 | | // Read the alpha channel if present | 1140 | | if *format == FormatFullBytes::RGBA32 { | 1141 | | reader.read_exact(&mut pixel[3..4])?; | 1142 | | } else if num_channels == 4 { | 1143 | | pixel[3] = 0xFF; | 1144 | | } | 1145 | | } | 1146 | | reader.read_exact(row_padding) | 1147 | | }, | 1148 | 182 | )?; | 1149 | | | 1150 | 15 | Ok(()) | 1151 | 197 | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_full_byte_pixel_data Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_full_byte_pixel_data Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_full_byte_pixel_data <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_full_byte_pixel_data Line | Count | Source | 1101 | 192 | fn read_full_byte_pixel_data( | 1102 | 192 | &mut self, | 1103 | 192 | buf: &mut [u8], | 1104 | 192 | format: &FormatFullBytes, | 1105 | 192 | ) -> ImageResult<()> { | 1106 | 192 | let num_channels = self.num_channels(); | 1107 | 192 | let row_padding_len = match *format { | 1108 | 113 | FormatFullBytes::RGB24 => (4 - (self.width as usize * 3) % 4) % 4, | 1109 | 79 | _ => 0, | 1110 | | }; | 1111 | 192 | let row_padding = &mut [0; 4][..row_padding_len]; | 1112 | | | 1113 | 192 | self.reader.seek(SeekFrom::Start(self.data_offset))?; | 1114 | | | 1115 | 192 | let reader = &mut self.reader; | 1116 | | | 1117 | 192 | with_rows( | 1118 | 192 | buf, | 1119 | 192 | self.width, | 1120 | 192 | self.height, | 1121 | 192 | num_channels, | 1122 | 192 | self.top_down, | 1123 | | |row| { | 1124 | | for pixel in row.chunks_mut(num_channels) { | 1125 | | if *format == FormatFullBytes::Format888 { | 1126 | | reader.read_u8()?; | 1127 | | } | 1128 | | | 1129 | | // 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 | | reader.read_exact(&mut pixel[0..3])?; | 1133 | | pixel[0..3].reverse(); | 1134 | | | 1135 | | if *format == FormatFullBytes::RGB32 { | 1136 | | reader.read_u8()?; | 1137 | | } | 1138 | | | 1139 | | // Read the alpha channel if present | 1140 | | if *format == FormatFullBytes::RGBA32 { | 1141 | | reader.read_exact(&mut pixel[3..4])?; | 1142 | | } else if num_channels == 4 { | 1143 | | pixel[3] = 0xFF; | 1144 | | } | 1145 | | } | 1146 | | reader.read_exact(row_padding) | 1147 | | }, | 1148 | 150 | )?; | 1149 | | | 1150 | 42 | Ok(()) | 1151 | 192 | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_full_byte_pixel_data Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_full_byte_pixel_data Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_full_byte_pixel_data <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_full_byte_pixel_data Line | Count | Source | 1101 | 15 | fn read_full_byte_pixel_data( | 1102 | 15 | &mut self, | 1103 | 15 | buf: &mut [u8], | 1104 | 15 | format: &FormatFullBytes, | 1105 | 15 | ) -> ImageResult<()> { | 1106 | 15 | let num_channels = self.num_channels(); | 1107 | 15 | let row_padding_len = match *format { | 1108 | 7 | FormatFullBytes::RGB24 => (4 - (self.width as usize * 3) % 4) % 4, | 1109 | 8 | _ => 0, | 1110 | | }; | 1111 | 15 | let row_padding = &mut [0; 4][..row_padding_len]; | 1112 | | | 1113 | 15 | self.reader.seek(SeekFrom::Start(self.data_offset))?; | 1114 | | | 1115 | 15 | let reader = &mut self.reader; | 1116 | | | 1117 | 15 | with_rows( | 1118 | 15 | buf, | 1119 | 15 | self.width, | 1120 | 15 | self.height, | 1121 | 15 | num_channels, | 1122 | 15 | self.top_down, | 1123 | | |row| { | 1124 | | for pixel in row.chunks_mut(num_channels) { | 1125 | | if *format == FormatFullBytes::Format888 { | 1126 | | reader.read_u8()?; | 1127 | | } | 1128 | | | 1129 | | // 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 | | reader.read_exact(&mut pixel[0..3])?; | 1133 | | pixel[0..3].reverse(); | 1134 | | | 1135 | | if *format == FormatFullBytes::RGB32 { | 1136 | | reader.read_u8()?; | 1137 | | } | 1138 | | | 1139 | | // Read the alpha channel if present | 1140 | | if *format == FormatFullBytes::RGBA32 { | 1141 | | reader.read_exact(&mut pixel[3..4])?; | 1142 | | } else if num_channels == 4 { | 1143 | | pixel[3] = 0xFF; | 1144 | | } | 1145 | | } | 1146 | | reader.read_exact(row_padding) | 1147 | | }, | 1148 | 13 | )?; | 1149 | | | 1150 | 2 | Ok(()) | 1151 | 15 | } |
|
1152 | | |
1153 | 1.34k | 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.34k | self.reader.seek(SeekFrom::Start(self.data_offset))?; |
1156 | | |
1157 | 1.34k | let num_channels = self.num_channels(); |
1158 | 1.34k | 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.34k | let mut row_iter = self.rows(buf); |
1165 | | |
1166 | 350k | while let Some(row) = row_iter.next() { |
1167 | 350k | let mut pixel_iter = row.chunks_exact_mut(num_channels); |
1168 | | |
1169 | 350k | let mut x = 0; |
1170 | | loop { |
1171 | 1.69M | let instruction = { |
1172 | 1.69M | let control_byte = self.reader.read_u8()?; |
1173 | 1.69M | match control_byte { |
1174 | | RLE_ESCAPE => { |
1175 | 858k | let op = self.reader.read_u8()?; |
1176 | | |
1177 | 858k | match op { |
1178 | 349k | RLE_ESCAPE_EOL => RLEInsn::EndOfRow, |
1179 | 379 | RLE_ESCAPE_EOF => RLEInsn::EndOfFile, |
1180 | | RLE_ESCAPE_DELTA => { |
1181 | 309k | let xdelta = self.reader.read_u8()?; |
1182 | 309k | let ydelta = self.reader.read_u8()?; |
1183 | 309k | RLEInsn::Delta(xdelta, ydelta) |
1184 | | } |
1185 | | _ => { |
1186 | 199k | let mut length = op as usize; |
1187 | 199k | if self.image_type == ImageType::RLE4 { |
1188 | 197k | length = length.div_ceil(2); |
1189 | 197k | } |
1190 | 199k | length += length & 1; |
1191 | 199k | let mut buffer = Vec::new(); |
1192 | 199k | self.reader.read_exact_vec(&mut buffer, length)?; |
1193 | 199k | RLEInsn::Absolute(op, buffer) |
1194 | | } |
1195 | | } |
1196 | | } |
1197 | | _ => { |
1198 | 839k | let palette_index = self.reader.read_u8()?; |
1199 | 839k | RLEInsn::PixelRun(control_byte, palette_index) |
1200 | | } |
1201 | | } |
1202 | | }; |
1203 | | |
1204 | 1.69M | match instruction { |
1205 | | RLEInsn::EndOfFile => { |
1206 | 3.84M | pixel_iter.for_each(|p| p.fill(0)); Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#0}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#0}<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#0}Line | Count | Source | 1206 | 852k | pixel_iter.for_each(|p| p.fill(0)); |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#0}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#0}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#0}<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#0}Line | Count | Source | 1206 | 2.53M | pixel_iter.for_each(|p| p.fill(0)); |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#0}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#0}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#0}<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#0}Line | Count | Source | 1206 | 460k | pixel_iter.for_each(|p| p.fill(0)); |
|
1207 | 3.22M | row_iter.for_each(|r| r.fill(0)); Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#1}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#1}<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#1}Line | Count | Source | 1207 | 824k | row_iter.for_each(|r| r.fill(0)); |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#1}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#1}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#1}<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#1}Line | Count | Source | 1207 | 1.41M | row_iter.for_each(|r| r.fill(0)); |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#1}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#1}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#1}<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#1}Line | Count | Source | 1207 | 983k | row_iter.for_each(|r| r.fill(0)); |
|
1208 | 379 | return Ok(()); |
1209 | | } |
1210 | | RLEInsn::EndOfRow => { |
1211 | 1.02G | pixel_iter.for_each(|p| p.fill(0)); Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#2}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#2}<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#2}Line | Count | Source | 1211 | 634M | pixel_iter.for_each(|p| p.fill(0)); |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#2}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#2}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#2}<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#2}Line | Count | Source | 1211 | 273M | pixel_iter.for_each(|p| p.fill(0)); |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#2}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#2}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#2}<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#2}Line | Count | Source | 1211 | 116M | pixel_iter.for_each(|p| p.fill(0)); |
|
1212 | 349k | break; |
1213 | | } |
1214 | 309k | 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 | 309k | if y_delta > 0 { |
1222 | | // Zero out the remainder of the current row. |
1223 | 213M | pixel_iter.for_each(|p| p.fill(0)); Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#3}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#3}<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#3}Line | Count | Source | 1223 | 139M | pixel_iter.for_each(|p| p.fill(0)); |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#3}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#3}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#3}<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#3}Line | Count | Source | 1223 | 14.1M | pixel_iter.for_each(|p| p.fill(0)); |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#3}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#3}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#3}<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#3}Line | Count | Source | 1223 | 60.2M | pixel_iter.for_each(|p| p.fill(0)); |
|
1224 | | |
1225 | | // If any full rows are skipped, zero them out. |
1226 | 42.8k | for _ in 1..y_delta { |
1227 | 571k | let row = row_iter.next().ok_or(DecoderError::CorruptRleData)?; |
1228 | 571k | row.fill(0); |
1229 | | } |
1230 | | |
1231 | | // Set the pixel iterator to the start of the next row. |
1232 | 42.8k | pixel_iter = row_iter |
1233 | 42.8k | .next() |
1234 | 42.8k | .ok_or(DecoderError::CorruptRleData)? |
1235 | 42.8k | .chunks_exact_mut(num_channels); |
1236 | | |
1237 | | // Zero out the pixels up to the current point in the row. |
1238 | 42.8k | for _ in 0..x { |
1239 | 6.62M | pixel_iter |
1240 | 6.62M | .next() |
1241 | 6.62M | .ok_or(DecoderError::CorruptRleData)? |
1242 | 6.62M | .fill(0); |
1243 | | } |
1244 | 266k | } |
1245 | | |
1246 | 309k | for _ in 0..x_delta { |
1247 | 1.37M | let pixel = pixel_iter.next().ok_or(DecoderError::CorruptRleData)?; |
1248 | 1.37M | pixel.fill(0); |
1249 | | } |
1250 | 309k | x += x_delta as usize; |
1251 | | } |
1252 | 199k | 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 | 199k | match image_type { |
1257 | | ImageType::RLE8 => { |
1258 | 1.51k | if !set_8bit_pixel_run( |
1259 | 1.51k | &mut pixel_iter, |
1260 | 1.51k | p, |
1261 | 1.51k | indices.iter(), |
1262 | 1.51k | length as usize, |
1263 | 1.51k | ) { |
1264 | 30 | return Err(DecoderError::CorruptRleData.into()); |
1265 | 1.48k | } |
1266 | | } |
1267 | | ImageType::RLE4 => { |
1268 | 197k | if !set_4bit_pixel_run( |
1269 | 197k | &mut pixel_iter, |
1270 | 197k | p, |
1271 | 197k | indices.iter(), |
1272 | 197k | length as usize, |
1273 | 197k | ) { |
1274 | 30 | return Err(DecoderError::CorruptRleData.into()); |
1275 | 197k | } |
1276 | | } |
1277 | 0 | _ => unreachable!(), |
1278 | | } |
1279 | 199k | x += length as usize; |
1280 | | } |
1281 | 839k | RLEInsn::PixelRun(n_pixels, palette_index) => { |
1282 | 839k | 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 | 104k | let repeat_pixel: [u8; 3] = p[palette_index as usize]; |
1291 | 1.77M | (&mut pixel_iter).take(n_pixels as usize).for_each(|p| { |
1292 | 1.77M | p[2] = repeat_pixel[2]; |
1293 | 1.77M | p[1] = repeat_pixel[1]; |
1294 | 1.77M | p[0] = repeat_pixel[0]; |
1295 | 1.77M | }); Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#4}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#4}<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#4}Line | Count | Source | 1291 | 370k | (&mut pixel_iter).take(n_pixels as usize).for_each(|p| { | 1292 | 370k | p[2] = repeat_pixel[2]; | 1293 | 370k | p[1] = repeat_pixel[1]; | 1294 | 370k | p[0] = repeat_pixel[0]; | 1295 | 370k | }); |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#4}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#4}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#4}<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#4}Line | Count | Source | 1291 | 1.29M | (&mut pixel_iter).take(n_pixels as usize).for_each(|p| { | 1292 | 1.29M | p[2] = repeat_pixel[2]; | 1293 | 1.29M | p[1] = repeat_pixel[1]; | 1294 | 1.29M | p[0] = repeat_pixel[0]; | 1295 | 1.29M | }); |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#4}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#4}Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#4}<image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data::{closure#4}Line | Count | Source | 1291 | 111k | (&mut pixel_iter).take(n_pixels as usize).for_each(|p| { | 1292 | 111k | p[2] = repeat_pixel[2]; | 1293 | 111k | p[1] = repeat_pixel[1]; | 1294 | 111k | p[0] = repeat_pixel[0]; | 1295 | 111k | }); |
|
1296 | | } |
1297 | | ImageType::RLE4 => { |
1298 | 735k | if !set_4bit_pixel_run( |
1299 | 735k | &mut pixel_iter, |
1300 | 735k | p, |
1301 | 735k | repeat(&palette_index), |
1302 | 735k | n_pixels as usize, |
1303 | 735k | ) { |
1304 | 71 | return Err(DecoderError::CorruptRleData.into()); |
1305 | 735k | } |
1306 | | } |
1307 | 0 | _ => unreachable!(), |
1308 | | } |
1309 | 839k | x += n_pixels as usize; |
1310 | | } |
1311 | | } |
1312 | | } |
1313 | | } |
1314 | | |
1315 | 5 | Ok(()) |
1316 | 1.34k | } Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data Line | Count | Source | 1153 | 456 | fn read_rle_data(&mut self, buf: &mut [u8], image_type: ImageType) -> ImageResult<()> { | 1154 | | // Seek to the start of the actual image data. | 1155 | 456 | self.reader.seek(SeekFrom::Start(self.data_offset))?; | 1156 | | | 1157 | 456 | let num_channels = self.num_channels(); | 1158 | 456 | 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 | 456 | let mut row_iter = self.rows(buf); | 1165 | | | 1166 | 289k | while let Some(row) = row_iter.next() { | 1167 | 289k | let mut pixel_iter = row.chunks_exact_mut(num_channels); | 1168 | | | 1169 | 289k | let mut x = 0; | 1170 | | loop { | 1171 | 1.45M | let instruction = { | 1172 | 1.45M | let control_byte = self.reader.read_u8()?; | 1173 | 1.45M | match control_byte { | 1174 | | RLE_ESCAPE => { | 1175 | 764k | let op = self.reader.read_u8()?; | 1176 | | | 1177 | 764k | match op { | 1178 | 288k | RLE_ESCAPE_EOL => RLEInsn::EndOfRow, | 1179 | 81 | RLE_ESCAPE_EOF => RLEInsn::EndOfFile, | 1180 | | RLE_ESCAPE_DELTA => { | 1181 | 292k | let xdelta = self.reader.read_u8()?; | 1182 | 292k | let ydelta = self.reader.read_u8()?; | 1183 | 292k | RLEInsn::Delta(xdelta, ydelta) | 1184 | | } | 1185 | | _ => { | 1186 | 183k | let mut length = op as usize; | 1187 | 183k | if self.image_type == ImageType::RLE4 { | 1188 | 182k | length = length.div_ceil(2); | 1189 | 182k | } | 1190 | 183k | length += length & 1; | 1191 | 183k | let mut buffer = Vec::new(); | 1192 | 183k | self.reader.read_exact_vec(&mut buffer, length)?; | 1193 | 183k | RLEInsn::Absolute(op, buffer) | 1194 | | } | 1195 | | } | 1196 | | } | 1197 | | _ => { | 1198 | 689k | let palette_index = self.reader.read_u8()?; | 1199 | 689k | RLEInsn::PixelRun(control_byte, palette_index) | 1200 | | } | 1201 | | } | 1202 | | }; | 1203 | | | 1204 | 1.45M | match instruction { | 1205 | | RLEInsn::EndOfFile => { | 1206 | 81 | pixel_iter.for_each(|p| p.fill(0)); | 1207 | 81 | row_iter.for_each(|r| r.fill(0)); | 1208 | 81 | return Ok(()); | 1209 | | } | 1210 | | RLEInsn::EndOfRow => { | 1211 | 288k | pixel_iter.for_each(|p| p.fill(0)); | 1212 | 288k | break; | 1213 | | } | 1214 | 292k | 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 | 292k | if y_delta > 0 { | 1222 | | // Zero out the remainder of the current row. | 1223 | 38.8k | pixel_iter.for_each(|p| p.fill(0)); | 1224 | | | 1225 | | // If any full rows are skipped, zero them out. | 1226 | 38.8k | for _ in 1..y_delta { | 1227 | 405k | let row = row_iter.next().ok_or(DecoderError::CorruptRleData)?; | 1228 | 405k | row.fill(0); | 1229 | | } | 1230 | | | 1231 | | // Set the pixel iterator to the start of the next row. | 1232 | 38.8k | pixel_iter = row_iter | 1233 | 38.8k | .next() | 1234 | 38.8k | .ok_or(DecoderError::CorruptRleData)? | 1235 | 38.8k | .chunks_exact_mut(num_channels); | 1236 | | | 1237 | | // Zero out the pixels up to the current point in the row. | 1238 | 38.8k | for _ in 0..x { | 1239 | 5.88M | pixel_iter | 1240 | 5.88M | .next() | 1241 | 5.88M | .ok_or(DecoderError::CorruptRleData)? | 1242 | 5.88M | .fill(0); | 1243 | | } | 1244 | 253k | } | 1245 | | | 1246 | 292k | for _ in 0..x_delta { | 1247 | 1.35M | let pixel = pixel_iter.next().ok_or(DecoderError::CorruptRleData)?; | 1248 | 1.35M | pixel.fill(0); | 1249 | | } | 1250 | 292k | x += x_delta as usize; | 1251 | | } | 1252 | 183k | 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 | 183k | match image_type { | 1257 | | ImageType::RLE8 => { | 1258 | 904 | if !set_8bit_pixel_run( | 1259 | 904 | &mut pixel_iter, | 1260 | 904 | p, | 1261 | 904 | indices.iter(), | 1262 | 904 | length as usize, | 1263 | 904 | ) { | 1264 | 12 | return Err(DecoderError::CorruptRleData.into()); | 1265 | 892 | } | 1266 | | } | 1267 | | ImageType::RLE4 => { | 1268 | 182k | if !set_4bit_pixel_run( | 1269 | 182k | &mut pixel_iter, | 1270 | 182k | p, | 1271 | 182k | indices.iter(), | 1272 | 182k | length as usize, | 1273 | 182k | ) { | 1274 | 7 | return Err(DecoderError::CorruptRleData.into()); | 1275 | 182k | } | 1276 | | } | 1277 | 0 | _ => unreachable!(), | 1278 | | } | 1279 | 183k | x += length as usize; | 1280 | | } | 1281 | 689k | RLEInsn::PixelRun(n_pixels, palette_index) => { | 1282 | 689k | 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 | 11.4k | let repeat_pixel: [u8; 3] = p[palette_index as usize]; | 1291 | 11.4k | (&mut pixel_iter).take(n_pixels as usize).for_each(|p| { | 1292 | | p[2] = repeat_pixel[2]; | 1293 | | p[1] = repeat_pixel[1]; | 1294 | | p[0] = repeat_pixel[0]; | 1295 | | }); | 1296 | | } | 1297 | | ImageType::RLE4 => { | 1298 | 678k | if !set_4bit_pixel_run( | 1299 | 678k | &mut pixel_iter, | 1300 | 678k | p, | 1301 | 678k | repeat(&palette_index), | 1302 | 678k | n_pixels as usize, | 1303 | 678k | ) { | 1304 | 43 | return Err(DecoderError::CorruptRleData.into()); | 1305 | 678k | } | 1306 | | } | 1307 | 0 | _ => unreachable!(), | 1308 | | } | 1309 | 689k | x += n_pixels as usize; | 1310 | | } | 1311 | | } | 1312 | | } | 1313 | | } | 1314 | | | 1315 | 3 | Ok(()) | 1316 | 456 | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data Line | Count | Source | 1153 | 746 | fn read_rle_data(&mut self, buf: &mut [u8], image_type: ImageType) -> ImageResult<()> { | 1154 | | // Seek to the start of the actual image data. | 1155 | 746 | self.reader.seek(SeekFrom::Start(self.data_offset))?; | 1156 | | | 1157 | 746 | let num_channels = self.num_channels(); | 1158 | 746 | 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 | 746 | let mut row_iter = self.rows(buf); | 1165 | | | 1166 | 51.1k | while let Some(row) = row_iter.next() { | 1167 | 51.1k | let mut pixel_iter = row.chunks_exact_mut(num_channels); | 1168 | | | 1169 | 51.1k | let mut x = 0; | 1170 | | loop { | 1171 | 219k | let instruction = { | 1172 | 220k | let control_byte = self.reader.read_u8()?; | 1173 | 219k | match control_byte { | 1174 | | RLE_ESCAPE => { | 1175 | 79.5k | let op = self.reader.read_u8()?; | 1176 | | | 1177 | 79.5k | match op { | 1178 | 50.4k | RLE_ESCAPE_EOL => RLEInsn::EndOfRow, | 1179 | 225 | RLE_ESCAPE_EOF => RLEInsn::EndOfFile, | 1180 | | RLE_ESCAPE_DELTA => { | 1181 | 14.7k | let xdelta = self.reader.read_u8()?; | 1182 | 14.7k | let ydelta = self.reader.read_u8()?; | 1183 | 14.7k | RLEInsn::Delta(xdelta, ydelta) | 1184 | | } | 1185 | | _ => { | 1186 | 14.1k | let mut length = op as usize; | 1187 | 14.1k | if self.image_type == ImageType::RLE4 { | 1188 | 13.7k | length = length.div_ceil(2); | 1189 | 13.7k | } | 1190 | 14.1k | length += length & 1; | 1191 | 14.1k | let mut buffer = Vec::new(); | 1192 | 14.1k | self.reader.read_exact_vec(&mut buffer, length)?; | 1193 | 14.1k | RLEInsn::Absolute(op, buffer) | 1194 | | } | 1195 | | } | 1196 | | } | 1197 | | _ => { | 1198 | 140k | let palette_index = self.reader.read_u8()?; | 1199 | 140k | RLEInsn::PixelRun(control_byte, palette_index) | 1200 | | } | 1201 | | } | 1202 | | }; | 1203 | | | 1204 | 219k | match instruction { | 1205 | | RLEInsn::EndOfFile => { | 1206 | 225 | pixel_iter.for_each(|p| p.fill(0)); | 1207 | 225 | row_iter.for_each(|r| r.fill(0)); | 1208 | 225 | return Ok(()); | 1209 | | } | 1210 | | RLEInsn::EndOfRow => { | 1211 | 50.4k | pixel_iter.for_each(|p| p.fill(0)); | 1212 | 50.4k | break; | 1213 | | } | 1214 | 14.7k | 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 | 14.7k | if y_delta > 0 { | 1222 | | // Zero out the remainder of the current row. | 1223 | 2.12k | pixel_iter.for_each(|p| p.fill(0)); | 1224 | | | 1225 | | // If any full rows are skipped, zero them out. | 1226 | 2.12k | for _ in 1..y_delta { | 1227 | 144k | let row = row_iter.next().ok_or(DecoderError::CorruptRleData)?; | 1228 | 144k | row.fill(0); | 1229 | | } | 1230 | | | 1231 | | // Set the pixel iterator to the start of the next row. | 1232 | 2.11k | pixel_iter = row_iter | 1233 | 2.11k | .next() | 1234 | 2.11k | .ok_or(DecoderError::CorruptRleData)? | 1235 | 2.11k | .chunks_exact_mut(num_channels); | 1236 | | | 1237 | | // Zero out the pixels up to the current point in the row. | 1238 | 2.11k | for _ in 0..x { | 1239 | 382k | pixel_iter | 1240 | 382k | .next() | 1241 | 382k | .ok_or(DecoderError::CorruptRleData)? | 1242 | 382k | .fill(0); | 1243 | | } | 1244 | 12.5k | } | 1245 | | | 1246 | 14.6k | for _ in 0..x_delta { | 1247 | 18.3k | let pixel = pixel_iter.next().ok_or(DecoderError::CorruptRleData)?; | 1248 | 18.2k | pixel.fill(0); | 1249 | | } | 1250 | 14.6k | x += x_delta as usize; | 1251 | | } | 1252 | 14.1k | 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 | 14.1k | match image_type { | 1257 | | ImageType::RLE8 => { | 1258 | 414 | if !set_8bit_pixel_run( | 1259 | 414 | &mut pixel_iter, | 1260 | 414 | p, | 1261 | 414 | indices.iter(), | 1262 | 414 | length as usize, | 1263 | 414 | ) { | 1264 | 17 | return Err(DecoderError::CorruptRleData.into()); | 1265 | 397 | } | 1266 | | } | 1267 | | ImageType::RLE4 => { | 1268 | 13.7k | if !set_4bit_pixel_run( | 1269 | 13.7k | &mut pixel_iter, | 1270 | 13.7k | p, | 1271 | 13.7k | indices.iter(), | 1272 | 13.7k | length as usize, | 1273 | 13.7k | ) { | 1274 | 21 | return Err(DecoderError::CorruptRleData.into()); | 1275 | 13.6k | } | 1276 | | } | 1277 | 0 | _ => unreachable!(), | 1278 | | } | 1279 | 14.0k | x += length as usize; | 1280 | | } | 1281 | 140k | RLEInsn::PixelRun(n_pixels, palette_index) => { | 1282 | 140k | 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 | 91.1k | let repeat_pixel: [u8; 3] = p[palette_index as usize]; | 1291 | 91.1k | (&mut pixel_iter).take(n_pixels as usize).for_each(|p| { | 1292 | | p[2] = repeat_pixel[2]; | 1293 | | p[1] = repeat_pixel[1]; | 1294 | | p[0] = repeat_pixel[0]; | 1295 | | }); | 1296 | | } | 1297 | | ImageType::RLE4 => { | 1298 | 49.1k | if !set_4bit_pixel_run( | 1299 | 49.1k | &mut pixel_iter, | 1300 | 49.1k | p, | 1301 | 49.1k | repeat(&palette_index), | 1302 | 49.1k | n_pixels as usize, | 1303 | 49.1k | ) { | 1304 | 26 | return Err(DecoderError::CorruptRleData.into()); | 1305 | 49.1k | } | 1306 | | } | 1307 | 0 | _ => unreachable!(), | 1308 | | } | 1309 | 140k | x += n_pixels as usize; | 1310 | | } | 1311 | | } | 1312 | | } | 1313 | | } | 1314 | | | 1315 | 1 | Ok(()) | 1316 | 746 | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_rle_data Line | Count | Source | 1153 | 143 | fn read_rle_data(&mut self, buf: &mut [u8], image_type: ImageType) -> ImageResult<()> { | 1154 | | // Seek to the start of the actual image data. | 1155 | 143 | self.reader.seek(SeekFrom::Start(self.data_offset))?; | 1156 | | | 1157 | 143 | let num_channels = self.num_channels(); | 1158 | 143 | 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 | 143 | let mut row_iter = self.rows(buf); | 1165 | | | 1166 | 10.0k | while let Some(row) = row_iter.next() { | 1167 | 10.0k | let mut pixel_iter = row.chunks_exact_mut(num_channels); | 1168 | | | 1169 | 10.0k | let mut x = 0; | 1170 | | loop { | 1171 | 23.4k | let instruction = { | 1172 | 23.4k | let control_byte = self.reader.read_u8()?; | 1173 | 23.4k | match control_byte { | 1174 | | RLE_ESCAPE => { | 1175 | 14.4k | let op = self.reader.read_u8()?; | 1176 | | | 1177 | 14.3k | match op { | 1178 | 9.86k | RLE_ESCAPE_EOL => RLEInsn::EndOfRow, | 1179 | 73 | RLE_ESCAPE_EOF => RLEInsn::EndOfFile, | 1180 | | RLE_ESCAPE_DELTA => { | 1181 | 2.52k | let xdelta = self.reader.read_u8()?; | 1182 | 2.52k | let ydelta = self.reader.read_u8()?; | 1183 | 2.52k | RLEInsn::Delta(xdelta, ydelta) | 1184 | | } | 1185 | | _ => { | 1186 | 1.93k | let mut length = op as usize; | 1187 | 1.93k | if self.image_type == ImageType::RLE4 { | 1188 | 1.72k | length = length.div_ceil(2); | 1189 | 1.72k | } | 1190 | 1.93k | length += length & 1; | 1191 | 1.93k | let mut buffer = Vec::new(); | 1192 | 1.93k | self.reader.read_exact_vec(&mut buffer, length)?; | 1193 | 1.91k | RLEInsn::Absolute(op, buffer) | 1194 | | } | 1195 | | } | 1196 | | } | 1197 | | _ => { | 1198 | 9.06k | let palette_index = self.reader.read_u8()?; | 1199 | 9.05k | RLEInsn::PixelRun(control_byte, palette_index) | 1200 | | } | 1201 | | } | 1202 | | }; | 1203 | | | 1204 | 23.4k | match instruction { | 1205 | | RLEInsn::EndOfFile => { | 1206 | 73 | pixel_iter.for_each(|p| p.fill(0)); | 1207 | 73 | row_iter.for_each(|r| r.fill(0)); | 1208 | 73 | return Ok(()); | 1209 | | } | 1210 | | RLEInsn::EndOfRow => { | 1211 | 9.86k | pixel_iter.for_each(|p| p.fill(0)); | 1212 | 9.86k | break; | 1213 | | } | 1214 | 2.52k | 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 | 2.52k | if y_delta > 0 { | 1222 | | // Zero out the remainder of the current row. | 1223 | 1.93k | pixel_iter.for_each(|p| p.fill(0)); | 1224 | | | 1225 | | // If any full rows are skipped, zero them out. | 1226 | 1.93k | for _ in 1..y_delta { | 1227 | 21.2k | let row = row_iter.next().ok_or(DecoderError::CorruptRleData)?; | 1228 | 21.1k | row.fill(0); | 1229 | | } | 1230 | | | 1231 | | // Set the pixel iterator to the start of the next row. | 1232 | 1.93k | pixel_iter = row_iter | 1233 | 1.93k | .next() | 1234 | 1.93k | .ok_or(DecoderError::CorruptRleData)? | 1235 | 1.93k | .chunks_exact_mut(num_channels); | 1236 | | | 1237 | | // Zero out the pixels up to the current point in the row. | 1238 | 1.93k | for _ in 0..x { | 1239 | 356k | pixel_iter | 1240 | 356k | .next() | 1241 | 356k | .ok_or(DecoderError::CorruptRleData)? | 1242 | 356k | .fill(0); | 1243 | | } | 1244 | 590 | } | 1245 | | | 1246 | 2.52k | for _ in 0..x_delta { | 1247 | 10.0k | let pixel = pixel_iter.next().ok_or(DecoderError::CorruptRleData)?; | 1248 | 10.0k | pixel.fill(0); | 1249 | | } | 1250 | 2.51k | x += x_delta as usize; | 1251 | | } | 1252 | 1.91k | 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 | 1.91k | match image_type { | 1257 | | ImageType::RLE8 => { | 1258 | 199 | if !set_8bit_pixel_run( | 1259 | 199 | &mut pixel_iter, | 1260 | 199 | p, | 1261 | 199 | indices.iter(), | 1262 | 199 | length as usize, | 1263 | 199 | ) { | 1264 | 1 | return Err(DecoderError::CorruptRleData.into()); | 1265 | 198 | } | 1266 | | } | 1267 | | ImageType::RLE4 => { | 1268 | 1.71k | if !set_4bit_pixel_run( | 1269 | 1.71k | &mut pixel_iter, | 1270 | 1.71k | p, | 1271 | 1.71k | indices.iter(), | 1272 | 1.71k | length as usize, | 1273 | 1.71k | ) { | 1274 | 2 | return Err(DecoderError::CorruptRleData.into()); | 1275 | 1.71k | } | 1276 | | } | 1277 | 0 | _ => unreachable!(), | 1278 | | } | 1279 | 1.90k | x += length as usize; | 1280 | | } | 1281 | 9.05k | RLEInsn::PixelRun(n_pixels, palette_index) => { | 1282 | 9.05k | 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 | 1.37k | let repeat_pixel: [u8; 3] = p[palette_index as usize]; | 1291 | 1.37k | (&mut pixel_iter).take(n_pixels as usize).for_each(|p| { | 1292 | | p[2] = repeat_pixel[2]; | 1293 | | p[1] = repeat_pixel[1]; | 1294 | | p[0] = repeat_pixel[0]; | 1295 | | }); | 1296 | | } | 1297 | | ImageType::RLE4 => { | 1298 | 7.67k | if !set_4bit_pixel_run( | 1299 | 7.67k | &mut pixel_iter, | 1300 | 7.67k | p, | 1301 | 7.67k | repeat(&palette_index), | 1302 | 7.67k | n_pixels as usize, | 1303 | 7.67k | ) { | 1304 | 2 | return Err(DecoderError::CorruptRleData.into()); | 1305 | 7.67k | } | 1306 | | } | 1307 | 0 | _ => unreachable!(), | 1308 | | } | 1309 | 9.05k | x += n_pixels as usize; | 1310 | | } | 1311 | | } | 1312 | | } | 1313 | | } | 1314 | | | 1315 | 1 | Ok(()) | 1316 | 143 | } |
|
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.20k | pub(crate) fn read_image_data(&mut self, buf: &mut [u8]) -> ImageResult<()> { |
1321 | 3.20k | match self.image_type { |
1322 | 853 | ImageType::Palette => self.read_palettized_pixel_data(buf), |
1323 | 184 | ImageType::RGB16 => self.read_16_bit_pixel_data(buf, Some(&R5_G5_B5_COLOR_MASK)), |
1324 | 192 | ImageType::RGB24 => self.read_full_byte_pixel_data(buf, &FormatFullBytes::RGB24), |
1325 | 50 | ImageType::RGB32 => self.read_full_byte_pixel_data(buf, &FormatFullBytes::RGB32), |
1326 | 54 | ImageType::RGBA32 => self.read_full_byte_pixel_data(buf, &FormatFullBytes::RGBA32), |
1327 | 492 | ImageType::RLE8 => self.read_rle_data(buf, ImageType::RLE8), |
1328 | 853 | ImageType::RLE4 => self.read_rle_data(buf, ImageType::RLE4), |
1329 | 127 | ImageType::Bitfields16 => match self.bitfields { |
1330 | 127 | Some(_) => self.read_16_bit_pixel_data(buf, None), |
1331 | 0 | None => Err(DecoderError::BitfieldMasksMissing(16).into()), |
1332 | | }, |
1333 | 396 | ImageType::Bitfields32 => match self.bitfields { |
1334 | | Some(R8_G8_B8_COLOR_MASK) => { |
1335 | 67 | self.read_full_byte_pixel_data(buf, &FormatFullBytes::Format888) |
1336 | | } |
1337 | | Some(R8_G8_B8_A8_COLOR_MASK) => { |
1338 | 41 | self.read_full_byte_pixel_data(buf, &FormatFullBytes::RGBA32) |
1339 | | } |
1340 | 288 | Some(_) => self.read_32_bit_pixel_data(buf), |
1341 | 0 | None => Err(DecoderError::BitfieldMasksMissing(32).into()), |
1342 | | }, |
1343 | | } |
1344 | 3.20k | } Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_image_data Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_image_data <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_image_data Line | Count | Source | 1320 | 1.28k | pub(crate) fn read_image_data(&mut self, buf: &mut [u8]) -> ImageResult<()> { | 1321 | 1.28k | match self.image_type { | 1322 | 381 | ImageType::Palette => self.read_palettized_pixel_data(buf), | 1323 | 70 | ImageType::RGB16 => self.read_16_bit_pixel_data(buf, Some(&R5_G5_B5_COLOR_MASK)), | 1324 | 72 | ImageType::RGB24 => self.read_full_byte_pixel_data(buf, &FormatFullBytes::RGB24), | 1325 | 47 | ImageType::RGB32 => self.read_full_byte_pixel_data(buf, &FormatFullBytes::RGB32), | 1326 | 0 | ImageType::RGBA32 => self.read_full_byte_pixel_data(buf, &FormatFullBytes::RGBA32), | 1327 | 141 | ImageType::RLE8 => self.read_rle_data(buf, ImageType::RLE8), | 1328 | 315 | ImageType::RLE4 => self.read_rle_data(buf, ImageType::RLE4), | 1329 | 56 | ImageType::Bitfields16 => match self.bitfields { | 1330 | 56 | Some(_) => self.read_16_bit_pixel_data(buf, None), | 1331 | 0 | None => Err(DecoderError::BitfieldMasksMissing(16).into()), | 1332 | | }, | 1333 | 207 | ImageType::Bitfields32 => match self.bitfields { | 1334 | | Some(R8_G8_B8_COLOR_MASK) => { | 1335 | 41 | self.read_full_byte_pixel_data(buf, &FormatFullBytes::Format888) | 1336 | | } | 1337 | | Some(R8_G8_B8_A8_COLOR_MASK) => { | 1338 | 37 | self.read_full_byte_pixel_data(buf, &FormatFullBytes::RGBA32) | 1339 | | } | 1340 | 129 | Some(_) => self.read_32_bit_pixel_data(buf), | 1341 | 0 | None => Err(DecoderError::BitfieldMasksMissing(32).into()), | 1342 | | }, | 1343 | | } | 1344 | 1.28k | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_image_data Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_image_data Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_image_data <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_image_data Line | Count | Source | 1320 | 1.68k | pub(crate) fn read_image_data(&mut self, buf: &mut [u8]) -> ImageResult<()> { | 1321 | 1.68k | match self.image_type { | 1322 | 424 | ImageType::Palette => self.read_palettized_pixel_data(buf), | 1323 | 106 | ImageType::RGB16 => self.read_16_bit_pixel_data(buf, Some(&R5_G5_B5_COLOR_MASK)), | 1324 | 113 | ImageType::RGB24 => self.read_full_byte_pixel_data(buf, &FormatFullBytes::RGB24), | 1325 | 0 | ImageType::RGB32 => self.read_full_byte_pixel_data(buf, &FormatFullBytes::RGB32), | 1326 | 53 | ImageType::RGBA32 => self.read_full_byte_pixel_data(buf, &FormatFullBytes::RGBA32), | 1327 | 336 | ImageType::RLE8 => self.read_rle_data(buf, ImageType::RLE8), | 1328 | 410 | ImageType::RLE4 => self.read_rle_data(buf, ImageType::RLE4), | 1329 | 66 | ImageType::Bitfields16 => match self.bitfields { | 1330 | 66 | Some(_) => self.read_16_bit_pixel_data(buf, None), | 1331 | 0 | None => Err(DecoderError::BitfieldMasksMissing(16).into()), | 1332 | | }, | 1333 | 174 | ImageType::Bitfields32 => match self.bitfields { | 1334 | | Some(R8_G8_B8_COLOR_MASK) => { | 1335 | 25 | self.read_full_byte_pixel_data(buf, &FormatFullBytes::Format888) | 1336 | | } | 1337 | | Some(R8_G8_B8_A8_COLOR_MASK) => { | 1338 | 1 | self.read_full_byte_pixel_data(buf, &FormatFullBytes::RGBA32) | 1339 | | } | 1340 | 148 | Some(_) => self.read_32_bit_pixel_data(buf), | 1341 | 0 | None => Err(DecoderError::BitfieldMasksMissing(32).into()), | 1342 | | }, | 1343 | | } | 1344 | 1.68k | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_image_data Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_image_data Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_image_data <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>>>::read_image_data Line | Count | Source | 1320 | 230 | pub(crate) fn read_image_data(&mut self, buf: &mut [u8]) -> ImageResult<()> { | 1321 | 230 | match self.image_type { | 1322 | 48 | ImageType::Palette => self.read_palettized_pixel_data(buf), | 1323 | 8 | ImageType::RGB16 => self.read_16_bit_pixel_data(buf, Some(&R5_G5_B5_COLOR_MASK)), | 1324 | 7 | ImageType::RGB24 => self.read_full_byte_pixel_data(buf, &FormatFullBytes::RGB24), | 1325 | 3 | ImageType::RGB32 => self.read_full_byte_pixel_data(buf, &FormatFullBytes::RGB32), | 1326 | 1 | ImageType::RGBA32 => self.read_full_byte_pixel_data(buf, &FormatFullBytes::RGBA32), | 1327 | 15 | ImageType::RLE8 => self.read_rle_data(buf, ImageType::RLE8), | 1328 | 128 | ImageType::RLE4 => self.read_rle_data(buf, ImageType::RLE4), | 1329 | 5 | ImageType::Bitfields16 => match self.bitfields { | 1330 | 5 | Some(_) => self.read_16_bit_pixel_data(buf, None), | 1331 | 0 | None => Err(DecoderError::BitfieldMasksMissing(16).into()), | 1332 | | }, | 1333 | 15 | ImageType::Bitfields32 => match self.bitfields { | 1334 | | Some(R8_G8_B8_COLOR_MASK) => { | 1335 | 1 | self.read_full_byte_pixel_data(buf, &FormatFullBytes::Format888) | 1336 | | } | 1337 | | Some(R8_G8_B8_A8_COLOR_MASK) => { | 1338 | 3 | self.read_full_byte_pixel_data(buf, &FormatFullBytes::RGBA32) | 1339 | | } | 1340 | 11 | Some(_) => self.read_32_bit_pixel_data(buf), | 1341 | 0 | None => Err(DecoderError::BitfieldMasksMissing(32).into()), | 1342 | | }, | 1343 | | } | 1344 | 230 | } |
|
1345 | | } |
1346 | | |
1347 | | impl<R: BufRead + Seek> ImageDecoder for BmpDecoder<R> { |
1348 | 18.0k | fn dimensions(&self) -> (u32, u32) { |
1349 | 18.0k | (self.width as u32, self.height as u32) |
1350 | 18.0k | } Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::dimensions Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::dimensions <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::dimensions Line | Count | Source | 1348 | 6.47k | fn dimensions(&self) -> (u32, u32) { | 1349 | 6.47k | (self.width as u32, self.height as u32) | 1350 | 6.47k | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::dimensions Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::dimensions Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::dimensions <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::dimensions Line | Count | Source | 1348 | 10.3k | fn dimensions(&self) -> (u32, u32) { | 1349 | 10.3k | (self.width as u32, self.height as u32) | 1350 | 10.3k | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::dimensions Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::dimensions Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::dimensions <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::dimensions Line | Count | Source | 1348 | 1.23k | fn dimensions(&self) -> (u32, u32) { | 1349 | 1.23k | (self.width as u32, self.height as u32) | 1350 | 1.23k | } |
|
1351 | | |
1352 | 14.7k | fn color_type(&self) -> ColorType { |
1353 | 14.7k | if self.indexed_color { |
1354 | 0 | ColorType::L8 |
1355 | 14.7k | } else if self.add_alpha_channel { |
1356 | 9.65k | ColorType::Rgba8 |
1357 | | } else { |
1358 | 5.14k | ColorType::Rgb8 |
1359 | | } |
1360 | 14.7k | } Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::color_type Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::color_type <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::color_type Line | Count | Source | 1352 | 5.18k | fn color_type(&self) -> ColorType { | 1353 | 5.18k | if self.indexed_color { | 1354 | 0 | ColorType::L8 | 1355 | 5.18k | } else if self.add_alpha_channel { | 1356 | 601 | ColorType::Rgba8 | 1357 | | } else { | 1358 | 4.58k | ColorType::Rgb8 | 1359 | | } | 1360 | 5.18k | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::color_type Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::color_type Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::color_type <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::color_type Line | Count | Source | 1352 | 8.61k | fn color_type(&self) -> ColorType { | 1353 | 8.61k | if self.indexed_color { | 1354 | 0 | ColorType::L8 | 1355 | 8.61k | } else if self.add_alpha_channel { | 1356 | 8.61k | ColorType::Rgba8 | 1357 | | } else { | 1358 | 0 | ColorType::Rgb8 | 1359 | | } | 1360 | 8.61k | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::color_type Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::color_type Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::color_type <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::color_type Line | Count | Source | 1352 | 1.00k | fn color_type(&self) -> ColorType { | 1353 | 1.00k | if self.indexed_color { | 1354 | 0 | ColorType::L8 | 1355 | 1.00k | } else if self.add_alpha_channel { | 1356 | 447 | ColorType::Rgba8 | 1357 | | } else { | 1358 | 556 | ColorType::Rgb8 | 1359 | | } | 1360 | 1.00k | } |
|
1361 | | |
1362 | 1.43k | fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> { |
1363 | 1.43k | assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes())); |
1364 | 1.43k | self.read_image_data(buf) |
1365 | 1.43k | } Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image Line | Count | Source | 1362 | 1.28k | fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> { | 1363 | 1.28k | assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes())); | 1364 | 1.28k | self.read_image_data(buf) | 1365 | 1.28k | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image Line | Count | Source | 1362 | 147 | fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> { | 1363 | 147 | assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes())); | 1364 | 147 | self.read_image_data(buf) | 1365 | 147 | } |
|
1366 | | |
1367 | 1.43k | fn read_image_boxed(self: Box<Self>, buf: &mut [u8]) -> ImageResult<()> { |
1368 | 1.43k | (*self).read_image(buf) |
1369 | 1.43k | } Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image_boxed Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image_boxed <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image_boxed Line | Count | Source | 1367 | 1.28k | fn read_image_boxed(self: Box<Self>, buf: &mut [u8]) -> ImageResult<()> { | 1368 | 1.28k | (*self).read_image(buf) | 1369 | 1.28k | } |
Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image_boxed Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image_boxed Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image_boxed Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image_boxed Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image_boxed Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image_boxed Unexecuted instantiation: <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image_boxed <image::codecs::bmp::decoder::BmpDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image_boxed Line | Count | Source | 1367 | 147 | fn read_image_boxed(self: Box<Self>, buf: &mut [u8]) -> ImageResult<()> { | 1368 | 147 | (*self).read_image(buf) | 1369 | 147 | } |
|
1370 | | } |
1371 | | |
1372 | | impl<R: BufRead + Seek> ImageDecoderRect for BmpDecoder<R> { |
1373 | | fn read_rect( |
1374 | | &mut self, |
1375 | | x: u32, |
1376 | | y: u32, |
1377 | | width: u32, |
1378 | | height: u32, |
1379 | | buf: &mut [u8], |
1380 | | row_pitch: usize, |
1381 | | ) -> ImageResult<()> { |
1382 | | let start = self.reader.stream_position()?; |
1383 | | load_rect( |
1384 | | x, |
1385 | | y, |
1386 | | width, |
1387 | | height, |
1388 | | buf, |
1389 | | row_pitch, |
1390 | | self, |
1391 | | self.total_bytes() as usize, |
1392 | | |_, _| Ok(()), |
1393 | | |s, buf| s.read_image_data(buf), |
1394 | | )?; |
1395 | | self.reader.seek(SeekFrom::Start(start))?; |
1396 | | Ok(()) |
1397 | | } |
1398 | | } |
1399 | | |
1400 | | #[cfg(test)] |
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 | | } |