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 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 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
45pub 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 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 fn read_color_information(&mut self) -> ImageResult<()> {
109 if self.header.pixel_depth % 8 != 0 || self.header.pixel_depth > 32 {
110 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 (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 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 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 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 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 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 (run_packet & 0x80) != 0 {
240 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 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 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 pixel_data.truncate(num_bytes);
269 }
270
271 Ok(pixel_data)
272 }
273
274 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 fn reverse_encoding_in_output(&mut self, pixels: &mut [u8]) {
286 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 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 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 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 let mut fallback_buf = vec![];
359 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 if self.image_type.is_color_mapped() {
385 let pixel_data = self.expand_color_map(rawbuf)?;
386 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}