use std::borrow::Cow; use std::io; use std::cmp; use std::mem; use std::iter; use std::io::prelude::*; use crate::common::{Block, Frame}; mod decoder; pub use self::decoder::{ PLTE_CHANNELS, StreamingDecoder, Decoded, DecodingError, DecodingFormatError, Extensions, Version }; const N_CHANNELS: usize = 4; /// Output mode for the image data #[derive(Clone, Copy, Debug, PartialEq)] #[repr(u8)] pub enum ColorOutput { /// The decoder expands the image data to 32bit RGBA. /// This affects: /// /// - The buffer buffer of the `Frame` returned by `Decoder::read_next_frame`. /// - `Decoder::fill_buffer`, `Decoder::buffer_size` and `Decoder::line_length`. RGBA = 0, /// The decoder returns the raw indexed data. Indexed = 1, } #[derive(Clone, Debug)] /// Memory limit in bytes. `MemoryLimit(0)` means /// that there is no memory limit set. pub struct MemoryLimit(pub u32); impl MemoryLimit { /// Enforce no memory limit. /// /// If you intend to process images from unknown origins this is a potentially dangerous /// constant to use, as your program could be vulnerable to decompression bombs. That is, /// malicious images crafted specifically to require an enormous amount of memory to process /// while having a disproportionately small file size. /// /// The risks for modern machines are a bit smaller as the dimensions of each frame can not /// exceed `u32::MAX` (~4Gb) but this is still a significant amount of memory. pub const NONE: MemoryLimit = MemoryLimit(0); fn buffer_size(&self, color: ColorOutput, width: u16, height: u16) -> Option { let pixels = u32::from(width) * u32::from(height); let bytes_per_pixel = match color { ColorOutput::Indexed => 1, ColorOutput::RGBA => 4, }; if self.0 > 0 && pixels > self.0 / bytes_per_pixel { None } else { Some(pixels as usize * bytes_per_pixel as usize) } } } /// Options for opening a GIF decoder. #[derive(Clone, Debug)] pub struct DecodeOptions { memory_limit: MemoryLimit, color_output: ColorOutput, check_frame_consistency: bool, check_for_end_code: bool, allow_unknown_blocks: bool, } impl DecodeOptions { /// Creates a new decoder builder pub fn new() -> DecodeOptions { DecodeOptions { memory_limit: MemoryLimit(50_000_000), // 50 MB color_output: ColorOutput::Indexed, check_frame_consistency: false, check_for_end_code: false, allow_unknown_blocks: false, } } /// Configure how color data is decoded. pub fn set_color_output(&mut self, color: ColorOutput) { self.color_output = color; } /// Configure a memory limit for decoding. pub fn set_memory_limit(&mut self, limit: MemoryLimit) { self.memory_limit = limit; } /// Configure if frames must be within the screen descriptor. /// /// The default is `false`. /// /// When turned on, all frame descriptors being read must fit within the screen descriptor or /// otherwise an error is returned and the stream left in an unspecified state. /// /// When turned off, frames may be arbitrarily larger or offset in relation to the screen. Many /// other decoder libraries handle this in highly divergent ways. This moves all checks to the /// caller, for example to emulate a specific style. pub fn check_frame_consistency(&mut self, check: bool) { self.check_frame_consistency = check; } /// Configure if LZW encoded blocks must end with a marker end code. /// /// The default is `false`. /// /// When turned on, all image data blocks—which are LZW encoded—must contain a special bit /// sequence signalling the end of the data. LZW processing terminates when this code is /// encountered. The specification states that it must be the last code output by the encoder /// for an image. /// /// When turned off then image data blocks can simply end. Note that this might silently ignore /// some bits of the last or second to last byte. pub fn check_lzw_end_code(&mut self, check: bool) { self.check_for_end_code = check; } /// Configure if unknown blocks are allowed to be decoded. /// /// The default is `false`. /// /// When turned on, the decoder will allow unknown blocks to be in the /// `BlockStart` position. /// /// When turned off, decoded block starts must mark an `Image`, `Extension`, /// or `Trailer` block. Otherwise, the decoded image will return an error. /// If an unknown block error is returned from decoding, enabling this /// setting may allow for a further state of decoding on the next attempt. pub fn allow_unknown_blocks(&mut self, check: bool) { self.allow_unknown_blocks = check; } /// Reads the logical screen descriptor including the global color palette /// /// Returns a `Decoder`. All decoder configuration has to be done beforehand. pub fn read_info(self, r: R) -> Result, DecodingError> { Decoder::with_no_init(r, StreamingDecoder::with_options(&self), self).init() } } struct ReadDecoder { reader: io::BufReader, decoder: StreamingDecoder, at_eof: bool } impl ReadDecoder { fn decode_next(&mut self) -> Result, DecodingError> { while !self.at_eof { let (consumed, result) = { let buf = self.reader.fill_buf()?; if buf.len() == 0 { return Err(DecodingError::format( "unexpected EOF" )) } self.decoder.update(buf)? }; self.reader.consume(consumed); match result { Decoded::Nothing => (), Decoded::BlockStart(Block::Trailer) => { self.at_eof = true }, result => return Ok(unsafe{ // FIXME: #6393 Some(mem::transmute::(result)) }), } } Ok(None) } } #[allow(dead_code)] /// GIF decoder pub struct Decoder { decoder: ReadDecoder, color_output: ColorOutput, memory_limit: MemoryLimit, bg_color: Option, global_palette: Option>, current_frame: Frame<'static>, buffer: Vec, } impl Decoder where R: Read { /// Create a new decoder with default options. pub fn new(reader: R) -> Result { DecodeOptions::new().read_info(reader) } /// Return a builder that allows configuring limits etc. pub fn build() -> DecodeOptions { DecodeOptions::new() } fn with_no_init(reader: R, decoder: StreamingDecoder, options: DecodeOptions) -> Decoder { Decoder { decoder: ReadDecoder { reader: io::BufReader::new(reader), decoder, at_eof: false }, bg_color: None, global_palette: None, buffer: Vec::with_capacity(32), color_output: options.color_output, memory_limit: options.memory_limit, current_frame: Frame::default(), } } fn init(mut self) -> Result { loop { match self.decoder.decode_next()? { Some(Decoded::BackgroundColor(bg_color)) => { self.bg_color = Some(bg_color) } Some(Decoded::GlobalPalette(palette)) => { self.global_palette = if palette.len() > 0 { Some(palette) } else { None }; break }, Some(_) => { // Unreachable since this loop exists after the global // palette has been read. unreachable!() }, None => return Err(DecodingError::format( "file does not contain any image data" )) } } // If the background color is invalid, ignore it if let Some(ref palette) = self.global_palette { if self.bg_color.unwrap_or(0) as usize >= (palette.len() / PLTE_CHANNELS) { self.bg_color = None; } } Ok(self) } /// Returns the next frame info pub fn next_frame_info(&mut self) -> Result>, DecodingError> { if !self.buffer.is_empty() { // FIXME: Warn about discarding data? self.buffer.clear(); } loop { match self.decoder.decode_next()? { Some(Decoded::Frame(frame)) => { self.current_frame = frame.clone(); if frame.palette.is_none() && self.global_palette.is_none() { return Err(DecodingError::format( "no color table available for current frame" )) } break }, Some(_) => (), None => return Ok(None) } } Ok(Some(&self.current_frame)) } /// Reads the next frame from the image. /// /// Do not call `Self::next_frame_info` beforehand. /// Deinterlaces the result. pub fn read_next_frame(&mut self) -> Result>, DecodingError> { if let Some(frame) = self.next_frame_info()? { let (width, height) = (frame.width, frame.height); let pixel_bytes = self.memory_limit .buffer_size(self.color_output, width, height) .ok_or_else(|| { DecodingError::format("image is too large to decode") })?; debug_assert_eq!( pixel_bytes, self.buffer_size(), "Checked computation diverges from required buffer size" ); let mut vec = vec![0; pixel_bytes]; self.read_into_buffer(&mut vec)?; self.current_frame.buffer = Cow::Owned(vec); self.current_frame.interlaced = false; Ok(Some(&self.current_frame)) } else { Ok(None) } } /// Reads the data of the current frame into a pre-allocated buffer. /// /// `Self::next_frame_info` needs to be called beforehand. /// The length of `buf` must be at least `Self::buffer_size`. /// Deinterlaces the result. pub fn read_into_buffer(&mut self, buf: &mut [u8]) -> Result<(), DecodingError> { if self.current_frame.interlaced { let width = self.line_length(); let height = self.current_frame.height as usize; for row in (InterlaceIterator { len: height, next: 0, pass: 0 }) { if !self.fill_buffer(&mut buf[row*width..][..width])? { return Err(DecodingError::format("image truncated")) } } } else { let buf = &mut buf[..self.buffer_size()]; if !self.fill_buffer(buf)? { return Err(DecodingError::format("image truncated")) } }; Ok(()) } /// Reads data of the current frame into a pre-allocated buffer until the buffer has been /// filled completely. /// /// `Self::next_frame_info` needs to be called beforehand. Returns `true` if the supplied /// buffer could be filled completely. Should not be called after `false` had been returned. pub fn fill_buffer(&mut self, mut buf: &mut [u8]) -> Result { use self::ColorOutput::*; const PLTE_CHANNELS: usize = 3; macro_rules! handle_data( ($data:expr) => { match self.color_output { RGBA => { let transparent = self.current_frame.transparent; let palette: &[u8] = match self.current_frame.palette { Some(ref table) => &*table, None => &*self.global_palette.as_ref().unwrap(), }; let len = cmp::min(buf.len()/N_CHANNELS, $data.len()); for (rgba, &idx) in buf[..len*N_CHANNELS].chunks_mut(N_CHANNELS).zip($data.iter()) { let plte_offset = PLTE_CHANNELS * idx as usize; if palette.len() >= plte_offset + PLTE_CHANNELS { let colors = &palette[plte_offset..]; rgba[0] = colors[0]; rgba[1] = colors[1]; rgba[2] = colors[2]; rgba[3] = if let Some(t) = transparent { if t == idx { 0x00 } else { 0xFF } } else { 0xFF } } } (len, N_CHANNELS) }, Indexed => { let len = cmp::min(buf.len(), $data.len()); buf[..len].copy_from_slice(&$data[..len]); (len, 1) } } } ); let buf_len = self.buffer.len(); if buf_len > 0 { let (len, channels) = handle_data!(&self.buffer); let _ = self.buffer.drain(..len); buf = &mut buf[len*channels..]; if buf.len() == 0 { return Ok(true) } } loop { match self.decoder.decode_next()? { Some(Decoded::Data(data)) => { let (len, channels) = handle_data!(data); buf = &mut buf[len*channels..]; // shorten buf if buf.len() > 0 { continue } else if len < data.len() { self.buffer.extend_from_slice(&data[len..]); } return Ok(true) }, Some(_) => return Ok(false), // make sure that no important result is missed None => return Ok(false) } } } /// Output buffer size pub fn buffer_size(&self) -> usize { self.line_length() * self.current_frame.height as usize } /// Line length of the current frame pub fn line_length(&self) -> usize { use self::ColorOutput::*; match self.color_output { RGBA => self.current_frame.width as usize * N_CHANNELS, Indexed => self.current_frame.width as usize } } /// Returns the color palette relevant for the current (next) frame pub fn palette(&self) -> Result<&[u8], DecodingError> { // TODO prevent planic Ok(match self.current_frame.palette { Some(ref table) => &*table, None => &*self.global_palette.as_ref().ok_or(DecodingError::format( "no color table available for current frame" ))?, }) } /// The global color palette pub fn global_palette(&self) -> Option<&[u8]> { self.global_palette.as_ref().map(|v| &**v) } /// Width of the image pub fn width(&self) -> u16 { self.decoder.decoder.width() } /// Height of the image pub fn height(&self) -> u16 { self.decoder.decoder.height() } /// Index of the background color in the global palette pub fn bg_color(&self) -> Option { self.bg_color.map(|v| v as usize) } } struct InterlaceIterator { len: usize, next: usize, pass: usize } impl iter::Iterator for InterlaceIterator { type Item = usize; fn next(&mut self) -> Option { if self.len == 0 || self.pass > 3 { return None } let mut next = self.next + [8, 8, 4, 2][self.pass]; while next >= self.len { next = [4, 2, 1, 0][self.pass]; self.pass += 1; } mem::swap(&mut next, &mut self.next); Some(next) } } #[cfg(test)] mod test { use std::fs::File; use super::{Decoder, InterlaceIterator}; #[test] fn test_simple_indexed() { let mut decoder = Decoder::new(File::open("tests/samples/sample_1.gif").unwrap()).unwrap(); let frame = decoder.read_next_frame().unwrap().unwrap(); assert_eq!(&*frame.buffer, &[ 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1 ][..]) } #[test] fn test_interlace_iterator() { for &(len, expect) in &[ (0, &[][..]), (1, &[0][..]), (2, &[0, 1][..]), (3, &[0, 2, 1][..]), (4, &[0, 2, 1, 3][..]), (5, &[0, 4, 2, 1, 3][..]), (6, &[0, 4, 2, 1, 3, 5][..]), (7, &[0, 4, 2, 6, 1, 3, 5][..]), (8, &[0, 4, 2, 6, 1, 3, 5, 7][..]), (9, &[0, 8, 4, 2, 6, 1, 3, 5, 7][..]), (10, &[0, 8, 4, 2, 6, 1, 3, 5, 7, 9][..]), (11, &[0, 8, 4, 2, 6, 10, 1, 3, 5, 7, 9][..]), (12, &[0, 8, 4, 2, 6, 10, 1, 3, 5, 7, 9, 11][..]), (13, &[0, 8, 4, 12, 2, 6, 10, 1, 3, 5, 7, 9, 11][..]), (14, &[0, 8, 4, 12, 2, 6, 10, 1, 3, 5, 7, 9, 11, 13][..]), (15, &[0, 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13][..]), (16, &[0, 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15][..]), (17, &[0, 8, 16, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15][..]), ] { let iter = InterlaceIterator { len: len, next: 0, pass: 0 }; let lines = iter.collect::>(); assert_eq!(lines, expect); } } }