/src/image/src/codecs/tga/decoder.rs
Line | Count | Source |
1 | | use super::header::{Header, ImageType, ALPHA_BIT_MASK}; |
2 | | use crate::error::DecodingError; |
3 | | use crate::io::ReadExt; |
4 | | use crate::utils::vec_try_with_capacity; |
5 | | use crate::{ |
6 | | color::{ColorType, ExtendedColorType}, |
7 | | error::{ImageError, ImageResult, UnsupportedError, UnsupportedErrorKind}, |
8 | | ImageDecoder, ImageFormat, |
9 | | }; |
10 | | use byteorder_lite::ReadBytesExt; |
11 | | use std::io::{self, Read}; |
12 | | |
13 | | struct ColorMap { |
14 | | /// sizes in bytes |
15 | | start_offset: usize, |
16 | | entry_size: usize, |
17 | | bytes: Vec<u8>, |
18 | | } |
19 | | |
20 | | impl ColorMap { |
21 | | /// Get one entry from the color map |
22 | 1.95M | pub(crate) fn get(&self, index: usize) -> Option<&[u8]> { |
23 | 1.95M | let entry = self.entry_size * index.checked_sub(self.start_offset)?; |
24 | 1.95M | self.bytes.get(entry..entry + self.entry_size) |
25 | 1.95M | } |
26 | | } |
27 | | |
28 | | /// The representation of a TGA decoder |
29 | | pub struct TgaDecoder<R> { |
30 | | r: R, |
31 | | |
32 | | width: usize, |
33 | | height: usize, |
34 | | |
35 | | // The number of bytes in the raw input data for each pixel. If a color map is used, this is the |
36 | | // number of bytes for each color map index. |
37 | | raw_bytes_per_pixel: usize, |
38 | | |
39 | | image_type: ImageType, |
40 | | color_type: ColorType, |
41 | | original_color_type: Option<ExtendedColorType>, |
42 | | |
43 | | header: Header, |
44 | | color_map: Option<ColorMap>, |
45 | | } |
46 | | |
47 | | #[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] |
48 | | enum TgaOrientation { |
49 | | TopLeft, |
50 | | TopRight, |
51 | | BottomRight, |
52 | | BottomLeft, |
53 | | } |
54 | | |
55 | | impl TgaOrientation { |
56 | 471 | fn from_image_desc_byte(value: u8) -> Self { |
57 | | // Set bits 4 and 5 indicates direction, if bit 4 is set then pixel order right -> left, |
58 | | // when bit 5 is set it indicates rows top -> bottom direction. |
59 | | // Sources: |
60 | | // https://en.wikipedia.org/wiki/Truevision_TGA ; Image specification (field 5) |
61 | 471 | if value & (1u8 << 4) == 0 { |
62 | | // Left -> Right |
63 | 209 | if value & (1u8 << 5) == 0 { |
64 | 198 | TgaOrientation::BottomLeft |
65 | | } else { |
66 | 11 | TgaOrientation::TopLeft |
67 | | } |
68 | | } else { |
69 | | // Right -> Left |
70 | 262 | if value & (1u8 << 5) == 0 { |
71 | 210 | TgaOrientation::BottomRight |
72 | | } else { |
73 | 52 | TgaOrientation::TopRight |
74 | | } |
75 | | } |
76 | 471 | } |
77 | | } |
78 | | |
79 | | impl<R: Read> TgaDecoder<R> { |
80 | | /// Create a new decoder that decodes from the stream `r` |
81 | 802 | pub fn new(mut r: R) -> ImageResult<TgaDecoder<R>> { |
82 | | // Read header |
83 | 802 | let header = Header::from_reader(&mut r)?; |
84 | 802 | let image_type = ImageType::new(header.image_type); |
85 | 802 | let width = header.image_width as usize; |
86 | 802 | let height = header.image_height as usize; |
87 | 802 | let raw_bytes_per_pixel = (header.pixel_depth as usize).div_ceil(8); |
88 | 802 | let num_alpha_bits = header.image_desc & ALPHA_BIT_MASK; |
89 | | |
90 | 802 | if width == 0 || height == 0 { |
91 | 6 | return Err(ImageError::Decoding(DecodingError::new( |
92 | 6 | ImageFormat::Tga.into(), |
93 | 6 | "Invalid empty image", |
94 | 6 | ))); |
95 | 796 | } |
96 | | |
97 | | // Validate header |
98 | 796 | if ![8, 16, 24, 32].contains(&header.pixel_depth) || ![0, 8].contains(&num_alpha_bits) { |
99 | 7 | return Err(ImageError::Unsupported( |
100 | 7 | UnsupportedError::from_format_and_kind( |
101 | 7 | ImageFormat::Tga.into(), |
102 | 7 | UnsupportedErrorKind::Color(ExtendedColorType::Unknown(header.pixel_depth)), |
103 | 7 | ), |
104 | 7 | )); |
105 | 789 | } |
106 | 789 | if image_type.is_color_mapped() { |
107 | 479 | if header.map_type != 1 { |
108 | 3 | return Err(ImageError::Decoding(DecodingError::new( |
109 | 3 | ImageFormat::Tga.into(), |
110 | 3 | "Color map type must be 1 for color mapped images", |
111 | 3 | ))); |
112 | 476 | } else if ![8, 16].contains(&header.pixel_depth) { |
113 | 4 | return Err(ImageError::Decoding(DecodingError::new( |
114 | 4 | ImageFormat::Tga.into(), |
115 | 4 | "Color map must use 1 or 2 byte indexes", |
116 | 4 | ))); |
117 | 472 | } else if header.pixel_depth > header.map_entry_size { |
118 | 2 | return Err(ImageError::Unsupported( |
119 | 2 | UnsupportedError::from_format_and_kind( |
120 | 2 | ImageFormat::Tga.into(), |
121 | 2 | UnsupportedErrorKind::GenericFeature( |
122 | 2 | "Indices larger than pixel values".into(), |
123 | 2 | ), |
124 | 2 | ), |
125 | 2 | )); |
126 | 470 | } |
127 | 310 | } |
128 | | |
129 | | // TODO: validate the rest of the fields in the header. |
130 | | |
131 | | // Read image ID (and ignore it) |
132 | 780 | let mut tmp = [0u8; 256]; |
133 | 780 | r.read_exact(&mut tmp[0..header.id_length as usize])?; |
134 | | |
135 | | // Read color map |
136 | 780 | let mut color_map = None; |
137 | 780 | if header.map_type == 1 { |
138 | 531 | let entry_size = (header.map_entry_size as usize).div_ceil(8); |
139 | 531 | if ![2, 3, 4].contains(&entry_size) { |
140 | 2 | return Err(ImageError::Unsupported( |
141 | 2 | UnsupportedError::from_format_and_kind( |
142 | 2 | ImageFormat::Tga.into(), |
143 | 2 | UnsupportedErrorKind::GenericFeature( |
144 | 2 | "Unsupported color map entry size".into(), |
145 | 2 | ), |
146 | 2 | ), |
147 | 2 | )); |
148 | 529 | } |
149 | | |
150 | 529 | let mut bytes = Vec::new(); |
151 | 529 | r.read_exact_vec(&mut bytes, entry_size * header.map_length as usize)?; |
152 | | |
153 | | // Color maps are technically allowed in non-color-mapped images, so check that we |
154 | | // actually need the color map before storing it. |
155 | 456 | if image_type.is_color_mapped() { |
156 | 413 | color_map = Some(ColorMap { |
157 | 413 | entry_size, |
158 | 413 | start_offset: header.map_origin as usize, |
159 | 413 | bytes, |
160 | 413 | }); |
161 | 413 | } |
162 | 249 | } |
163 | | |
164 | | // Compute output pixel depth |
165 | 705 | let total_pixel_bits = if header.map_type == 1 { |
166 | 456 | header.map_entry_size |
167 | | } else { |
168 | 249 | header.pixel_depth |
169 | | }; |
170 | 705 | let num_other_bits = total_pixel_bits |
171 | 705 | .checked_sub(num_alpha_bits) |
172 | 705 | .ok_or_else(|| { |
173 | 0 | ImageError::Decoding(DecodingError::new( |
174 | 0 | ImageFormat::Tga.into(), |
175 | 0 | "More alpha bits than pixel bits", |
176 | 0 | )) |
177 | 0 | })?; Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::new::{closure#0}Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::new::{closure#0}Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::new::{closure#0}Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::new::{closure#0}Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::new::{closure#0}Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::new::{closure#0}Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::new::{closure#0}Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::new::{closure#0}Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::new::{closure#0}Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::new::{closure#0}Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::new::{closure#0}Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::new::{closure#0} |
178 | | |
179 | | // Determine color type |
180 | | let color_type; |
181 | 705 | let mut original_color_type = None; |
182 | 705 | match (num_alpha_bits, num_other_bits, image_type.is_color()) { |
183 | | // really, the encoding is BGR and BGRA, this is fixed up with |
184 | | // `TgaDecoder::reverse_encoding`. |
185 | 155 | (0, 32, true) => color_type = ColorType::Rgba8, |
186 | 46 | (8, 24, true) => color_type = ColorType::Rgba8, |
187 | 292 | (0, 24, true) => color_type = ColorType::Rgb8, |
188 | 29 | (8, 8, false) => color_type = ColorType::La8, |
189 | 42 | (0, 8, false) => color_type = ColorType::L8, |
190 | 102 | (8, 0, false) => { |
191 | 102 | // alpha-only image is treated as L8 |
192 | 102 | color_type = ColorType::L8; |
193 | 102 | original_color_type = Some(ExtendedColorType::A8); |
194 | 102 | } |
195 | | _ => { |
196 | 39 | return Err(ImageError::Unsupported( |
197 | 39 | UnsupportedError::from_format_and_kind( |
198 | 39 | ImageFormat::Tga.into(), |
199 | 39 | UnsupportedErrorKind::Color(ExtendedColorType::Unknown(header.pixel_depth)), |
200 | 39 | ), |
201 | 39 | )) |
202 | | } |
203 | | } |
204 | | |
205 | 666 | Ok(TgaDecoder { |
206 | 666 | r, |
207 | 666 | |
208 | 666 | width, |
209 | 666 | height, |
210 | 666 | raw_bytes_per_pixel, |
211 | 666 | |
212 | 666 | image_type, |
213 | 666 | color_type, |
214 | 666 | original_color_type, |
215 | 666 | |
216 | 666 | header, |
217 | 666 | color_map, |
218 | 666 | }) |
219 | 802 | } Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::new Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::new Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::new Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::new Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::new Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::new Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::new Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::new Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::new Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::new Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::new <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::new Line | Count | Source | 81 | 802 | pub fn new(mut r: R) -> ImageResult<TgaDecoder<R>> { | 82 | | // Read header | 83 | 802 | let header = Header::from_reader(&mut r)?; | 84 | 802 | let image_type = ImageType::new(header.image_type); | 85 | 802 | let width = header.image_width as usize; | 86 | 802 | let height = header.image_height as usize; | 87 | 802 | let raw_bytes_per_pixel = (header.pixel_depth as usize).div_ceil(8); | 88 | 802 | let num_alpha_bits = header.image_desc & ALPHA_BIT_MASK; | 89 | | | 90 | 802 | if width == 0 || height == 0 { | 91 | 6 | return Err(ImageError::Decoding(DecodingError::new( | 92 | 6 | ImageFormat::Tga.into(), | 93 | 6 | "Invalid empty image", | 94 | 6 | ))); | 95 | 796 | } | 96 | | | 97 | | // Validate header | 98 | 796 | if ![8, 16, 24, 32].contains(&header.pixel_depth) || ![0, 8].contains(&num_alpha_bits) { | 99 | 7 | return Err(ImageError::Unsupported( | 100 | 7 | UnsupportedError::from_format_and_kind( | 101 | 7 | ImageFormat::Tga.into(), | 102 | 7 | UnsupportedErrorKind::Color(ExtendedColorType::Unknown(header.pixel_depth)), | 103 | 7 | ), | 104 | 7 | )); | 105 | 789 | } | 106 | 789 | if image_type.is_color_mapped() { | 107 | 479 | if header.map_type != 1 { | 108 | 3 | return Err(ImageError::Decoding(DecodingError::new( | 109 | 3 | ImageFormat::Tga.into(), | 110 | 3 | "Color map type must be 1 for color mapped images", | 111 | 3 | ))); | 112 | 476 | } else if ![8, 16].contains(&header.pixel_depth) { | 113 | 4 | return Err(ImageError::Decoding(DecodingError::new( | 114 | 4 | ImageFormat::Tga.into(), | 115 | 4 | "Color map must use 1 or 2 byte indexes", | 116 | 4 | ))); | 117 | 472 | } else if header.pixel_depth > header.map_entry_size { | 118 | 2 | return Err(ImageError::Unsupported( | 119 | 2 | UnsupportedError::from_format_and_kind( | 120 | 2 | ImageFormat::Tga.into(), | 121 | 2 | UnsupportedErrorKind::GenericFeature( | 122 | 2 | "Indices larger than pixel values".into(), | 123 | 2 | ), | 124 | 2 | ), | 125 | 2 | )); | 126 | 470 | } | 127 | 310 | } | 128 | | | 129 | | // TODO: validate the rest of the fields in the header. | 130 | | | 131 | | // Read image ID (and ignore it) | 132 | 780 | let mut tmp = [0u8; 256]; | 133 | 780 | r.read_exact(&mut tmp[0..header.id_length as usize])?; | 134 | | | 135 | | // Read color map | 136 | 780 | let mut color_map = None; | 137 | 780 | if header.map_type == 1 { | 138 | 531 | let entry_size = (header.map_entry_size as usize).div_ceil(8); | 139 | 531 | if ![2, 3, 4].contains(&entry_size) { | 140 | 2 | return Err(ImageError::Unsupported( | 141 | 2 | UnsupportedError::from_format_and_kind( | 142 | 2 | ImageFormat::Tga.into(), | 143 | 2 | UnsupportedErrorKind::GenericFeature( | 144 | 2 | "Unsupported color map entry size".into(), | 145 | 2 | ), | 146 | 2 | ), | 147 | 2 | )); | 148 | 529 | } | 149 | | | 150 | 529 | let mut bytes = Vec::new(); | 151 | 529 | r.read_exact_vec(&mut bytes, entry_size * header.map_length as usize)?; | 152 | | | 153 | | // Color maps are technically allowed in non-color-mapped images, so check that we | 154 | | // actually need the color map before storing it. | 155 | 456 | if image_type.is_color_mapped() { | 156 | 413 | color_map = Some(ColorMap { | 157 | 413 | entry_size, | 158 | 413 | start_offset: header.map_origin as usize, | 159 | 413 | bytes, | 160 | 413 | }); | 161 | 413 | } | 162 | 249 | } | 163 | | | 164 | | // Compute output pixel depth | 165 | 705 | let total_pixel_bits = if header.map_type == 1 { | 166 | 456 | header.map_entry_size | 167 | | } else { | 168 | 249 | header.pixel_depth | 169 | | }; | 170 | 705 | let num_other_bits = total_pixel_bits | 171 | 705 | .checked_sub(num_alpha_bits) | 172 | 705 | .ok_or_else(|| { | 173 | | ImageError::Decoding(DecodingError::new( | 174 | | ImageFormat::Tga.into(), | 175 | | "More alpha bits than pixel bits", | 176 | | )) | 177 | 0 | })?; | 178 | | | 179 | | // Determine color type | 180 | | let color_type; | 181 | 705 | let mut original_color_type = None; | 182 | 705 | match (num_alpha_bits, num_other_bits, image_type.is_color()) { | 183 | | // really, the encoding is BGR and BGRA, this is fixed up with | 184 | | // `TgaDecoder::reverse_encoding`. | 185 | 155 | (0, 32, true) => color_type = ColorType::Rgba8, | 186 | 46 | (8, 24, true) => color_type = ColorType::Rgba8, | 187 | 292 | (0, 24, true) => color_type = ColorType::Rgb8, | 188 | 29 | (8, 8, false) => color_type = ColorType::La8, | 189 | 42 | (0, 8, false) => color_type = ColorType::L8, | 190 | 102 | (8, 0, false) => { | 191 | 102 | // alpha-only image is treated as L8 | 192 | 102 | color_type = ColorType::L8; | 193 | 102 | original_color_type = Some(ExtendedColorType::A8); | 194 | 102 | } | 195 | | _ => { | 196 | 39 | return Err(ImageError::Unsupported( | 197 | 39 | UnsupportedError::from_format_and_kind( | 198 | 39 | ImageFormat::Tga.into(), | 199 | 39 | UnsupportedErrorKind::Color(ExtendedColorType::Unknown(header.pixel_depth)), | 200 | 39 | ), | 201 | 39 | )) | 202 | | } | 203 | | } | 204 | | | 205 | 666 | Ok(TgaDecoder { | 206 | 666 | r, | 207 | 666 | | 208 | 666 | width, | 209 | 666 | height, | 210 | 666 | raw_bytes_per_pixel, | 211 | 666 | | 212 | 666 | image_type, | 213 | 666 | color_type, | 214 | 666 | original_color_type, | 215 | 666 | | 216 | 666 | header, | 217 | 666 | color_map, | 218 | 666 | }) | 219 | 802 | } |
|
220 | | |
221 | | /// Reads a run length encoded data for given number of bytes |
222 | 543 | fn read_encoded_data(&mut self, buf: &mut [u8]) -> io::Result<()> { |
223 | 543 | assert!(self.raw_bytes_per_pixel <= 4); |
224 | 543 | let mut repeat_buf = [0; 4]; |
225 | 543 | let repeat_buf = &mut repeat_buf[..self.raw_bytes_per_pixel]; |
226 | | |
227 | 543 | let mut index = 0; |
228 | 946k | while index < buf.len() { |
229 | 946k | let run_packet = self.r.read_u8()?; |
230 | | // If the highest bit in `run_packet` is set, then we repeat pixels |
231 | | // |
232 | | // Note: the TGA format adds 1 to both counts because having a count |
233 | | // of 0 would be pointless. |
234 | 946k | if (run_packet & 0x80) != 0 { |
235 | | // high bit set, so we will repeat the data |
236 | 427k | let repeat_count = ((run_packet & !0x80) + 1) as usize; |
237 | 427k | self.r.read_exact(repeat_buf)?; |
238 | | |
239 | 46.0M | for chunk in buf[index..] |
240 | 427k | .chunks_exact_mut(self.raw_bytes_per_pixel) |
241 | 427k | .take(repeat_count) |
242 | 46.0M | { |
243 | 46.0M | chunk.copy_from_slice(repeat_buf); |
244 | 46.0M | } |
245 | 427k | index += repeat_count * self.raw_bytes_per_pixel; |
246 | | } else { |
247 | | // not set, so `run_packet+1` is the number of non-encoded pixels |
248 | 518k | let num_raw_bytes = |
249 | 518k | ((run_packet + 1) as usize * self.raw_bytes_per_pixel).min(buf.len() - index); |
250 | | |
251 | 518k | self.r.read_exact(&mut buf[index..][..num_raw_bytes])?; |
252 | 518k | index += num_raw_bytes; |
253 | | } |
254 | | } |
255 | | |
256 | 395 | Ok(()) |
257 | 543 | } Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::read_encoded_data Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::read_encoded_data Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::read_encoded_data Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::read_encoded_data Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::read_encoded_data Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::read_encoded_data Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::read_encoded_data Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::read_encoded_data Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::read_encoded_data Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::read_encoded_data Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::read_encoded_data <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::read_encoded_data Line | Count | Source | 222 | 543 | fn read_encoded_data(&mut self, buf: &mut [u8]) -> io::Result<()> { | 223 | 543 | assert!(self.raw_bytes_per_pixel <= 4); | 224 | 543 | let mut repeat_buf = [0; 4]; | 225 | 543 | let repeat_buf = &mut repeat_buf[..self.raw_bytes_per_pixel]; | 226 | | | 227 | 543 | let mut index = 0; | 228 | 946k | while index < buf.len() { | 229 | 946k | let run_packet = self.r.read_u8()?; | 230 | | // If the highest bit in `run_packet` is set, then we repeat pixels | 231 | | // | 232 | | // Note: the TGA format adds 1 to both counts because having a count | 233 | | // of 0 would be pointless. | 234 | 946k | if (run_packet & 0x80) != 0 { | 235 | | // high bit set, so we will repeat the data | 236 | 427k | let repeat_count = ((run_packet & !0x80) + 1) as usize; | 237 | 427k | self.r.read_exact(repeat_buf)?; | 238 | | | 239 | 46.0M | for chunk in buf[index..] | 240 | 427k | .chunks_exact_mut(self.raw_bytes_per_pixel) | 241 | 427k | .take(repeat_count) | 242 | 46.0M | { | 243 | 46.0M | chunk.copy_from_slice(repeat_buf); | 244 | 46.0M | } | 245 | 427k | index += repeat_count * self.raw_bytes_per_pixel; | 246 | | } else { | 247 | | // not set, so `run_packet+1` is the number of non-encoded pixels | 248 | 518k | let num_raw_bytes = | 249 | 518k | ((run_packet + 1) as usize * self.raw_bytes_per_pixel).min(buf.len() - index); | 250 | | | 251 | 518k | self.r.read_exact(&mut buf[index..][..num_raw_bytes])?; | 252 | 518k | index += num_raw_bytes; | 253 | | } | 254 | | } | 255 | | | 256 | 395 | Ok(()) | 257 | 543 | } |
|
258 | | |
259 | | /// Expands indices into its mapped color |
260 | 288 | fn expand_color_map( |
261 | 288 | &self, |
262 | 288 | input: &[u8], |
263 | 288 | output: &mut [u8], |
264 | 288 | color_map: &ColorMap, |
265 | 288 | ) -> ImageResult<()> { |
266 | 288 | if self.raw_bytes_per_pixel == 1 { |
267 | 1.94M | for (&index, chunk) in input |
268 | 156 | .iter() |
269 | 156 | .zip(output.chunks_exact_mut(color_map.entry_size)) |
270 | | { |
271 | 1.94M | if let Some(color) = color_map.get(index as usize) { |
272 | 1.94M | chunk.copy_from_slice(color); |
273 | 1.94M | } else { |
274 | 126 | return Err(ImageError::Decoding(DecodingError::new( |
275 | 126 | ImageFormat::Tga.into(), |
276 | 126 | "Invalid color map index", |
277 | 126 | ))); |
278 | | } |
279 | | } |
280 | 132 | } else if self.raw_bytes_per_pixel == 2 { |
281 | 12.5k | for (index, chunk) in input |
282 | 132 | .chunks_exact(2) |
283 | 132 | .zip(output.chunks_exact_mut(color_map.entry_size)) |
284 | | { |
285 | 12.5k | let index = u16::from_le_bytes(index.try_into().unwrap()); |
286 | 12.5k | if let Some(color) = color_map.get(index as usize) { |
287 | 12.4k | chunk.copy_from_slice(color); |
288 | 12.4k | } else { |
289 | 110 | return Err(ImageError::Decoding(DecodingError::new( |
290 | 110 | ImageFormat::Tga.into(), |
291 | 110 | "Invalid color map index", |
292 | 110 | ))); |
293 | | } |
294 | | } |
295 | | } else { |
296 | 0 | unreachable!("Supported bytes_per_pixel values are checked in TgaDecoder::new"); |
297 | | } |
298 | | |
299 | 52 | Ok(()) |
300 | 288 | } Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::expand_color_map Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::expand_color_map Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::expand_color_map Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::expand_color_map Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::expand_color_map Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::expand_color_map Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::expand_color_map Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::expand_color_map Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::expand_color_map Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::expand_color_map Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::expand_color_map <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::expand_color_map Line | Count | Source | 260 | 288 | fn expand_color_map( | 261 | 288 | &self, | 262 | 288 | input: &[u8], | 263 | 288 | output: &mut [u8], | 264 | 288 | color_map: &ColorMap, | 265 | 288 | ) -> ImageResult<()> { | 266 | 288 | if self.raw_bytes_per_pixel == 1 { | 267 | 1.94M | for (&index, chunk) in input | 268 | 156 | .iter() | 269 | 156 | .zip(output.chunks_exact_mut(color_map.entry_size)) | 270 | | { | 271 | 1.94M | if let Some(color) = color_map.get(index as usize) { | 272 | 1.94M | chunk.copy_from_slice(color); | 273 | 1.94M | } else { | 274 | 126 | return Err(ImageError::Decoding(DecodingError::new( | 275 | 126 | ImageFormat::Tga.into(), | 276 | 126 | "Invalid color map index", | 277 | 126 | ))); | 278 | | } | 279 | | } | 280 | 132 | } else if self.raw_bytes_per_pixel == 2 { | 281 | 12.5k | for (index, chunk) in input | 282 | 132 | .chunks_exact(2) | 283 | 132 | .zip(output.chunks_exact_mut(color_map.entry_size)) | 284 | | { | 285 | 12.5k | let index = u16::from_le_bytes(index.try_into().unwrap()); | 286 | 12.5k | if let Some(color) = color_map.get(index as usize) { | 287 | 12.4k | chunk.copy_from_slice(color); | 288 | 12.4k | } else { | 289 | 110 | return Err(ImageError::Decoding(DecodingError::new( | 290 | 110 | ImageFormat::Tga.into(), | 291 | 110 | "Invalid color map index", | 292 | 110 | ))); | 293 | | } | 294 | | } | 295 | | } else { | 296 | 0 | unreachable!("Supported bytes_per_pixel values are checked in TgaDecoder::new"); | 297 | | } | 298 | | | 299 | 52 | Ok(()) | 300 | 288 | } |
|
301 | | |
302 | | /// Reverse from BGR encoding to RGB encoding |
303 | | /// |
304 | | /// TGA files are stored in the BGRA encoding. This function swaps |
305 | | /// the blue and red bytes in the `pixels` array. |
306 | 235 | fn reverse_encoding_in_output(&mut self, pixels: &mut [u8]) { |
307 | | // We only need to reverse the encoding of color images |
308 | 235 | match self.color_type { |
309 | | ColorType::Rgb8 | ColorType::Rgba8 => { |
310 | 5.22M | for chunk in pixels.chunks_mut(self.color_type.bytes_per_pixel().into()) { |
311 | 5.22M | chunk.swap(0, 2); |
312 | 5.22M | } |
313 | | } |
314 | 106 | _ => {} |
315 | | } |
316 | 235 | } Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::reverse_encoding_in_output Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::reverse_encoding_in_output Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::reverse_encoding_in_output Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::reverse_encoding_in_output Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::reverse_encoding_in_output Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::reverse_encoding_in_output Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::reverse_encoding_in_output Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::reverse_encoding_in_output Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::reverse_encoding_in_output Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::reverse_encoding_in_output Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::reverse_encoding_in_output <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::reverse_encoding_in_output Line | Count | Source | 306 | 235 | fn reverse_encoding_in_output(&mut self, pixels: &mut [u8]) { | 307 | | // We only need to reverse the encoding of color images | 308 | 235 | match self.color_type { | 309 | | ColorType::Rgb8 | ColorType::Rgba8 => { | 310 | 5.22M | for chunk in pixels.chunks_mut(self.color_type.bytes_per_pixel().into()) { | 311 | 5.22M | chunk.swap(0, 2); | 312 | 5.22M | } | 313 | | } | 314 | 106 | _ => {} | 315 | | } | 316 | 235 | } |
|
317 | | |
318 | | /// Change image orientation depending on the flags set |
319 | 471 | fn fixup_orientation(&mut self, pixels: &mut [u8]) { |
320 | 471 | let orientation = TgaOrientation::from_image_desc_byte(self.header.image_desc); |
321 | | |
322 | | // Flip image if bottom->top direction |
323 | 471 | if (orientation == TgaOrientation::BottomLeft || orientation == TgaOrientation::BottomRight) |
324 | 408 | && self.height > 1 |
325 | | { |
326 | 257 | let row_stride = self.width * self.raw_bytes_per_pixel; |
327 | | |
328 | 257 | let (left_part, right_part) = pixels.split_at_mut(self.height / 2 * row_stride); |
329 | | |
330 | 407k | for (src, dst) in left_part |
331 | 257 | .chunks_exact_mut(row_stride) |
332 | 257 | .zip(right_part.chunks_exact_mut(row_stride).rev()) |
333 | | { |
334 | 15.8M | for (src, dst) in src.iter_mut().zip(dst.iter_mut()) { |
335 | 15.8M | std::mem::swap(src, dst); |
336 | 15.8M | } |
337 | | } |
338 | 214 | } |
339 | | |
340 | | // Flop image if right->left direction |
341 | 471 | if (orientation == TgaOrientation::BottomRight || orientation == TgaOrientation::TopRight) |
342 | 262 | && self.width > 1 |
343 | | { |
344 | 245k | for row in pixels.chunks_exact_mut(self.width * self.raw_bytes_per_pixel) { |
345 | 245k | let (left_part, right_part) = |
346 | 245k | row.split_at_mut(self.width / 2 * self.raw_bytes_per_pixel); |
347 | 5.31M | for (src, dst) in left_part |
348 | 245k | .chunks_exact_mut(self.raw_bytes_per_pixel) |
349 | 245k | .zip(right_part.chunks_exact_mut(self.raw_bytes_per_pixel).rev()) |
350 | | { |
351 | 7.63M | for (src, dst) in src.iter_mut().zip(dst.iter_mut()) { |
352 | 7.63M | std::mem::swap(dst, src); |
353 | 7.63M | } |
354 | | } |
355 | | } |
356 | 237 | } |
357 | 471 | } Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::fixup_orientation Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::fixup_orientation Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::fixup_orientation Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::fixup_orientation Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::fixup_orientation Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::fixup_orientation Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::fixup_orientation Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::fixup_orientation Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::fixup_orientation Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::fixup_orientation Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::fixup_orientation <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>>>::fixup_orientation Line | Count | Source | 319 | 471 | fn fixup_orientation(&mut self, pixels: &mut [u8]) { | 320 | 471 | let orientation = TgaOrientation::from_image_desc_byte(self.header.image_desc); | 321 | | | 322 | | // Flip image if bottom->top direction | 323 | 471 | if (orientation == TgaOrientation::BottomLeft || orientation == TgaOrientation::BottomRight) | 324 | 408 | && self.height > 1 | 325 | | { | 326 | 257 | let row_stride = self.width * self.raw_bytes_per_pixel; | 327 | | | 328 | 257 | let (left_part, right_part) = pixels.split_at_mut(self.height / 2 * row_stride); | 329 | | | 330 | 407k | for (src, dst) in left_part | 331 | 257 | .chunks_exact_mut(row_stride) | 332 | 257 | .zip(right_part.chunks_exact_mut(row_stride).rev()) | 333 | | { | 334 | 15.8M | for (src, dst) in src.iter_mut().zip(dst.iter_mut()) { | 335 | 15.8M | std::mem::swap(src, dst); | 336 | 15.8M | } | 337 | | } | 338 | 214 | } | 339 | | | 340 | | // Flop image if right->left direction | 341 | 471 | if (orientation == TgaOrientation::BottomRight || orientation == TgaOrientation::TopRight) | 342 | 262 | && self.width > 1 | 343 | | { | 344 | 245k | for row in pixels.chunks_exact_mut(self.width * self.raw_bytes_per_pixel) { | 345 | 245k | let (left_part, right_part) = | 346 | 245k | row.split_at_mut(self.width / 2 * self.raw_bytes_per_pixel); | 347 | 5.31M | for (src, dst) in left_part | 348 | 245k | .chunks_exact_mut(self.raw_bytes_per_pixel) | 349 | 245k | .zip(right_part.chunks_exact_mut(self.raw_bytes_per_pixel).rev()) | 350 | | { | 351 | 7.63M | for (src, dst) in src.iter_mut().zip(dst.iter_mut()) { | 352 | 7.63M | std::mem::swap(dst, src); | 353 | 7.63M | } | 354 | | } | 355 | | } | 356 | 237 | } | 357 | 471 | } |
|
358 | | } |
359 | | |
360 | | impl<R: Read> ImageDecoder for TgaDecoder<R> { |
361 | 1.93k | fn dimensions(&self) -> (u32, u32) { |
362 | 1.93k | (self.width as u32, self.height as u32) |
363 | 1.93k | } Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::dimensions Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::dimensions Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::dimensions Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::dimensions Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::dimensions Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::dimensions Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::dimensions Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::dimensions Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::dimensions Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::dimensions Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::dimensions <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::dimensions Line | Count | Source | 361 | 1.93k | fn dimensions(&self) -> (u32, u32) { | 362 | 1.93k | (self.width as u32, self.height as u32) | 363 | 1.93k | } |
|
364 | | |
365 | 1.93k | fn color_type(&self) -> ColorType { |
366 | 1.93k | self.color_type |
367 | 1.93k | } Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::color_type Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::color_type Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::color_type Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::color_type Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::color_type Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::color_type Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::color_type Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::color_type Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::color_type Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::color_type Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::color_type <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::color_type Line | Count | Source | 365 | 1.93k | fn color_type(&self) -> ColorType { | 366 | 1.93k | self.color_type | 367 | 1.93k | } |
|
368 | | |
369 | 0 | fn original_color_type(&self) -> ExtendedColorType { |
370 | 0 | self.original_color_type |
371 | 0 | .unwrap_or_else(|| self.color_type().into()) Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::original_color_type::{closure#0}Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::original_color_type::{closure#0}Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::original_color_type::{closure#0}Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::original_color_type::{closure#0}Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::original_color_type::{closure#0}Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::original_color_type::{closure#0}Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::original_color_type::{closure#0}Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::original_color_type::{closure#0}Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::original_color_type::{closure#0}Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::original_color_type::{closure#0}Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::original_color_type::{closure#0} |
372 | 0 | } Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::original_color_type Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::original_color_type Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::original_color_type Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::original_color_type Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::original_color_type Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::original_color_type Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::original_color_type Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::original_color_type Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::original_color_type Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::original_color_type Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::original_color_type |
373 | | |
374 | 636 | fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> { |
375 | 636 | assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes())); |
376 | | |
377 | | // Decode the raw data |
378 | | // |
379 | | // We have already checked in `TgaDecoder::new` that the indices take less space than the |
380 | | // pixels they encode, so it is safe to read the raw data into `buf`. |
381 | 636 | let num_raw_bytes = self.width * self.height * self.raw_bytes_per_pixel; |
382 | 636 | if self.image_type.is_encoded() { |
383 | 543 | self.read_encoded_data(&mut buf[..num_raw_bytes])?; |
384 | | } else { |
385 | 93 | self.r.read_exact(&mut buf[..num_raw_bytes])?; |
386 | | } |
387 | | |
388 | 471 | self.fixup_orientation(&mut buf[..num_raw_bytes]); |
389 | | |
390 | | // Expand the indices using the color map if necessary |
391 | 471 | if let Some(ref color_map) = self.color_map { |
392 | | // This allocation could be avoided by expanding each row (or block of pixels) as it is |
393 | | // read, or by doing the color map expansion in-place. But those may be more effort than |
394 | | // it is worth. |
395 | 288 | let mut rawbuf = vec_try_with_capacity(num_raw_bytes)?; |
396 | 288 | rawbuf.extend_from_slice(&buf[..num_raw_bytes]); |
397 | | |
398 | 288 | self.expand_color_map(&rawbuf, buf, color_map)?; |
399 | 183 | } |
400 | | |
401 | 235 | self.reverse_encoding_in_output(buf); |
402 | | |
403 | 235 | Ok(()) |
404 | 636 | } Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image Line | Count | Source | 374 | 636 | fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> { | 375 | 636 | assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes())); | 376 | | | 377 | | // Decode the raw data | 378 | | // | 379 | | // We have already checked in `TgaDecoder::new` that the indices take less space than the | 380 | | // pixels they encode, so it is safe to read the raw data into `buf`. | 381 | 636 | let num_raw_bytes = self.width * self.height * self.raw_bytes_per_pixel; | 382 | 636 | if self.image_type.is_encoded() { | 383 | 543 | self.read_encoded_data(&mut buf[..num_raw_bytes])?; | 384 | | } else { | 385 | 93 | self.r.read_exact(&mut buf[..num_raw_bytes])?; | 386 | | } | 387 | | | 388 | 471 | self.fixup_orientation(&mut buf[..num_raw_bytes]); | 389 | | | 390 | | // Expand the indices using the color map if necessary | 391 | 471 | if let Some(ref color_map) = self.color_map { | 392 | | // This allocation could be avoided by expanding each row (or block of pixels) as it is | 393 | | // read, or by doing the color map expansion in-place. But those may be more effort than | 394 | | // it is worth. | 395 | 288 | let mut rawbuf = vec_try_with_capacity(num_raw_bytes)?; | 396 | 288 | rawbuf.extend_from_slice(&buf[..num_raw_bytes]); | 397 | | | 398 | 288 | self.expand_color_map(&rawbuf, buf, color_map)?; | 399 | 183 | } | 400 | | | 401 | 235 | self.reverse_encoding_in_output(buf); | 402 | | | 403 | 235 | Ok(()) | 404 | 636 | } |
|
405 | | |
406 | 0 | fn read_image_boxed(self: Box<Self>, buf: &mut [u8]) -> ImageResult<()> { |
407 | 0 | (*self).read_image(buf) |
408 | 0 | } Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image_boxed Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image_boxed Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image_boxed Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image_boxed Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image_boxed Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image_boxed Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image_boxed Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image_boxed Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image_boxed Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image_boxed Unexecuted instantiation: <image::codecs::tga::decoder::TgaDecoder<std::io::cursor::Cursor<&[u8]>> as image::io::decoder::ImageDecoder>::read_image_boxed |
409 | | } |