use embedded_graphics::prelude::*;
use nom::{bytes::complete::take, IResult};
use crate::{
color_map::ColorMap,
footer::TgaFooter,
header::{Bpp, ImageOrigin, TgaHeader},
parse_error::ParseError,
raw_iter::RawPixels,
Compression, DataType,
};
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub struct RawTga<'a> {
data: &'a [u8],
color_map: Option<ColorMap<'a>>,
pixel_data: &'a [u8],
size: Size,
data_type: DataType,
compression: Compression,
bpp: Bpp,
image_origin: ImageOrigin,
}
impl<'a> RawTga<'a> {
pub fn from_slice(data: &'a [u8]) -> Result<Self, ParseError> {
let input = data;
let (input, header) = TgaHeader::parse(input).map_err(|_| ParseError::Header)?;
let (input, _image_id) = parse_image_id(input, &header).map_err(|_| ParseError::Header)?;
let (input, color_map) = ColorMap::parse(input, &header)?;
let footer_length = TgaFooter::parse(data).map_or(0, |footer| footer.length(data));
let pixel_data = &input[0..input.len().saturating_sub(footer_length)];
let size = Size::new(u32::from(header.width), u32::from(header.height));
Ok(Self {
data,
color_map,
pixel_data,
size,
bpp: header.pixel_depth,
image_origin: header.image_origin,
data_type: header.data_type,
compression: header.compression,
})
}
pub fn size(&self) -> Size {
self.size
}
pub fn color_map(&self) -> Option<&ColorMap<'a>> {
self.color_map.as_ref()
}
pub fn color_bpp(&self) -> Bpp {
if let Some(color_map) = &self.color_map {
color_map.entry_bpp()
} else {
self.bpp
}
}
pub fn image_origin(&self) -> ImageOrigin {
self.image_origin
}
pub fn data_type(&self) -> DataType {
self.data_type
}
pub fn compression(&self) -> Compression {
self.compression
}
pub fn image_data(&self) -> &'a [u8] {
self.pixel_data
}
pub fn image_data_bpp(&self) -> Bpp {
self.bpp
}
pub fn pixels(&self) -> RawPixels<'_> {
RawPixels::new(self)
}
pub fn header(&self) -> TgaHeader {
TgaHeader::parse(self.data).unwrap().1
}
pub fn developer_directory(&self) -> Option<&'a [u8]> {
TgaFooter::parse(self.data).and_then(|footer| footer.developer_directory(self.data))
}
pub fn extension_area(&self) -> Option<&'a [u8]> {
TgaFooter::parse(self.data).and_then(|footer| footer.extension_area(self.data))
}
pub fn image_id(&self) -> Option<&'a [u8]> {
let (input, header) = TgaHeader::parse(self.data).ok()?;
parse_image_id(input, &header)
.ok()
.map(|(_input, id)| id)
.filter(|id| !id.is_empty())
}
}
fn parse_image_id<'a>(input: &'a [u8], header: &TgaHeader) -> IResult<&'a [u8], &'a [u8]> {
take(header.id_len)(input)
}