Coverage Report

Created: 2025-11-05 08:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}