1 use crate::{ 2 error::{UnsupportedError, UnsupportedErrorKind}, 3 ColorType, ImageError, ImageFormat, ImageResult, 4 }; 5 use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; 6 use std::io::{Read, Write}; 7 8 pub(crate) const ALPHA_BIT_MASK: u8 = 0b1111; 9 pub(crate) const SCREEN_ORIGIN_BIT_MASK: u8 = 0b10_0000; 10 11 pub(crate) enum ImageType { 12 NoImageData = 0, 13 /// Uncompressed images. 14 RawColorMap = 1, 15 RawTrueColor = 2, 16 RawGrayScale = 3, 17 /// Run length encoded images. 18 RunColorMap = 9, 19 RunTrueColor = 10, 20 RunGrayScale = 11, 21 Unknown, 22 } 23 24 impl ImageType { 25 /// Create a new image type from a u8. new(img_type: u8) -> ImageType26 pub(crate) fn new(img_type: u8) -> ImageType { 27 match img_type { 28 0 => ImageType::NoImageData, 29 30 1 => ImageType::RawColorMap, 31 2 => ImageType::RawTrueColor, 32 3 => ImageType::RawGrayScale, 33 34 9 => ImageType::RunColorMap, 35 10 => ImageType::RunTrueColor, 36 11 => ImageType::RunGrayScale, 37 38 _ => ImageType::Unknown, 39 } 40 } 41 42 /// Check if the image format uses colors as opposed to gray scale. is_color(&self) -> bool43 pub(crate) fn is_color(&self) -> bool { 44 match *self { 45 ImageType::RawColorMap 46 | ImageType::RawTrueColor 47 | ImageType::RunTrueColor 48 | ImageType::RunColorMap => true, 49 _ => false, 50 } 51 } 52 53 /// Does the image use a color map. is_color_mapped(&self) -> bool54 pub(crate) fn is_color_mapped(&self) -> bool { 55 match *self { 56 ImageType::RawColorMap | ImageType::RunColorMap => true, 57 _ => false, 58 } 59 } 60 61 /// Is the image run length encoded. is_encoded(&self) -> bool62 pub(crate) fn is_encoded(&self) -> bool { 63 match *self { 64 ImageType::RunColorMap | ImageType::RunTrueColor | ImageType::RunGrayScale => true, 65 _ => false, 66 } 67 } 68 } 69 70 /// Header used by TGA image files. 71 #[derive(Debug, Default)] 72 pub(crate) struct Header { 73 pub(crate) id_length: u8, // length of ID string 74 pub(crate) map_type: u8, // color map type 75 pub(crate) image_type: u8, // image type code 76 pub(crate) map_origin: u16, // starting index of map 77 pub(crate) map_length: u16, // length of map 78 pub(crate) map_entry_size: u8, // size of map entries in bits 79 pub(crate) x_origin: u16, // x-origin of image 80 pub(crate) y_origin: u16, // y-origin of image 81 pub(crate) image_width: u16, // width of image 82 pub(crate) image_height: u16, // height of image 83 pub(crate) pixel_depth: u8, // bits per pixel 84 pub(crate) image_desc: u8, // image descriptor 85 } 86 87 impl Header { 88 /// Load the header with values from pixel information. from_pixel_info( color_type: ColorType, width: u16, height: u16, ) -> ImageResult<Self>89 pub(crate) fn from_pixel_info( 90 color_type: ColorType, 91 width: u16, 92 height: u16, 93 ) -> ImageResult<Self> { 94 let mut header = Self::default(); 95 96 if width > 0 && height > 0 { 97 let (num_alpha_bits, other_channel_bits, image_type) = match color_type { 98 ColorType::Rgba8 | ColorType::Bgra8 => (8, 24, ImageType::RawTrueColor), 99 ColorType::Rgb8 | ColorType::Bgr8 => (0, 24, ImageType::RawTrueColor), 100 ColorType::La8 => (8, 8, ImageType::RawGrayScale), 101 ColorType::L8 => (0, 8, ImageType::RawGrayScale), 102 _ => { 103 return Err(ImageError::Unsupported( 104 UnsupportedError::from_format_and_kind( 105 ImageFormat::Tga.into(), 106 UnsupportedErrorKind::Color(color_type.into()), 107 ), 108 )) 109 } 110 }; 111 112 header.image_type = image_type as u8; 113 header.image_width = width; 114 header.image_height = height; 115 header.pixel_depth = num_alpha_bits + other_channel_bits; 116 header.image_desc = num_alpha_bits & ALPHA_BIT_MASK; 117 header.image_desc |= SCREEN_ORIGIN_BIT_MASK; // Upper left origin. 118 } 119 120 Ok(header) 121 } 122 123 /// Load the header with values from the reader. from_reader(r: &mut dyn Read) -> ImageResult<Self>124 pub(crate) fn from_reader(r: &mut dyn Read) -> ImageResult<Self> { 125 Ok(Self { 126 id_length: r.read_u8()?, 127 map_type: r.read_u8()?, 128 image_type: r.read_u8()?, 129 map_origin: r.read_u16::<LittleEndian>()?, 130 map_length: r.read_u16::<LittleEndian>()?, 131 map_entry_size: r.read_u8()?, 132 x_origin: r.read_u16::<LittleEndian>()?, 133 y_origin: r.read_u16::<LittleEndian>()?, 134 image_width: r.read_u16::<LittleEndian>()?, 135 image_height: r.read_u16::<LittleEndian>()?, 136 pixel_depth: r.read_u8()?, 137 image_desc: r.read_u8()?, 138 }) 139 } 140 141 /// Write out the header values. write_to(&self, w: &mut dyn Write) -> ImageResult<()>142 pub(crate) fn write_to(&self, w: &mut dyn Write) -> ImageResult<()> { 143 w.write_u8(self.id_length)?; 144 w.write_u8(self.map_type)?; 145 w.write_u8(self.image_type)?; 146 w.write_u16::<LittleEndian>(self.map_origin)?; 147 w.write_u16::<LittleEndian>(self.map_length)?; 148 w.write_u8(self.map_entry_size)?; 149 w.write_u16::<LittleEndian>(self.x_origin)?; 150 w.write_u16::<LittleEndian>(self.y_origin)?; 151 w.write_u16::<LittleEndian>(self.image_width)?; 152 w.write_u16::<LittleEndian>(self.image_height)?; 153 w.write_u8(self.pixel_depth)?; 154 w.write_u8(self.image_desc)?; 155 Ok(()) 156 } 157 } 158