diff options
Diffstat (limited to 'vendor/image/src/codecs/tga/header.rs')
-rw-r--r-- | vendor/image/src/codecs/tga/header.rs | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/vendor/image/src/codecs/tga/header.rs b/vendor/image/src/codecs/tga/header.rs new file mode 100644 index 0000000..83ba7a3 --- /dev/null +++ b/vendor/image/src/codecs/tga/header.rs @@ -0,0 +1,150 @@ +use crate::{ + error::{UnsupportedError, UnsupportedErrorKind}, + ColorType, ImageError, ImageFormat, ImageResult, +}; +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; +use std::io::{Read, Write}; + +pub(crate) const ALPHA_BIT_MASK: u8 = 0b1111; +pub(crate) const SCREEN_ORIGIN_BIT_MASK: u8 = 0b10_0000; + +pub(crate) enum ImageType { + NoImageData = 0, + /// Uncompressed images. + RawColorMap = 1, + RawTrueColor = 2, + RawGrayScale = 3, + /// Run length encoded images. + RunColorMap = 9, + RunTrueColor = 10, + RunGrayScale = 11, + Unknown, +} + +impl ImageType { + /// Create a new image type from a u8. + pub(crate) fn new(img_type: u8) -> ImageType { + match img_type { + 0 => ImageType::NoImageData, + + 1 => ImageType::RawColorMap, + 2 => ImageType::RawTrueColor, + 3 => ImageType::RawGrayScale, + + 9 => ImageType::RunColorMap, + 10 => ImageType::RunTrueColor, + 11 => ImageType::RunGrayScale, + + _ => ImageType::Unknown, + } + } + + /// Check if the image format uses colors as opposed to gray scale. + pub(crate) fn is_color(&self) -> bool { + matches! { *self, + ImageType::RawColorMap + | ImageType::RawTrueColor + | ImageType::RunTrueColor + | ImageType::RunColorMap + } + } + + /// Does the image use a color map. + pub(crate) fn is_color_mapped(&self) -> bool { + matches! { *self, ImageType::RawColorMap | ImageType::RunColorMap } + } + + /// Is the image run length encoded. + pub(crate) fn is_encoded(&self) -> bool { + matches! {*self, ImageType::RunColorMap | ImageType::RunTrueColor | ImageType::RunGrayScale } + } +} + +/// Header used by TGA image files. +#[derive(Debug, Default)] +pub(crate) struct Header { + pub(crate) id_length: u8, // length of ID string + pub(crate) map_type: u8, // color map type + pub(crate) image_type: u8, // image type code + pub(crate) map_origin: u16, // starting index of map + pub(crate) map_length: u16, // length of map + pub(crate) map_entry_size: u8, // size of map entries in bits + pub(crate) x_origin: u16, // x-origin of image + pub(crate) y_origin: u16, // y-origin of image + pub(crate) image_width: u16, // width of image + pub(crate) image_height: u16, // height of image + pub(crate) pixel_depth: u8, // bits per pixel + pub(crate) image_desc: u8, // image descriptor +} + +impl Header { + /// Load the header with values from pixel information. + pub(crate) fn from_pixel_info( + color_type: ColorType, + width: u16, + height: u16, + ) -> ImageResult<Self> { + let mut header = Self::default(); + + if width > 0 && height > 0 { + let (num_alpha_bits, other_channel_bits, image_type) = match color_type { + ColorType::Rgba8 => (8, 24, ImageType::RawTrueColor), + ColorType::Rgb8 => (0, 24, ImageType::RawTrueColor), + ColorType::La8 => (8, 8, ImageType::RawGrayScale), + ColorType::L8 => (0, 8, ImageType::RawGrayScale), + _ => { + return Err(ImageError::Unsupported( + UnsupportedError::from_format_and_kind( + ImageFormat::Tga.into(), + UnsupportedErrorKind::Color(color_type.into()), + ), + )) + } + }; + + header.image_type = image_type as u8; + header.image_width = width; + header.image_height = height; + header.pixel_depth = num_alpha_bits + other_channel_bits; + header.image_desc = num_alpha_bits & ALPHA_BIT_MASK; + header.image_desc |= SCREEN_ORIGIN_BIT_MASK; // Upper left origin. + } + + Ok(header) + } + + /// Load the header with values from the reader. + pub(crate) fn from_reader(r: &mut dyn Read) -> ImageResult<Self> { + Ok(Self { + id_length: r.read_u8()?, + map_type: r.read_u8()?, + image_type: r.read_u8()?, + map_origin: r.read_u16::<LittleEndian>()?, + map_length: r.read_u16::<LittleEndian>()?, + map_entry_size: r.read_u8()?, + x_origin: r.read_u16::<LittleEndian>()?, + y_origin: r.read_u16::<LittleEndian>()?, + image_width: r.read_u16::<LittleEndian>()?, + image_height: r.read_u16::<LittleEndian>()?, + pixel_depth: r.read_u8()?, + image_desc: r.read_u8()?, + }) + } + + /// Write out the header values. + pub(crate) fn write_to(&self, w: &mut dyn Write) -> ImageResult<()> { + w.write_u8(self.id_length)?; + w.write_u8(self.map_type)?; + w.write_u8(self.image_type)?; + w.write_u16::<LittleEndian>(self.map_origin)?; + w.write_u16::<LittleEndian>(self.map_length)?; + w.write_u8(self.map_entry_size)?; + w.write_u16::<LittleEndian>(self.x_origin)?; + w.write_u16::<LittleEndian>(self.y_origin)?; + w.write_u16::<LittleEndian>(self.image_width)?; + w.write_u16::<LittleEndian>(self.image_height)?; + w.write_u8(self.pixel_depth)?; + w.write_u8(self.image_desc)?; + Ok(()) + } +} |