use std::borrow::Cow;
use std::io;
use std::cmp;
use std::mem;
use std::iter;
use std::io::prelude::*;
use traits::{Parameter, SetParameter};
use common::Frame;
use util;
mod decoder;
pub use self::decoder::{
PLTE_CHANNELS, StreamingDecoder, Decoded, DecodingError, Extensions
};
const N_CHANNELS: usize = 4;
impl<T, R> Parameter<Decoder<R>> for T
where T: Parameter<StreamingDecoder>, R: Read {
type Result = ();
fn set_param(self, this: &mut Decoder<R>) {
this.decoder.set(self);
}
}
#[derive(PartialEq, Debug)]
#[repr(u8)]
pub enum ColorOutput {
RGBA = 0,
Indexed = 1,
}
impl<R: Read> Parameter<Decoder<R>> for ColorOutput {
type Result = ();
fn set_param(self, this: &mut Decoder<R>) {
this.color_output = self
}
}
#[derive(Debug)]
pub struct MemoryLimit(pub u32);
impl<R: Read> Parameter<Decoder<R>> for MemoryLimit {
type Result = ();
fn set_param(self, this: &mut Decoder<R>) {
let MemoryLimit(limit) = self;
this.memory_limit = limit
}
}
pub struct Decoder<R: Read> {
r: R,
decoder: StreamingDecoder,
memory_limit: u32,
color_output: ColorOutput,
}
impl<R: Read> Decoder<R> {
pub fn new(r: R) -> Decoder<R> {
Decoder {
r: r,
decoder: StreamingDecoder::new(),
memory_limit: 50_000_000,
color_output: ColorOutput::Indexed
}
}
pub fn read_info(self) -> Result<Reader<R>, DecodingError> {
Reader::new(self.r, self.decoder, self.color_output, self.memory_limit).init()
}
}
struct ReadDecoder<R: Read> {
reader: io::BufReader<R>,
decoder: StreamingDecoder,
at_eof: bool
}
impl<R: Read> ReadDecoder<R> {
fn decode_next(&mut self) -> Result<Option<Decoded>, 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(::common::Block::Trailer) => {
self.at_eof = true
},
result => return Ok(unsafe{
Some(mem::transmute::<Decoded, Decoded>(result))
}),
}
}
Ok(None)
}
}
#[allow(dead_code)]
pub struct Reader<R: Read> {
decoder: ReadDecoder<R>,
color_output: ColorOutput,
memory_limit: u32,
bg_color: Option<u8>,
global_palette: Option<Vec<u8>>,
current_frame: Frame<'static>,
buffer: Vec<u8>,
offset: usize
}
impl<R> Reader<R> where R: Read {
fn new(reader: R, decoder: StreamingDecoder,
color_output: ColorOutput, memory_limit: u32
) -> Reader<R> {
Reader {
decoder: ReadDecoder {
reader: io::BufReader::new(reader),
decoder: decoder,
at_eof: false
},
bg_color: None,
global_palette: None,
buffer: Vec::with_capacity(32),
color_output: color_output,
memory_limit: memory_limit,
current_frame: Frame::default(),
offset: 0
}
}
fn init(mut self) -> Result<Self, DecodingError> {
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!()
},
None => return Err(DecodingError::Format(
"File does not contain any image data"
))
}
}
if let &Some(ref palette) = &self.global_palette {
if self.bg_color.unwrap_or(0) as usize >= palette.len() {
self.bg_color = None;
}
}
Ok(self)
}
pub fn next_frame_info(&mut self) -> Result<Option<&Frame<'static>>, DecodingError> {
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."
))
}
if self.memory_limit > 0 && (
(frame.width as u32 * frame.height as u32)
> self.memory_limit
) {
return Err(DecodingError::Format(
"Image is too large to decode."
))
}
break
},
Some(_) => (),
None => return Ok(None)
}
}
Ok(Some(&self.current_frame))
}
pub fn read_next_frame(&mut self) -> Result<Option<&Frame<'static>>, DecodingError> {
if self.next_frame_info()?.is_some() {
let mut vec = vec![0; self.buffer_size()];
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)
}
}
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(())
}
pub fn fill_buffer(&mut self, mut buf: &mut [u8]) -> Result<bool, DecodingError> {
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());
util::copy_memory(&$data[..len], &mut buf[..len]);
(len, 1)
}
}
}
);
let buf_len = self.buffer.len();
if buf_len > 0 {
let (len, channels) = handle_data!(&self.buffer);
self.buffer.truncate(buf_len-len);
let buf_ = buf; 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);
let buf_ = buf; buf = &mut buf_[len*channels..];
if buf.len() > 0 {
continue
} else if len < data.len() {
self.buffer.extend(data[len..].iter().map(|&v| v));
}
return Ok(true)
},
Some(_) => return Ok(false),
None => return Ok(false)
}
}
}
pub fn buffer_size(&self) -> usize {
self.line_length() * self.current_frame.height as usize
}
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
}
}
pub fn palette(&self) -> Result<&[u8], DecodingError> {
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."
))?,
})
}
pub fn global_palette(&self) -> Option<&[u8]> {
self.global_palette.as_ref().map(|v| &**v)
}
pub fn width(&self) -> u16 {
self.decoder.decoder.width()
}
pub fn height(&self) -> u16 {
self.decoder.decoder.height()
}
pub fn bg_color(&self) -> Option<usize> {
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<Self::Item> {
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()).read_info().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::<Vec<_>>();
assert_eq!(lines, expect);
}
}
}
#[cfg(feature = "c_api")]
mod c_interface {
use std::io::prelude::*;
use std::ptr;
use std::borrow::Cow;
use libc::c_int;
use common::Block;
use c_api::{self, GifWord};
use c_api_utils::{CInterface, copy_colormap, copy_data, saved_images_new};
use super::decoder::{Decoded, DecodingError};
use super::{Reader};
impl<R> Reader<R> where R: Read + 'static {
pub fn into_c_interface(self) -> Box<CInterface> {
Box::new(self)
}
}
impl<R: Read> CInterface for Reader<R> {
fn read_screen_desc(&mut self, this: &mut c_api::GifFileType) {
this.SWidth = self.width() as GifWord;
this.SHeight = self.height() as GifWord;
this.SColorResolution = 255;
this.SBackGroundColor = self.bg_color().unwrap_or(0) as GifWord;
this.AspectByte = 0;
self.offset = 0;
}
fn current_image_buffer(&mut self) -> Result<(&[u8], &mut usize), DecodingError> {
if let Cow::Borrowed(_) = self.current_frame.buffer {
self.read_next_frame()?;
}
Ok((&self.current_frame.buffer, &mut self.offset))
}
fn last_ext(&self) -> (u8, &[u8], bool) {
self.decoder.decoder.last_ext()
}
fn next_record_type(&mut self) -> Result<Block, DecodingError> {
loop {
match self.decoder.decode_next()? {
Some(Decoded::BlockStart(type_)) => return Ok(type_),
Some(_) => (),
None => return Ok(Block::Trailer)
}
}
}
fn decode_next(&mut self) -> Result<Option<Decoded>, DecodingError> {
self.decoder.decode_next()
}
}
}