diff --git a/src/tga/decoder.rs b/src/tga/decoder.rs index 5aa011e384..f896b6a08e 100644 --- a/src/tga/decoder.rs +++ b/src/tga/decoder.rs @@ -171,6 +171,10 @@ pub struct TGADecoder { header: Header, color_map: Option, + + // Used in read_scanline + line_read: Option, + line_remain_buff: Vec, } impl TGADecoder { @@ -189,6 +193,9 @@ impl TGADecoder { header: Header::new(), color_map: None, + + line_read: None, + line_remain_buff: Vec::new(), } } @@ -305,7 +312,7 @@ impl TGADecoder { fn read_image_data(&mut self) -> ImageResult> { // read the pixels from the data region let mut pixel_data = if self.image_type.is_encoded() { - try!(self.read_encoded_data()) + try!(self.read_all_encoded_data()) } else { let num_raw_bytes = self.width * self.height * self.bytes_per_pixel; let mut buf = vec![0; num_raw_bytes]; @@ -325,9 +332,8 @@ impl TGADecoder { Ok(pixel_data) } - /// Reads a run length encoded packet - fn read_encoded_data(&mut self) -> ImageResult> { - let num_bytes = self.width * self.height * self.bytes_per_pixel; + /// Reads a run length encoded data for given number of bytes + fn read_encoded_data(&mut self, num_bytes: usize) -> ImageResult> { let mut pixel_data = Vec::with_capacity(num_bytes); while pixel_data.len() < num_bytes { @@ -354,6 +360,39 @@ impl TGADecoder { 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; + + self.read_encoded_data(num_bytes) + } + + /// Reads a run length encoded line + fn read_encoded_line(&mut self) -> ImageResult> { + 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 @@ -377,10 +416,7 @@ impl TGADecoder { /// 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]) { - let screen_origin_bit = 0b10_0000 & self.header.image_desc != 0; - - - if !screen_origin_bit { + if self.is_flipped_vertically() { let num_bytes = pixels.len(); let width_bytes = num_bytes / self.height; @@ -398,6 +434,17 @@ impl TGADecoder { } } } + + /// 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 + } } impl ImageDecoder for TGADecoder { @@ -416,11 +463,45 @@ impl ImageDecoder for TGADecoder { fn row_len(&mut self) -> ImageResult { try!(self.read_metadata()); - Ok(self.bytes_per_pixel * 8 * self.width) + Ok(self.bytes_per_pixel * self.width) } - fn read_scanline(&mut self, _buf: &mut [u8]) -> ImageResult { - unimplemented!(); + fn read_scanline(&mut self, buf: &mut [u8]) -> ImageResult { + try!(self.read_metadata()); + + if let Some(line_read) = self.line_read { + if line_read == self.height { + return Err(ImageError::ImageEnd); + } + } + + // read the pixels from the data region + let mut pixel_data = if self.image_type.is_encoded() { + try!(self.read_encoded_line()) + } else { + let num_raw_bytes = self.width * self.bytes_per_pixel; + let mut buf = vec![0; num_raw_bytes]; + try!(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); + + let mut row_index = self.line_read.unwrap_or(0) + 1; + self.line_read = Some(row_index); + + if self.is_flipped_vertically() { + row_index = self.height - (row_index-1); + } + + Ok(row_index as u32) } fn read_image(&mut self) -> ImageResult {