use byteorder::{LittleEndian, ReadBytesExt}; use std::convert::TryFrom; use std::io; use std::io::{Read, Seek}; use crate::color::ColorType; use crate::error::{ImageError, ImageResult}; use crate::image::{ImageDecoder, ImageReadBuffer}; 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 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 fn is_color(&self) -> bool { match *self { ImageType::RawColorMap | ImageType::RawTrueColor | ImageType::RunTrueColor | ImageType::RunColorMap => true, _ => false, } } /// Does the image use a color map fn is_color_mapped(&self) -> bool { match *self { ImageType::RawColorMap | ImageType::RunColorMap => true, _ => false, } } /// Is the image run length encoded fn is_encoded(&self) -> bool { match *self { ImageType::RunColorMap | ImageType::RunTrueColor | ImageType::RunGrayScale => true, _ => false, } } } /// Header used by TGA image files #[derive(Debug)] struct Header { id_length: u8, // length of ID string map_type: u8, // color map type image_type: u8, // image type code map_origin: u16, // starting index of map map_length: u16, // length of map map_entry_size: u8, // size of map entries in bits x_origin: u16, // x-origin of image y_origin: u16, // y-origin of image image_width: u16, // width of image image_height: u16, // height of image pixel_depth: u8, // bits per pixel image_desc: u8, // image descriptor } impl Header { /// Create a header with all values set to zero fn new() -> Header { Header { id_length: 0, map_type: 0, image_type: 0, map_origin: 0, map_length: 0, map_entry_size: 0, x_origin: 0, y_origin: 0, image_width: 0, image_height: 0, pixel_depth: 0, image_desc: 0, } } /// Load the header with values from the reader fn from_reader(r: &mut dyn Read) -> ImageResult
{ Ok(Header { id_length: r.read_u8()?, map_type: r.read_u8()?, image_type: r.read_u8()?, map_origin: r.read_u16::()?, map_length: r.read_u16::()?, map_entry_size: r.read_u8()?, x_origin: r.read_u16::()?, y_origin: r.read_u16::()?, image_width: r.read_u16::()?, image_height: r.read_u16::()?, pixel_depth: r.read_u8()?, image_desc: r.read_u8()?, }) } } struct ColorMap { /// sizes in bytes start_offset: usize, entry_size: usize, bytes: Vec, } impl ColorMap { pub(crate) fn from_reader( r: &mut dyn Read, start_offset: u16, num_entries: u16, bits_per_entry: u8, ) -> ImageResult { let bytes_per_entry = (bits_per_entry as usize + 7) / 8; let mut bytes = vec![0; bytes_per_entry * num_entries as usize]; r.read_exact(&mut bytes)?; Ok(ColorMap { entry_size: bytes_per_entry, start_offset: start_offset as usize, bytes, }) } /// Get one entry from the color map pub(crate) fn get(&self, index: usize) -> &[u8] { let entry = self.start_offset + self.entry_size * index; &self.bytes[entry..entry + self.entry_size] } } /// The representation of a TGA decoder pub struct TgaDecoder { r: R, width: usize, height: usize, bytes_per_pixel: usize, has_loaded_metadata: bool, image_type: ImageType, color_type: ColorType, header: Header, color_map: Option, // Used in read_scanline line_read: Option, line_remain_buff: Vec, } impl TgaDecoder { /// Create a new decoder that decodes from the stream `r` pub fn new(r: R) -> ImageResult> { let mut decoder = TgaDecoder { r, width: 0, height: 0, bytes_per_pixel: 0, has_loaded_metadata: false, image_type: ImageType::Unknown, color_type: ColorType::L8, header: Header::new(), color_map: None, line_read: None, line_remain_buff: Vec::new(), }; decoder.read_metadata()?; Ok(decoder) } fn read_header(&mut self) -> ImageResult<()> { self.header = Header::from_reader(&mut self.r)?; self.image_type = ImageType::new(self.header.image_type); self.width = self.header.image_width as usize; self.height = self.header.image_height as usize; self.bytes_per_pixel = (self.header.pixel_depth as usize + 7) / 8; Ok(()) } fn read_metadata(&mut self) -> ImageResult<()> { if !self.has_loaded_metadata { self.read_header()?; self.read_image_id()?; self.read_color_map()?; self.read_color_information()?; self.has_loaded_metadata = true; } Ok(()) } /// Loads the color information for the decoder /// /// To keep things simple, we won't handle bit depths that aren't divisible /// by 8 and are less than 32. fn read_color_information(&mut self) -> ImageResult<()> { if self.header.pixel_depth % 8 != 0 { return Err(ImageError::UnsupportedError( "Bit depth must be divisible by 8".to_string(), )); } if self.header.pixel_depth > 32 { return Err(ImageError::UnsupportedError( "Bit depth must be less than 32".to_string(), )); } let num_alpha_bits = self.header.image_desc & 0b1111; let other_channel_bits = if self.header.map_type != 0 { self.header.map_entry_size } else { if num_alpha_bits > self.header.pixel_depth { return Err(ImageError::UnsupportedError( format!("Color format not supported. Alpha bits: {}", num_alpha_bits), )); } self.header.pixel_depth - num_alpha_bits }; let color = self.image_type.is_color(); match (num_alpha_bits, other_channel_bits, color) { // really, the encoding is BGR and BGRA, this is fixed // up with `TgaDecoder::reverse_encoding`. (0, 32, true) => self.color_type = ColorType::Rgba8, (8, 24, true) => self.color_type = ColorType::Rgba8, (0, 24, true) => self.color_type = ColorType::Rgb8, (8, 8, false) => self.color_type = ColorType::La8, (0, 8, false) => self.color_type = ColorType::L8, _ => { return Err(ImageError::UnsupportedError(format!( "Color format not supported. Bit depth: {}, Alpha bits: {}", other_channel_bits, num_alpha_bits ))) } } Ok(()) } /// Read the image id field /// /// We're not interested in this field, so this function skips it if it /// is present fn read_image_id(&mut self) -> ImageResult<()> { self.r .seek(io::SeekFrom::Current(i64::from(self.header.id_length)))?; Ok(()) } fn read_color_map(&mut self) -> ImageResult<()> { if self.header.map_type == 1 { self.color_map = Some(ColorMap::from_reader( &mut self.r, self.header.map_origin, self.header.map_length, self.header.map_entry_size, )?); } Ok(()) } /// Expands indices into its mapped color fn expand_color_map(&self, pixel_data: &[u8]) -> Vec { #[inline] fn bytes_to_index(bytes: &[u8]) -> usize { let mut result = 0usize; for byte in bytes.iter() { result = result << 8 | *byte as usize; } result } let bytes_per_entry = (self.header.map_entry_size as usize + 7) / 8; let mut result = Vec::with_capacity(self.width * self.height * bytes_per_entry); let color_map = self.color_map.as_ref().unwrap(); for chunk in pixel_data.chunks(self.bytes_per_pixel) { let index = bytes_to_index(chunk); result.extend(color_map.get(index).iter().cloned()); } result } /// Reads a run length encoded data for given number of bytes fn read_encoded_data(&mut self, num_bytes: usize) -> io::Result> { let mut pixel_data = Vec::with_capacity(num_bytes); while pixel_data.len() < num_bytes { let run_packet = self.r.read_u8()?; // If the highest bit in `run_packet` is set, then we repeat pixels // // Note: the TGA format adds 1 to both counts because having a count // of 0 would be pointless. if (run_packet & 0x80) != 0 { // high bit set, so we will repeat the data let repeat_count = ((run_packet & !0x80) + 1) as usize; let mut data = Vec::with_capacity(self.bytes_per_pixel); self.r .by_ref() .take(self.bytes_per_pixel as u64) .read_to_end(&mut data)?; for _ in 0usize..repeat_count { pixel_data.extend(data.iter().cloned()); } } else { // not set, so `run_packet+1` is the number of non-encoded pixels let num_raw_bytes = (run_packet + 1) as usize * self.bytes_per_pixel; self.r .by_ref() .take(num_raw_bytes as u64) .read_to_end(&mut pixel_data)?; } } Ok(pixel_data) } /// Reads a run length encoded packet fn read_all_encoded_data(&mut self) -> ImageResult> { let num_bytes = self.width * self.height * self.bytes_per_pixel; Ok(self.read_encoded_data(num_bytes)?) } /// Reads a run length encoded line fn read_encoded_line(&mut self) -> io::Result> { let line_num_bytes = self.width * self.bytes_per_pixel; let remain_len = self.line_remain_buff.len(); if remain_len >= line_num_bytes { let remain_buf = self.line_remain_buff.clone(); self.line_remain_buff = remain_buf[line_num_bytes..].to_vec(); return Ok(remain_buf[0..line_num_bytes].to_vec()); } let num_bytes = line_num_bytes - remain_len; let line_data = self.read_encoded_data(num_bytes)?; let mut pixel_data = Vec::with_capacity(line_num_bytes); pixel_data.append(&mut self.line_remain_buff); pixel_data.extend_from_slice(&line_data[..num_bytes]); // put the remain data to line_remain_buff self.line_remain_buff = line_data[num_bytes..].to_vec(); Ok(pixel_data) } /// Reverse from BGR encoding to RGB encoding /// /// TGA files are stored in the BGRA encoding. This function swaps /// the blue and red bytes in the `pixels` array. fn reverse_encoding(&mut self, pixels: &mut [u8]) { // We only need to reverse the encoding of color images match self.color_type { ColorType::Rgb8 | ColorType::Rgba8 => { for chunk in pixels.chunks_mut(self.bytes_per_pixel) { chunk.swap(0, 2); } } _ => {} } } /// Flip the image vertically depending on the screen origin bit /// /// The bit in position 5 of the image descriptor byte is the screen origin bit. /// If it's 1, the origin is in the top left corner. /// If it's 0, the origin is in the bottom left corner. /// This function checks the bit, and if it's 0, flips the image vertically. fn flip_vertically(&mut self, pixels: &mut [u8]) { if self.is_flipped_vertically() { let num_bytes = pixels.len(); let width_bytes = num_bytes / self.height; // Flip the image vertically. for vertical_index in 0..(self.height / 2) { let vertical_target = (self.height - vertical_index) * width_bytes - width_bytes; for horizontal_index in 0..width_bytes { let source = vertical_index * width_bytes + horizontal_index; let target = vertical_target + horizontal_index; pixels.swap(target, source); } } } } /// Check whether the image is vertically flipped /// /// The bit in position 5 of the image descriptor byte is the screen origin bit. /// If it's 1, the origin is in the top left corner. /// If it's 0, the origin is in the bottom left corner. /// This function checks the bit, and if it's 0, flips the image vertically. fn is_flipped_vertically(&self) -> bool { let screen_origin_bit = 0b10_0000 & self.header.image_desc != 0; !screen_origin_bit } fn read_scanline(&mut self, buf: &mut [u8]) -> io::Result { if let Some(line_read) = self.line_read { if line_read == self.height { return Ok(0); } } // read the pixels from the data region let mut pixel_data = if self.image_type.is_encoded() { self.read_encoded_line()? } else { let num_raw_bytes = self.width * self.bytes_per_pixel; let mut buf = vec![0; num_raw_bytes]; self.r.by_ref().read_exact(&mut buf)?; buf }; // expand the indices using the color map if necessary if self.image_type.is_color_mapped() { pixel_data = self.expand_color_map(&pixel_data) } self.reverse_encoding(&mut pixel_data); // copy to the output buffer buf[..pixel_data.len()].copy_from_slice(&pixel_data); self.line_read = Some(self.line_read.unwrap_or(0) + 1); Ok(pixel_data.len()) } } impl<'a, R: 'a + Read + Seek> ImageDecoder<'a> for TgaDecoder { type Reader = TGAReader; fn dimensions(&self) -> (u32, u32) { (self.width as u32, self.height as u32) } fn color_type(&self) -> ColorType { self.color_type } fn scanline_bytes(&self) -> u64 { // This cannot overflow because TGA has a maximum width of u16::MAX_VALUE and // `bytes_per_pixel` is a u8. u64::from(self.color_type.bytes_per_pixel()) * self.width as u64 } fn into_reader(self) -> ImageResult { Ok(TGAReader { buffer: ImageReadBuffer::new(self.scanline_bytes(), self.total_bytes()), decoder: self, }) } fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> { assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes())); // read the pixels from the data region let len = if self.image_type.is_encoded() { let pixel_data = self.read_all_encoded_data()?; buf[0..pixel_data.len()].copy_from_slice(&pixel_data); pixel_data.len() } else { let num_raw_bytes = self.width * self.height * self.bytes_per_pixel; self.r.by_ref().read_exact(&mut buf[0..num_raw_bytes])?; num_raw_bytes }; // expand the indices using the color map if necessary if self.image_type.is_color_mapped() { let pixel_data = self.expand_color_map(&buf[0..len]); buf.copy_from_slice(&pixel_data); } self.reverse_encoding(buf); self.flip_vertically(buf); Ok(()) } } pub struct TGAReader { buffer: ImageReadBuffer, decoder: TgaDecoder, } impl Read for TGAReader { fn read(&mut self, buf: &mut [u8]) -> io::Result { let decoder = &mut self.decoder; self.buffer.read(buf, |buf| decoder.read_scanline(buf)) } }