1use super::header::{Header, ImageType, ALPHA_BIT_MASK};
2use crate::error::DecodingError;
3use crate::io::ReadExt;
4use crate::utils::vec_try_with_capacity;
5use crate::{
6 color::{ColorType, ExtendedColorType},
7 error::{ImageError, ImageResult, UnsupportedError, UnsupportedErrorKind},
8 ImageDecoder, ImageFormat,
9};
10use byteorder_lite::ReadBytesExt;
11use std::io::{self, Read};
12
13struct ColorMap {
14 start_offset: usize,
16 entry_size: usize,
17 bytes: Vec<u8>,
18}
19
20impl ColorMap {
21 pub(crate) fn get(&self, index: usize) -> Option<&[u8]> {
23 let entry = self.entry_size * index.checked_sub(self.start_offset)?;
24 self.bytes.get(entry..entry + self.entry_size)
25 }
26}
27
28pub struct TgaDecoder<R> {
30 r: R,
31
32 width: usize,
33 height: usize,
34
35 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)]
48enum TgaOrientation {
49 TopLeft,
50 TopRight,
51 BottomRight,
52 BottomLeft,
53}
54
55impl TgaOrientation {
56 fn from_image_desc_byte(value: u8) -> Self {
57 if value & (1u8 << 4) == 0 {
62 if value & (1u8 << 5) == 0 {
64 TgaOrientation::BottomLeft
65 } else {
66 TgaOrientation::TopLeft
67 }
68 } else {
69 if value & (1u8 << 5) == 0 {
71 TgaOrientation::BottomRight
72 } else {
73 TgaOrientation::TopRight
74 }
75 }
76 }
77}
78
79impl<R: Read> TgaDecoder<R> {
80 pub fn new(mut r: R) -> ImageResult<TgaDecoder<R>> {
82 let header = Header::from_reader(&mut r)?;
84 let image_type = ImageType::new(header.image_type);
85 let width = header.image_width as usize;
86 let height = header.image_height as usize;
87 let raw_bytes_per_pixel = (header.pixel_depth as usize).div_ceil(8);
88 let num_alpha_bits = header.image_desc & ALPHA_BIT_MASK;
89
90 if width == 0 || height == 0 {
91 return Err(ImageError::Decoding(DecodingError::new(
92 ImageFormat::Tga.into(),
93 "Invalid empty image",
94 )));
95 }
96
97 if ![8, 16, 24, 32].contains(&header.pixel_depth) || ![0, 8].contains(&num_alpha_bits) {
99 return Err(ImageError::Unsupported(
100 UnsupportedError::from_format_and_kind(
101 ImageFormat::Tga.into(),
102 UnsupportedErrorKind::Color(ExtendedColorType::Unknown(header.pixel_depth)),
103 ),
104 ));
105 }
106 if image_type.is_color_mapped() {
107 if header.map_type != 1 {
108 return Err(ImageError::Decoding(DecodingError::new(
109 ImageFormat::Tga.into(),
110 "Color map type must be 1 for color mapped images",
111 )));
112 } else if ![8, 16].contains(&header.pixel_depth) {
113 return Err(ImageError::Decoding(DecodingError::new(
114 ImageFormat::Tga.into(),
115 "Color map must use 1 or 2 byte indexes",
116 )));
117 } else if header.pixel_depth > header.map_entry_size {
118 return Err(ImageError::Unsupported(
119 UnsupportedError::from_format_and_kind(
120 ImageFormat::Tga.into(),
121 UnsupportedErrorKind::GenericFeature(
122 "Indices larger than pixel values".into(),
123 ),
124 ),
125 ));
126 }
127 }
128
129 let mut tmp = [0u8; 256];
133 r.read_exact(&mut tmp[0..header.id_length as usize])?;
134
135 let mut color_map = None;
137 if header.map_type == 1 {
138 let entry_size = (header.map_entry_size as usize).div_ceil(8);
139 if ![2, 3, 4].contains(&entry_size) {
140 return Err(ImageError::Unsupported(
141 UnsupportedError::from_format_and_kind(
142 ImageFormat::Tga.into(),
143 UnsupportedErrorKind::GenericFeature(
144 "Unsupported color map entry size".into(),
145 ),
146 ),
147 ));
148 }
149
150 let mut bytes = Vec::new();
151 r.read_exact_vec(&mut bytes, entry_size * header.map_length as usize)?;
152
153 if image_type.is_color_mapped() {
156 color_map = Some(ColorMap {
157 entry_size,
158 start_offset: header.map_origin as usize,
159 bytes,
160 });
161 }
162 }
163
164 let total_pixel_bits = if header.map_type == 1 {
166 header.map_entry_size
167 } else {
168 header.pixel_depth
169 };
170 let num_other_bits = total_pixel_bits
171 .checked_sub(num_alpha_bits)
172 .ok_or_else(|| {
173 ImageError::Decoding(DecodingError::new(
174 ImageFormat::Tga.into(),
175 "More alpha bits than pixel bits",
176 ))
177 })?;
178
179 let color_type;
181 let mut original_color_type = None;
182 match (num_alpha_bits, num_other_bits, image_type.is_color()) {
183 (0, 32, true) => color_type = ColorType::Rgba8,
186 (8, 24, true) => color_type = ColorType::Rgba8,
187 (0, 24, true) => color_type = ColorType::Rgb8,
188 (8, 8, false) => color_type = ColorType::La8,
189 (0, 8, false) => color_type = ColorType::L8,
190 (8, 0, false) => {
191 color_type = ColorType::L8;
193 original_color_type = Some(ExtendedColorType::A8);
194 }
195 _ => {
196 return Err(ImageError::Unsupported(
197 UnsupportedError::from_format_and_kind(
198 ImageFormat::Tga.into(),
199 UnsupportedErrorKind::Color(ExtendedColorType::Unknown(header.pixel_depth)),
200 ),
201 ))
202 }
203 }
204
205 Ok(TgaDecoder {
206 r,
207
208 width,
209 height,
210 raw_bytes_per_pixel,
211
212 image_type,
213 color_type,
214 original_color_type,
215
216 header,
217 color_map,
218 })
219 }
220
221 fn read_encoded_data(&mut self, buf: &mut [u8]) -> io::Result<()> {
223 assert!(self.raw_bytes_per_pixel <= 4);
224 let mut repeat_buf = [0; 4];
225 let repeat_buf = &mut repeat_buf[..self.raw_bytes_per_pixel];
226
227 let mut index = 0;
228 while index < buf.len() {
229 let run_packet = self.r.read_u8()?;
230 if (run_packet & 0x80) != 0 {
235 let repeat_count = ((run_packet & !0x80) + 1) as usize;
237 self.r.read_exact(repeat_buf)?;
238
239 for chunk in buf[index..]
240 .chunks_exact_mut(self.raw_bytes_per_pixel)
241 .take(repeat_count)
242 {
243 chunk.copy_from_slice(repeat_buf);
244 }
245 index += repeat_count * self.raw_bytes_per_pixel;
246 } else {
247 let num_raw_bytes =
249 ((run_packet + 1) as usize * self.raw_bytes_per_pixel).min(buf.len() - index);
250
251 self.r.read_exact(&mut buf[index..][..num_raw_bytes])?;
252 index += num_raw_bytes;
253 }
254 }
255
256 Ok(())
257 }
258
259 fn expand_color_map(
261 &self,
262 input: &[u8],
263 output: &mut [u8],
264 color_map: &ColorMap,
265 ) -> ImageResult<()> {
266 if self.raw_bytes_per_pixel == 1 {
267 for (&index, chunk) in input
268 .iter()
269 .zip(output.chunks_exact_mut(color_map.entry_size))
270 {
271 if let Some(color) = color_map.get(index as usize) {
272 chunk.copy_from_slice(color);
273 } else {
274 return Err(ImageError::Decoding(DecodingError::new(
275 ImageFormat::Tga.into(),
276 "Invalid color map index",
277 )));
278 }
279 }
280 } else if self.raw_bytes_per_pixel == 2 {
281 for (index, chunk) in input
282 .chunks_exact(2)
283 .zip(output.chunks_exact_mut(color_map.entry_size))
284 {
285 let index = u16::from_le_bytes(index.try_into().unwrap());
286 if let Some(color) = color_map.get(index as usize) {
287 chunk.copy_from_slice(color);
288 } else {
289 return Err(ImageError::Decoding(DecodingError::new(
290 ImageFormat::Tga.into(),
291 "Invalid color map index",
292 )));
293 }
294 }
295 } else {
296 unreachable!("Supported bytes_per_pixel values are checked in TgaDecoder::new");
297 }
298
299 Ok(())
300 }
301
302 fn reverse_encoding_in_output(&mut self, pixels: &mut [u8]) {
307 match self.color_type {
309 ColorType::Rgb8 | ColorType::Rgba8 => {
310 for chunk in pixels.chunks_mut(self.color_type.bytes_per_pixel().into()) {
311 chunk.swap(0, 2);
312 }
313 }
314 _ => {}
315 }
316 }
317
318 fn fixup_orientation(&mut self, pixels: &mut [u8]) {
320 let orientation = TgaOrientation::from_image_desc_byte(self.header.image_desc);
321
322 if (orientation == TgaOrientation::BottomLeft || orientation == TgaOrientation::BottomRight)
324 && self.height > 1
325 {
326 let row_stride = self.width * self.raw_bytes_per_pixel;
327
328 let (left_part, right_part) = pixels.split_at_mut(self.height / 2 * row_stride);
329
330 for (src, dst) in left_part
331 .chunks_exact_mut(row_stride)
332 .zip(right_part.chunks_exact_mut(row_stride).rev())
333 {
334 for (src, dst) in src.iter_mut().zip(dst.iter_mut()) {
335 std::mem::swap(src, dst);
336 }
337 }
338 }
339
340 if (orientation == TgaOrientation::BottomRight || orientation == TgaOrientation::TopRight)
342 && self.width > 1
343 {
344 for row in pixels.chunks_exact_mut(self.width * self.raw_bytes_per_pixel) {
345 let (left_part, right_part) =
346 row.split_at_mut(self.width / 2 * self.raw_bytes_per_pixel);
347 for (src, dst) in left_part
348 .chunks_exact_mut(self.raw_bytes_per_pixel)
349 .zip(right_part.chunks_exact_mut(self.raw_bytes_per_pixel).rev())
350 {
351 for (src, dst) in src.iter_mut().zip(dst.iter_mut()) {
352 std::mem::swap(dst, src);
353 }
354 }
355 }
356 }
357 }
358}
359
360impl<R: Read> ImageDecoder for TgaDecoder<R> {
361 fn dimensions(&self) -> (u32, u32) {
362 (self.width as u32, self.height as u32)
363 }
364
365 fn color_type(&self) -> ColorType {
366 self.color_type
367 }
368
369 fn original_color_type(&self) -> ExtendedColorType {
370 self.original_color_type
371 .unwrap_or_else(|| self.color_type().into())
372 }
373
374 fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> {
375 assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));
376
377 let num_raw_bytes = self.width * self.height * self.raw_bytes_per_pixel;
382 if self.image_type.is_encoded() {
383 self.read_encoded_data(&mut buf[..num_raw_bytes])?;
384 } else {
385 self.r.read_exact(&mut buf[..num_raw_bytes])?;
386 }
387
388 self.fixup_orientation(&mut buf[..num_raw_bytes]);
389
390 if let Some(ref color_map) = self.color_map {
392 let mut rawbuf = vec_try_with_capacity(num_raw_bytes)?;
396 rawbuf.extend_from_slice(&buf[..num_raw_bytes]);
397
398 self.expand_color_map(&rawbuf, buf, color_map)?;
399 }
400
401 self.reverse_encoding_in_output(buf);
402
403 Ok(())
404 }
405
406 fn read_image_boxed(self: Box<Self>, buf: &mut [u8]) -> ImageResult<()> {
407 (*self).read_image(buf)
408 }
409}