1#![no_implicit_prelude]
21
22extern crate core;
23extern crate rpsp;
24
25use core::clone::Clone;
26use core::convert::From;
27use core::fmt::{self, Debug, Formatter};
28use core::iter::{IntoIterator, Iterator};
29use core::marker::Copy;
30use core::ops::Deref;
31use core::option::Option::{self, None, Some};
32use core::result::Result::{self, Err, Ok};
33use core::unreachable;
34
35use rpsp::io::{Error, Read, Seek, SeekFrom};
36
37use crate::frame::RGB;
38use crate::fs::DeviceError;
39
40const ATTRS_NONE: u8 = 0u8;
41const ATTRS_TOP_LEFT: u8 = 0x08u8;
42const ATTRS_GRAYSCALE: u8 = 0x01u8;
43const ATTRS_TOP_RIGHT: u8 = 0x10u8;
44const ATTRS_TRUE_COLOR: u8 = 0x02u8;
45const ATTRS_BOTTOM_LEFT: u8 = 0x20u8;
46const ATTRS_BOTTOM_RIGHT: u8 = 0x40u8;
47const ATTRS_MAPPED_COLOR: u8 = 0x04u8;
48const ATTRS_IS_COMPRESSED: u8 = 0x80u8;
49
50pub enum ImageError {
51 InvalidType(u8),
52 Io(Error<DeviceError>),
53 Empty,
54 NotTGA,
55 InvalidImage,
56 InvalidColorMap,
57}
58pub enum Pixels<'a, R: Reader> {
59 Raw(Raw<'a, R>),
60 Compressed(Compressed<'a, R>),
61}
62
63pub struct Pixel {
64 pub pos: Point,
65 pub color: u32,
66}
67pub struct Point {
68 pub x: i32,
69 pub y: i32,
70}
71pub struct Header {
72 map: Option<ColorMap>,
73 bits: u8,
74 attrs: u8,
75 width: u16,
76 alpha: u8,
77 height: u16,
78 origin: Point,
79}
80pub struct Raw<'a, R: Reader> {
81 pos: Point,
82 image: TgaParser<'a, R>,
83}
84pub struct TgaParser<'a, R: Reader> {
85 buf: [u8; 0xFF],
86 pos: usize,
87 avail: usize,
88 reader: &'a mut R,
89 header: Header,
90}
91pub struct Compressed<'a, R: Reader> {
92 cur: u32,
93 pos: Point,
94 skip: u8,
95 count: u8,
96 image: TgaParser<'a, R>,
97}
98
99pub trait Reader: Read<DeviceError> + Seek<DeviceError> {}
100
101struct ColorMap {
102 len: u16,
103 pos: u16,
104 buf: [u8; 4],
105 bits: u8,
106 last: Option<u32>,
107 index: u16,
108}
109
110impl Pixel {
111 #[inline(always)]
112 pub fn rgb(&self) -> RGB {
113 RGB::raw(self.color)
114 }
115 #[inline(always)]
116 pub fn is_solid(&self) -> bool {
117 (self.color >> 24) & 0xFF == 0xFF
118 }
119 #[inline(always)]
120 pub fn is_transparent(&self) -> bool {
121 (self.color >> 24) & 0xFF == 0
122 }
123}
124impl Point {
125 #[inline(always)]
126 fn new(x: i32, y: i32) -> Point {
127 Point { x, y }
128 }
129
130 fn next(&mut self, h: &Header) -> Option<Point> {
131 if self.y < 0 || self.y >= h.height as i32 {
132 return None;
133 }
134 let p = *self;
135 self.x = self.x.saturating_add(1);
136 if self.x >= h.width as i32 {
137 self.y = if h.is_flipped() { self.y.saturating_sub(1) } else { self.y.saturating_add(1) };
138 self.x = 0;
139 }
140 Some(p)
141 }
142}
143impl Header {
144 fn new(r: &mut impl Reader) -> Result<Header, ImageError> {
145 let mut b = [0u8; 18];
146 r.read_exact(&mut b)?;
147 match b[16] {
148 8 | 16 | 24 | 32 => (),
149 _ => return Err(ImageError::InvalidImage),
150 }
151 if b[0] > 0 {
152 r.seek(SeekFrom::Current(b[0] as i64))?;
153 }
154 Ok(Header {
155 map: ColorMap::new(&b)?,
156 bits: b[16] / 0x8,
157 attrs: attrs(b[2], b[17])?,
158 alpha: b[17] & 0xF,
159 width: le_u16(&b[12..]),
160 height: le_u16(&b[14..]),
161 origin: Point::new(le_u16(&b[8..]) as i32, le_u16(&b[10..]) as i32),
162 })
163 }
164
165 #[inline(always)]
166 pub fn alpha(&self) -> u8 {
167 self.alpha
168 }
169 #[inline(always)]
170 pub fn width(&self) -> i32 {
171 self.width as i32
172 }
173 #[inline(always)]
174 pub fn height(&self) -> i32 {
175 self.height as i32
176 }
177 #[inline(always)]
178 pub fn origin(&self) -> Point {
179 self.origin
180 }
181 #[inline(always)]
182 pub fn pixel_size(&self) -> u8 {
183 self.bits
184 }
185 #[inline]
186 pub fn image_start(&self) -> u64 {
187 self.map
188 .as_ref()
189 .map(|m| m.pos as u64 + (m.len * m.bits as u16) as u64)
190 .unwrap_or(0)
191 }
192 #[inline(always)]
193 pub fn is_flipped(&self) -> bool {
194 self.attrs & ATTRS_BOTTOM_LEFT != 0 || self.attrs & ATTRS_BOTTOM_RIGHT != 0
195 }
196 #[inline(always)]
197 pub fn is_compressed(&self) -> bool {
198 self.attrs & ATTRS_IS_COMPRESSED != 0
199 }
200}
201impl ColorMap {
202 fn new(b: &[u8]) -> Result<Option<ColorMap>, ImageError> {
203 match b[1] {
204 1 => (),
205 0 => return Ok(None),
206 _ => return Err(ImageError::InvalidColorMap),
207 }
208 let n = le_u16(&b[5..]);
209 if n == 0 {
210 return Ok(None);
211 }
212 let p = le_u16(&b[3..]);
213 Ok(Some(ColorMap {
214 len: n,
215 pos: if p == 0 { 0x12u16 + b[0] as u16 } else { p },
216 buf: [0u8; 4],
217 bits: b[7] / 0x8,
218 last: None,
219 index: 0u16,
220 }))
221 }
222
223 fn index(&mut self, v: u32, r: &mut impl Reader) -> Result<Option<u32>, ImageError> {
224 if v as u16 == self.index && self.last.is_some() {
225 return Ok(self.last);
226 }
227 if v as u16 >= self.len {
228 return Ok(None);
229 }
230 let i = v as u64 * self.bits as u64;
231 if i > 0xFFFF {
232 return Ok(None);
233 }
234 let l = r.stream_position()?;
235 r.seek(SeekFrom::Start(i + self.pos as u64))?;
236 let n = r.read(&mut self.buf)?;
237 r.seek(SeekFrom::Start(l))?;
238 let c = match self.bits {
239 1 if n >= 1 => self.buf[0] as u32,
240 2 if n >= 2 => le_u16(&self.buf) as u32,
241 3 if n >= 3 => le_u24(&self.buf),
242 4 if n >= 4 => le_u32(&self.buf),
243 _ => return Ok(None),
244 };
245 self.index = v as u16;
246 self.last.replace(c);
247 Ok(Some(c))
248 }
249}
250impl<R: Reader> TgaParser<'_, R> {
251 pub fn new<'a>(reader: &'a mut R) -> Result<TgaParser<'a, R>, ImageError> {
252 let h = Header::new(reader)?;
253 let s = h.image_start();
254 if s > 0 {
255 reader.seek(SeekFrom::Start(s))?;
256 }
257 Ok(TgaParser {
258 reader,
259 buf: [0u8; 0xFF],
260 pos: 0usize,
261 avail: 0usize,
262 header: h,
263 })
264 }
265
266 #[inline(always)]
267 pub fn header(&self) -> &Header {
268 &self.header
269 }
270
271 #[inline]
272 fn fix_alpha(&self, v: u32) -> u32 {
273 if (v >> 24) & 0xFF > 0 {
274 return v;
275 } else if self.header.alpha == 0 {
276 v | 0xFF000000
277 } else {
278 v
279 }
280 }
281 #[inline]
282 fn next(&mut self) -> Result<u32, ImageError> {
283 match self.header.bits {
284 1 => Ok(self.read(1)?[0] as u32),
285 2 => Ok(le_u16(self.read(2)?) as u32),
286 3 => Ok(le_u24(self.read(3)?)),
287 4 => Ok(le_u32(self.read(4)?)),
288 _ => unreachable!(),
289 }
290 }
291 fn map(&mut self, c: u32) -> Result<u32, ImageError> {
292 let n = match self.header.map.as_mut() {
293 Some(m) => m.index(c, self.reader)?.unwrap_or(c),
294 None => c,
295 };
296 match self.header.bits {
298 _ if self.header.attrs & 0x7 == ATTRS_NONE => Ok(n),
299 1 if self.header.attrs & ATTRS_GRAYSCALE != 0 => Ok((n & 0xFF) << 16 | (n & 0xFF) << 8 | n & 0xFF | 0xFF000000),
302 2 => Ok((0xFF * ((n >> 15) & 0x1)) | (((n >> 10) & 0x1F) << 16) | (((n >> 5) << 0x1F) << 8) | (n & 0x1F)),
305 3 => Ok(n | 0xFF000000), _ => Ok(n), }
308 }
309 #[inline]
310 fn read(&mut self, want: usize) -> Result<&[u8], ImageError> {
311 self.refill(want)?;
312 if self.avail.saturating_sub(self.pos) < want {
313 Err(ImageError::Empty)
314 } else {
315 let n = self.pos;
316 self.pos += want;
317 Ok(&self.buf[n..n + want])
318 }
319 }
320 fn refill(&mut self, want: usize) -> Result<usize, ImageError> {
321 while self.avail.saturating_sub(self.pos) < want {
322 if self.pos > 0 {
323 self.buf.copy_within(self.pos.., 0);
324 self.avail -= self.pos;
325 self.pos = 0;
326 }
327 let n = self.reader.read(&mut self.buf[self.avail..])?;
328 if n == 0 {
329 break;
330 }
331 self.avail += n;
332 }
333 Ok(self.avail)
334 }
335}
336impl<R: Reader> Compressed<'_, R> {
337 fn decompress(&mut self) -> Option<Result<u32, ImageError>> {
338 if self.count > 0 {
339 self.count -= 1;
340 return Some(Ok(self.cur));
341 }
342 if self.skip > 0 {
343 self.skip -= 1;
344 return Some(self.image.next().and_then(|v| self.image.map(v)));
345 }
346 let v = match self.image.read(1) {
347 Err(e) => return Some(Err(e)),
348 Ok(v) => v[0],
349 };
350 if v & 0x80 != 0 {
351 self.count = (v & 0x7F) + 1;
352 self.cur = match self.image.next() {
353 Err(e) => return Some(Err(e)),
354 Ok(v) => v,
355 };
356 } else {
357 self.skip = (v & 0x7F) + 1;
358 }
359 self.decompress()
360 }
361}
362
363impl<'a, R: Reader> IntoIterator for TgaParser<'a, R> {
364 type IntoIter = Pixels<'a, R>;
365 type Item = Result<Pixel, ImageError>;
366
367 fn into_iter(self) -> Pixels<'a, R> {
368 let y = if self.header.is_flipped() { self.header.height.saturating_sub(1) } else { 0 };
369 if self.header.attrs & ATTRS_IS_COMPRESSED != 0 {
370 Pixels::Compressed(Compressed {
371 pos: Point::new(0, y as i32),
372 cur: 0u32,
373 skip: 0u8,
374 image: self,
375 count: 0u8,
376 })
377 } else {
378 Pixels::Raw(Raw {
379 pos: Point::new(0, y as i32),
380 image: self,
381 })
382 }
383 }
384}
385
386impl<R: Reader> Iterator for Raw<'_, R> {
387 type Item = Result<Pixel, ImageError>;
388
389 fn next(&mut self) -> Option<Result<Pixel, ImageError>> {
390 let p = self.pos.next(&self.image.header)?;
391 match self.image.next() {
392 Ok(c) => Some(Ok(Pixel {
393 pos: p,
394 color: match self.image.map(c) {
395 Err(e) => return Some(Err(e)),
396 Ok(v) => self.image.fix_alpha(v),
397 },
398 })),
399 Err(ImageError::Empty) => None,
400 Err(e) => Some(Err(e)),
401 }
402 }
403}
404impl<R: Reader> Iterator for Pixels<'_, R> {
405 type Item = Result<Pixel, ImageError>;
406
407 #[inline(always)]
408 fn next(&mut self) -> Option<Result<Pixel, ImageError>> {
409 match self {
410 Pixels::Raw(v) => v.next(),
411 Pixels::Compressed(v) => v.next(),
412 }
413 }
414}
415impl<R: Reader> Iterator for Compressed<'_, R> {
416 type Item = Result<Pixel, ImageError>;
417
418 fn next(&mut self) -> Option<Result<Pixel, ImageError>> {
419 let p = self.pos.next(&self.image.header)?;
420 match self.decompress()? {
421 Ok(c) => Some(Ok(Pixel {
422 pos: p,
423 color: self.image.fix_alpha(c),
424 })),
425 Err(ImageError::Empty) => None,
426 Err(e) => Some(Err(e)),
427 }
428 }
429}
430
431impl Copy for Point {}
432impl Clone for Point {
433 #[inline(always)]
434 fn clone(&self) -> Point {
435 Point { x: self.x, y: self.y }
436 }
437}
438
439impl Copy for Pixel {}
440impl Clone for Pixel {
441 #[inline(always)]
442 fn clone(&self) -> Pixel {
443 Pixel {
444 pos: self.pos.clone(),
445 color: self.color,
446 }
447 }
448}
449impl Deref for Pixel {
450 type Target = Point;
451
452 #[inline(always)]
453 fn deref(&self) -> &Point {
454 &self.pos
455 }
456}
457
458impl From<DeviceError> for ImageError {
459 #[inline(always)]
460 fn from(v: DeviceError) -> ImageError {
461 ImageError::Io(Error::Other(v))
462 }
463}
464impl From<Error<DeviceError>> for ImageError {
465 #[inline(always)]
466 fn from(v: Error<DeviceError>) -> ImageError {
467 ImageError::Io(v)
468 }
469}
470
471impl<D: Read<DeviceError> + Seek<DeviceError>> Reader for D {}
472
473#[cfg(feature = "debug")]
474impl Debug for ImageError {
475 #[inline]
476 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
477 match self {
478 ImageError::Io(v) => f.debug_tuple("Io").field(v).finish(),
479 ImageError::InvalidType(v) => f.debug_tuple("InvalidType").field(v).finish(),
480 ImageError::Empty => f.write_str("Empty"),
481 ImageError::NotTGA => f.write_str("NotTGA"),
482 ImageError::InvalidImage => f.write_str("InvalidImage"),
483 ImageError::InvalidColorMap => f.write_str("InvalidColorMap"),
484 }
485 }
486}
487#[cfg(not(feature = "debug"))]
488impl Debug for ImageError {
489 #[inline(always)]
490 fn fmt(&self, _f: &mut Formatter<'_>) -> fmt::Result {
491 Ok(())
492 }
493}
494
495#[inline]
496fn le_u16(b: &[u8]) -> u16 {
497 (b[0] as u16) | (b[1] as u16) << 8
498}
499#[inline]
500fn le_u24(b: &[u8]) -> u32 {
501 (b[0] as u32) | (b[1] as u32) << 8 | (b[2] as u32) << 16
502}
503#[inline]
504fn le_u32(b: &[u8]) -> u32 {
505 (b[0] as u32) | (b[1] as u32) << 8 | (b[2] as u32) << 16 | (b[3] as u32) << 24
506}
507#[inline]
508fn attrs(a: u8, p: u8) -> Result<u8, ImageError> {
509 let r = match a {
510 _ if a & !0xB != 0 => return Err(ImageError::InvalidType(a)),
511 0 => return Err(ImageError::InvalidType(a)),
512 1 if a & 0x8 != 0 => ATTRS_MAPPED_COLOR | ATTRS_IS_COMPRESSED,
513 2 if a & 0x8 != 0 => ATTRS_TRUE_COLOR | ATTRS_IS_COMPRESSED,
514 3 if a & 0x8 != 0 => ATTRS_GRAYSCALE | ATTRS_IS_COMPRESSED,
515 _ if a & 0x8 != 0 => ATTRS_NONE | ATTRS_IS_COMPRESSED,
516 1 => ATTRS_MAPPED_COLOR,
517 2 => ATTRS_TRUE_COLOR,
518 3 => ATTRS_GRAYSCALE,
519 _ => ATTRS_NONE,
520 };
521 match (p & 0x30) >> 4 {
522 0 => Ok(r | ATTRS_BOTTOM_LEFT),
523 1 => Ok(r | ATTRS_BOTTOM_RIGHT),
524 2 => Ok(r | ATTRS_TOP_LEFT),
525 _ => Ok(r | ATTRS_TOP_RIGHT),
526 }
527}