image/codecs/tga/
decoder.rs

1use super::header::{Header, ImageType, ALPHA_BIT_MASK, SCREEN_ORIGIN_BIT_MASK};
2use crate::{
3    color::{ColorType, ExtendedColorType},
4    error::{
5        ImageError, ImageResult, LimitError, LimitErrorKind, UnsupportedError, UnsupportedErrorKind,
6    },
7    image::{ImageDecoder, ImageFormat},
8};
9use byteorder_lite::ReadBytesExt;
10use std::io::{self, Read};
11
12struct ColorMap {
13    /// sizes in bytes
14    start_offset: usize,
15    entry_size: usize,
16    bytes: Vec<u8>,
17}
18
19impl ColorMap {
20    pub(crate) fn from_reader(
21        r: &mut dyn Read,
22        start_offset: u16,
23        num_entries: u16,
24        bits_per_entry: u8,
25    ) -> ImageResult<ColorMap> {
26        let bytes_per_entry = (bits_per_entry as usize + 7) / 8;
27
28        let mut bytes = vec![0; bytes_per_entry * num_entries as usize];
29        r.read_exact(&mut bytes)?;
30
31        Ok(ColorMap {
32            entry_size: bytes_per_entry,
33            start_offset: start_offset as usize,
34            bytes,
35        })
36    }
37
38    /// Get one entry from the color map
39    pub(crate) fn get(&self, index: usize) -> Option<&[u8]> {
40        let entry = self.start_offset + self.entry_size * index;
41        self.bytes.get(entry..entry + self.entry_size)
42    }
43}
44
45/// The representation of a TGA decoder
46pub struct TgaDecoder<R> {
47    r: R,
48
49    width: usize,
50    height: usize,
51    bytes_per_pixel: usize,
52    has_loaded_metadata: bool,
53
54    image_type: ImageType,
55    color_type: ColorType,
56    original_color_type: Option<ExtendedColorType>,
57
58    header: Header,
59    color_map: Option<ColorMap>,
60}
61
62impl<R: Read> TgaDecoder<R> {
63    /// Create a new decoder that decodes from the stream `r`
64    pub fn new(r: R) -> ImageResult<TgaDecoder<R>> {
65        let mut decoder = TgaDecoder {
66            r,
67
68            width: 0,
69            height: 0,
70            bytes_per_pixel: 0,
71            has_loaded_metadata: false,
72
73            image_type: ImageType::Unknown,
74            color_type: ColorType::L8,
75            original_color_type: None,
76
77            header: Header::default(),
78            color_map: None,
79        };
80        decoder.read_metadata()?;
81        Ok(decoder)
82    }
83
84    fn read_header(&mut self) -> ImageResult<()> {
85        self.header = Header::from_reader(&mut self.r)?;
86        self.image_type = ImageType::new(self.header.image_type);
87        self.width = self.header.image_width as usize;
88        self.height = self.header.image_height as usize;
89        self.bytes_per_pixel = (self.header.pixel_depth as usize + 7) / 8;
90        Ok(())
91    }
92
93    fn read_metadata(&mut self) -> ImageResult<()> {
94        if !self.has_loaded_metadata {
95            self.read_header()?;
96            self.read_image_id()?;
97            self.read_color_map()?;
98            self.read_color_information()?;
99            self.has_loaded_metadata = true;
100        }
101        Ok(())
102    }
103
104    /// Loads the color information for the decoder
105    ///
106    /// To keep things simple, we won't handle bit depths that aren't divisible
107    /// by 8 and are larger than 32.
108    fn read_color_information(&mut self) -> ImageResult<()> {
109        if self.header.pixel_depth % 8 != 0 || self.header.pixel_depth > 32 {
110            // Bit depth must be divisible by 8, and must be less than or equal
111            // to 32.
112            return Err(ImageError::Unsupported(
113                UnsupportedError::from_format_and_kind(
114                    ImageFormat::Tga.into(),
115                    UnsupportedErrorKind::Color(ExtendedColorType::Unknown(
116                        self.header.pixel_depth,
117                    )),
118                ),
119            ));
120        }
121
122        let num_alpha_bits = self.header.image_desc & ALPHA_BIT_MASK;
123
124        let other_channel_bits = if self.header.map_type != 0 {
125            self.header.map_entry_size
126        } else {
127            if num_alpha_bits > self.header.pixel_depth {
128                return Err(ImageError::Unsupported(
129                    UnsupportedError::from_format_and_kind(
130                        ImageFormat::Tga.into(),
131                        UnsupportedErrorKind::Color(ExtendedColorType::Unknown(
132                            self.header.pixel_depth,
133                        )),
134                    ),
135                ));
136            }
137
138            self.header.pixel_depth - num_alpha_bits
139        };
140        let color = self.image_type.is_color();
141
142        match (num_alpha_bits, other_channel_bits, color) {
143            // really, the encoding is BGR and BGRA, this is fixed
144            // up with `TgaDecoder::reverse_encoding`.
145            (0, 32, true) => self.color_type = ColorType::Rgba8,
146            (8, 24, true) => self.color_type = ColorType::Rgba8,
147            (0, 24, true) => self.color_type = ColorType::Rgb8,
148            (8, 8, false) => self.color_type = ColorType::La8,
149            (0, 8, false) => self.color_type = ColorType::L8,
150            (8, 0, false) => {
151                // alpha-only image is treated as L8
152                self.color_type = ColorType::L8;
153                self.original_color_type = Some(ExtendedColorType::A8);
154            }
155            _ => {
156                return Err(ImageError::Unsupported(
157                    UnsupportedError::from_format_and_kind(
158                        ImageFormat::Tga.into(),
159                        UnsupportedErrorKind::Color(ExtendedColorType::Unknown(
160                            self.header.pixel_depth,
161                        )),
162                    ),
163                ))
164            }
165        }
166        Ok(())
167    }
168
169    /// Read the image id field
170    ///
171    /// We're not interested in this field, so this function skips it if it
172    /// is present
173    fn read_image_id(&mut self) -> ImageResult<()> {
174        self.r
175            .read_exact(&mut vec![0; self.header.id_length as usize])?;
176        Ok(())
177    }
178
179    fn read_color_map(&mut self) -> ImageResult<()> {
180        if self.header.map_type == 1 {
181            // FIXME: we could reverse the map entries, which avoids having to reverse all pixels
182            // in the final output individually.
183            self.color_map = Some(ColorMap::from_reader(
184                &mut self.r,
185                self.header.map_origin,
186                self.header.map_length,
187                self.header.map_entry_size,
188            )?);
189        }
190        Ok(())
191    }
192
193    /// Expands indices into its mapped color
194    fn expand_color_map(&self, pixel_data: &[u8]) -> io::Result<Vec<u8>> {
195        #[inline]
196        fn bytes_to_index(bytes: &[u8]) -> usize {
197            let mut result = 0usize;
198            for byte in bytes {
199                result = (result << 8) | *byte as usize;
200            }
201            result
202        }
203
204        let bytes_per_entry = (self.header.map_entry_size as usize + 7) / 8;
205        let mut result = Vec::with_capacity(self.width * self.height * bytes_per_entry);
206
207        if self.bytes_per_pixel == 0 {
208            return Err(io::ErrorKind::Other.into());
209        }
210
211        let color_map = self
212            .color_map
213            .as_ref()
214            .ok_or_else(|| io::Error::from(io::ErrorKind::Other))?;
215
216        for chunk in pixel_data.chunks(self.bytes_per_pixel) {
217            let index = bytes_to_index(chunk);
218            if let Some(color) = color_map.get(index) {
219                result.extend_from_slice(color);
220            } else {
221                return Err(io::ErrorKind::Other.into());
222            }
223        }
224
225        Ok(result)
226    }
227
228    /// Reads a run length encoded data for given number of bytes
229    fn read_encoded_data(&mut self, num_bytes: usize) -> io::Result<Vec<u8>> {
230        let mut pixel_data = Vec::with_capacity(num_bytes);
231        let mut repeat_buf = Vec::with_capacity(self.bytes_per_pixel);
232
233        while pixel_data.len() < num_bytes {
234            let run_packet = self.r.read_u8()?;
235            // If the highest bit in `run_packet` is set, then we repeat pixels
236            //
237            // Note: the TGA format adds 1 to both counts because having a count
238            // of 0 would be pointless.
239            if (run_packet & 0x80) != 0 {
240                // high bit set, so we will repeat the data
241                let repeat_count = ((run_packet & !0x80) + 1) as usize;
242                self.r
243                    .by_ref()
244                    .take(self.bytes_per_pixel as u64)
245                    .read_to_end(&mut repeat_buf)?;
246
247                // get the repeating pixels from the bytes of the pixel stored in `repeat_buf`
248                let data = repeat_buf
249                    .iter()
250                    .cycle()
251                    .take(repeat_count * self.bytes_per_pixel);
252                pixel_data.extend(data);
253                repeat_buf.clear();
254            } else {
255                // not set, so `run_packet+1` is the number of non-encoded pixels
256                let num_raw_bytes = (run_packet + 1) as usize * self.bytes_per_pixel;
257                self.r
258                    .by_ref()
259                    .take(num_raw_bytes as u64)
260                    .read_to_end(&mut pixel_data)?;
261            }
262        }
263
264        if pixel_data.len() > num_bytes {
265            // FIXME: the last packet contained more data than we asked for!
266            // This is at least a warning. We truncate the data since some methods rely on the
267            // length to be accurate in the success case.
268            pixel_data.truncate(num_bytes);
269        }
270
271        Ok(pixel_data)
272    }
273
274    /// Reads a run length encoded packet
275    fn read_all_encoded_data(&mut self) -> ImageResult<Vec<u8>> {
276        let num_bytes = self.width * self.height * self.bytes_per_pixel;
277
278        Ok(self.read_encoded_data(num_bytes)?)
279    }
280
281    /// Reverse from BGR encoding to RGB encoding
282    ///
283    /// TGA files are stored in the BGRA encoding. This function swaps
284    /// the blue and red bytes in the `pixels` array.
285    fn reverse_encoding_in_output(&mut self, pixels: &mut [u8]) {
286        // We only need to reverse the encoding of color images
287        match self.color_type {
288            ColorType::Rgb8 | ColorType::Rgba8 => {
289                for chunk in pixels.chunks_mut(self.color_type.bytes_per_pixel().into()) {
290                    chunk.swap(0, 2);
291                }
292            }
293            _ => {}
294        }
295    }
296
297    /// Flip the image vertically depending on the screen origin bit
298    ///
299    /// The bit in position 5 of the image descriptor byte is the screen origin bit.
300    /// If it's 1, the origin is in the top left corner.
301    /// If it's 0, the origin is in the bottom left corner.
302    /// This function checks the bit, and if it's 0, flips the image vertically.
303    fn flip_vertically(&mut self, pixels: &mut [u8]) {
304        if self.is_flipped_vertically() {
305            if self.height == 0 {
306                return;
307            }
308
309            let num_bytes = pixels.len();
310
311            let width_bytes = num_bytes / self.height;
312
313            // Flip the image vertically.
314            for vertical_index in 0..(self.height / 2) {
315                let vertical_target = (self.height - vertical_index) * width_bytes - width_bytes;
316
317                for horizontal_index in 0..width_bytes {
318                    let source = vertical_index * width_bytes + horizontal_index;
319                    let target = vertical_target + horizontal_index;
320
321                    pixels.swap(target, source);
322                }
323            }
324        }
325    }
326
327    /// Check whether the image is vertically flipped
328    ///
329    /// The bit in position 5 of the image descriptor byte is the screen origin bit.
330    /// If it's 1, the origin is in the top left corner.
331    /// If it's 0, the origin is in the bottom left corner.
332    /// This function checks the bit, and if it's 0, flips the image vertically.
333    fn is_flipped_vertically(&self) -> bool {
334        let screen_origin_bit = SCREEN_ORIGIN_BIT_MASK & self.header.image_desc != 0;
335        !screen_origin_bit
336    }
337}
338
339impl<R: Read> ImageDecoder for TgaDecoder<R> {
340    fn dimensions(&self) -> (u32, u32) {
341        (self.width as u32, self.height as u32)
342    }
343
344    fn color_type(&self) -> ColorType {
345        self.color_type
346    }
347
348    fn original_color_type(&self) -> ExtendedColorType {
349        self.original_color_type
350            .unwrap_or_else(|| self.color_type().into())
351    }
352
353    fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> {
354        assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));
355
356        // In indexed images, we might need more bytes than pixels to read them. That's nonsensical
357        // to encode but we'll not want to crash.
358        let mut fallback_buf = vec![];
359        // read the pixels from the data region
360        let rawbuf = if self.image_type.is_encoded() {
361            let pixel_data = self.read_all_encoded_data()?;
362            if self.bytes_per_pixel <= usize::from(self.color_type.bytes_per_pixel()) {
363                buf[..pixel_data.len()].copy_from_slice(&pixel_data);
364                &buf[..pixel_data.len()]
365            } else {
366                fallback_buf = pixel_data;
367                &fallback_buf[..]
368            }
369        } else {
370            let num_raw_bytes = self.width * self.height * self.bytes_per_pixel;
371            if self.bytes_per_pixel <= usize::from(self.color_type.bytes_per_pixel()) {
372                self.r.by_ref().read_exact(&mut buf[..num_raw_bytes])?;
373                &buf[..num_raw_bytes]
374            } else {
375                fallback_buf.resize(num_raw_bytes, 0u8);
376                self.r
377                    .by_ref()
378                    .read_exact(&mut fallback_buf[..num_raw_bytes])?;
379                &fallback_buf[..num_raw_bytes]
380            }
381        };
382
383        // expand the indices using the color map if necessary
384        if self.image_type.is_color_mapped() {
385            let pixel_data = self.expand_color_map(rawbuf)?;
386            // not enough data to fill the buffer, or would overflow the buffer
387            if pixel_data.len() != buf.len() {
388                return Err(ImageError::Limits(LimitError::from_kind(
389                    LimitErrorKind::DimensionError,
390                )));
391            }
392            buf.copy_from_slice(&pixel_data);
393        }
394
395        self.reverse_encoding_in_output(buf);
396
397        self.flip_vertically(buf);
398
399        Ok(())
400    }
401
402    fn read_image_boxed(self: Box<Self>, buf: &mut [u8]) -> ImageResult<()> {
403        (*self).read_image(buf)
404    }
405}