diff options
Diffstat (limited to 'vendor/gif/src')
| -rw-r--r-- | vendor/gif/src/common.rs | 346 | ||||
| -rw-r--r-- | vendor/gif/src/encoder.rs | 434 | ||||
| -rw-r--r-- | vendor/gif/src/lib.rs | 154 | ||||
| -rw-r--r-- | vendor/gif/src/reader/decoder.rs | 724 | ||||
| -rw-r--r-- | vendor/gif/src/reader/mod.rs | 522 | ||||
| -rw-r--r-- | vendor/gif/src/traits.rs | 49 | 
6 files changed, 2229 insertions, 0 deletions
| diff --git a/vendor/gif/src/common.rs b/vendor/gif/src/common.rs new file mode 100644 index 0000000..20ba99b --- /dev/null +++ b/vendor/gif/src/common.rs @@ -0,0 +1,346 @@ +use std::borrow::Cow; +use std::collections::HashMap; +use std::collections::HashSet; + +/// Disposal method +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[repr(u8)] +pub enum DisposalMethod { +    /// StreamingDecoder is not required to take any action. +    Any = 0, +    /// Do not dispose. +    Keep = 1, +    /// Restore to background color. +    Background = 2, +    /// Restore to previous. +    Previous = 3, +} + +impl DisposalMethod { +    /// Converts `u8` to `Option<Self>` +    pub fn from_u8(n: u8) -> Option<DisposalMethod> { +        match n { +            0 => Some(DisposalMethod::Any), +            1 => Some(DisposalMethod::Keep), +            2 => Some(DisposalMethod::Background), +            3 => Some(DisposalMethod::Previous), +            _ => None +        } +    } +} + +/// Known GIF block labels. +/// +/// Note that the block uniquely specifies the layout of bytes that follow and how they are +/// framed. For example, the header always has a fixed length but is followed by a variable amount +/// of additional data. An image descriptor may be followed by a local color table depending on +/// information read in it. Therefore, it doesn't make sense to continue parsing after encountering +/// an unknown block as the semantics of following bytes are unclear. +/// +/// The extension block provides a common framing for an arbitrary amount of application specific +/// data which may be ignored. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[repr(u8)] +pub enum Block { +    /// Image block. +    Image = 0x2C, +    /// Extension block. +    Extension = 0x21, +    /// Image trailer. +    Trailer = 0x3B, +} + +impl Block { +    /// Converts `u8` to `Option<Self>` +    pub fn from_u8(n: u8) -> Option<Block> { +        match n { +            0x2C => Some(Block::Image), +            0x21 => Some(Block::Extension), +            0x3B => Some(Block::Trailer), +            _ => None +        } +    } +} + +/// A newtype wrapper around an arbitrary extension ID. +/// +/// An extension is some amount of byte data organized in sub-blocks so that one can skip over it +/// without knowing the semantics. Though technically you likely want to use a `Application` +/// extension, the library tries to stay flexible here. +/// +/// This allows us to customize the set of impls compared to a raw `u8`. It also clarifies the +/// intent and gives some inherent methods for interoperability with known extension types. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct AnyExtension(pub u8); + +/// Known GIF extension labels. +/// +/// These are extensions which may be interpreted by the library and to which a specification with +/// the internal data layout is known. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[repr(u8)] +pub enum Extension { +    /// Plain Text extension. +    /// +    /// This instructs the decoder to render a text as characters in a grid of cells, in a +    /// mono-spaced font of its choosing. This is seldom actually implemented and ignored by +    /// ImageMagick. The color is always taken from the global table which further complicates any +    /// use. No real information on the frame sequencing of this block is available in the +    /// standard. +    Text = 0x01, +    /// Control extension. +    Control = 0xF9, +    /// Comment extension. +    Comment = 0xFE, +    /// Application extension. +    /// +    /// See [ImageMagick] for an idea of commonly recognized extensions. +    /// +    /// [ImageMagick]: https://github.com/ImageMagick/ImageMagick/blob/b0b58c6303195928060f55f9c3ca8233ab7f7733/coders/gif.c#L1128 +    Application = 0xFF, +} + +impl AnyExtension { +    /// Decode the label as a known extension. +    pub fn into_known(self) -> Option<Extension> { +        Extension::from_u8(self.0) +    } +} + +impl From<Extension> for AnyExtension { +    fn from(ext: Extension) -> Self { +        AnyExtension(ext as u8) +    } +} + +impl Extension { +    /// Converts `u8` to a `Extension` if it is known. +    pub fn from_u8(n: u8) -> Option<Extension> { +        match n { +            0x01 => Some(Extension::Text), +            0xF9 => Some(Extension::Control), +            0xFE => Some(Extension::Comment), +            0xFF => Some(Extension::Application), +            _ => None +        } +    } +} + +/// A GIF frame +#[derive(Debug, Clone)] +pub struct Frame<'a> { +    /// Frame delay in units of 10 ms. +    pub delay: u16, +    /// Disposal method. +    pub dispose: DisposalMethod, +    /// Transparent index (if available). +    pub transparent: Option<u8>, +    /// True if the frame needs user input to be displayed. +    pub needs_user_input: bool, +    /// Offset from the top border of the canvas. +    pub top: u16, +    /// Offset from the left border of the canvas. +    pub left: u16, +    /// Width of the frame. +    pub width: u16, +    /// Height of the frame. +    pub height: u16, +    /// True if the image is interlaced. +    pub interlaced: bool, +    /// Frame local color palette if available. +    pub palette: Option<Vec<u8>>, +    /// Buffer containing the image data. +    /// Only indices unless configured differently. +    pub buffer: Cow<'a, [u8]> +} + +impl<'a> Default for Frame<'a> { +    fn default() -> Frame<'a> { +        Frame { +            delay: 0, +            dispose: DisposalMethod::Keep, +            transparent: None, +            needs_user_input: false, +            top: 0, +            left: 0, +            width: 0, +            height: 0, +            interlaced: false, +            palette: None, +            buffer: Cow::Borrowed(&[]) +        } +    } +} + +impl Frame<'static> { +    /// Creates a frame from pixels in RGBA format. +    /// +    /// This is a lossy method. The `gif` format does not support arbitrary alpha but only a 1-bit +    /// transparency mask per pixel. Any non-zero alpha value will be interpreted as a fully opaque +    /// pixel. Additionally, only 256 colors can appear in a single frame. The palette will be +    /// reduced by the NeuQuant algorithm if necessary. Different frames have independent palettes. +    /// +    /// *Note: This method is not optimized for speed.* +    /// +    /// # Panics: +    /// *   If the length of pixels does not equal `width * height * 4`. +    #[cfg(feature = "color_quant")] +    pub fn from_rgba(width: u16, height: u16, pixels: &mut [u8]) -> Frame<'static> { +        Frame::from_rgba_speed(width, height, pixels, 1) +    } + +    /// Creates a frame from pixels in RGBA format. +    /// +    /// `speed` is a value in the range [1, 30]. +    /// The higher the value the faster it runs at the cost of image quality. +    /// A `speed` of 10 is a good compromise between speed and quality. +    /// +    /// This is a lossy method. The `gif` format does not support arbitrary alpha but only a 1-bit +    /// transparency mask per pixel. Any non-zero alpha value will be interpreted as a fully opaque +    /// pixel. Additionally, only 256 colors can appear in a single frame. The palette will be +    /// reduced by the NeuQuant algorithm if necessary. Different frames have independent palettes. +    /// +    /// # Panics: +    /// *   If the length of pixels does not equal `width * height * 4`. +    /// *   If `speed < 1` or `speed > 30` +    #[cfg(feature = "color_quant")] +    pub fn from_rgba_speed(width: u16, height: u16, pixels: &mut [u8], speed: i32) -> Frame<'static> { +        assert_eq!(width as usize * height as usize * 4, pixels.len(), "Too much or too little pixel data for the given width and height to create a GIF Frame"); +        assert!(speed >= 1 && speed <= 30, "speed needs to be in the range [1, 30]"); +        let mut transparent = None; +        for pix in pixels.chunks_exact_mut(4) { +            if pix[3] != 0 { +                pix[3] = 0xFF; +            } else { +                transparent = Some([pix[0], pix[1], pix[2], pix[3]]) +            } +        } + +        // Attempt to build a palette of all colors. If we go over 256 colors, +        // switch to the NeuQuant algorithm. +        let mut colors: HashSet<(u8, u8, u8, u8)> = HashSet::new(); +        for pixel in pixels.chunks_exact(4) { +            if colors.insert((pixel[0], pixel[1], pixel[2], pixel[3])) && colors.len() > 256 { +                // > 256 colours, let's use NeuQuant. +                let nq = color_quant::NeuQuant::new(speed, 256, pixels); + +                return Frame { +                    width, +                    height, +                    buffer: Cow::Owned(pixels.chunks_exact(4).map(|pix| nq.index_of(pix) as u8).collect()), +                    palette: Some(nq.color_map_rgb()), +                    transparent: transparent.map(|t| nq.index_of(&t) as u8), +                    ..Frame::default() +                }; +            } +        } + +        // Palette size <= 256 elements, we can build an exact palette. +        let mut colors_vec: Vec<(u8, u8, u8, u8)> = colors.into_iter().collect(); +        colors_vec.sort(); +        let palette = colors_vec.iter().flat_map(|&(r, g, b, _a)| [r, g, b]).collect(); +        let colors_lookup: HashMap<(u8, u8, u8, u8), u8> =  colors_vec.into_iter().zip(0..=255).collect(); + +        let index_of = | pixel: &[u8] | +            *colors_lookup.get(&(pixel[0], pixel[1], pixel[2], pixel[3])).unwrap(); + +        return Frame { +            width, +            height, +            buffer: Cow::Owned(pixels.chunks_exact(4).map(|pix| index_of(pix)).collect()), +            palette: Some(palette), +            transparent: transparent.map(|t| index_of(&t)), +            ..Frame::default() +        } +    } + +    /// Creates a frame from a palette and indexed pixels. +    /// +    /// # Panics: +    /// *   If the length of pixels does not equal `width * height`. +    /// *   If the length of palette > `256 * 3`. +    pub fn from_palette_pixels(width: u16, height: u16, pixels: &[u8], palette: &[u8], transparent: Option<u8>) -> Frame<'static> { +        assert_eq!(width as usize * height as usize, pixels.len(), "Too many or too little pixels for the given width and height to create a GIF Frame"); +        assert!(palette.len() <= 256*3, "Too many palette values to create a GIF Frame"); + +        Frame { +            width, +            height, +            buffer: Cow::Owned(pixels.to_vec()), +            palette: Some(palette.to_vec()), +            transparent, +            ..Frame::default() +        } +    } + +    /// Creates a frame from indexed pixels in the global palette. +    /// +    /// # Panics: +    /// *   If the length of pixels does not equal `width * height`. +    pub fn from_indexed_pixels(width: u16, height: u16, pixels: &[u8], transparent: Option<u8>) -> Frame<'static> { +        assert_eq!(width as usize * height as usize, pixels.len(), "Too many or too little pixels for the given width and height to create a GIF Frame"); + +        Frame { +            width, +            height, +            buffer: Cow::Owned(pixels.to_vec()), +            palette: None, +            transparent, +            ..Frame::default() +        } +    } + +    /// Creates a frame from pixels in RGB format. +    /// +    /// This is a lossy method. In the `gif` format only 256 colors can appear in a single frame. +    /// The palette will be reduced by the NeuQuant algorithm if necessary. Different frames have +    /// independent palettes. +    /// +    /// *Note: This method is not optimized for speed.* +    /// +    /// # Panics: +    /// *   If the length of pixels does not equal `width * height * 3`. +    #[cfg(feature = "color_quant")] +    pub fn from_rgb(width: u16, height: u16, pixels: &[u8]) -> Frame<'static> { +        Frame::from_rgb_speed(width, height, pixels, 1) +    } + +    /// Creates a frame from pixels in RGB format. +    /// +    /// `speed` is a value in the range [1, 30]. +    /// +    /// This is a lossy method. In the `gif` format only 256 colors can appear in a single frame. +    /// The palette will be reduced by the NeuQuant algorithm if necessary. Different frames have +    /// independent palettes. +    /// +    /// The higher the value the faster it runs at the cost of image quality. +    /// A `speed` of 10 is a good compromise between speed and quality. +    /// +    /// # Panics: +    /// *   If the length of pixels does not equal `width * height * 3`. +    /// *   If `speed < 1` or `speed > 30` +    #[cfg(feature = "color_quant")] +    pub fn from_rgb_speed(width: u16, height: u16, pixels: &[u8], speed: i32) -> Frame<'static> { +        assert_eq!(width as usize * height as usize * 3, pixels.len(), "Too much or too little pixel data for the given width and height to create a GIF Frame"); +        let mut vec: Vec<u8> = Vec::with_capacity(pixels.len() + width as usize * height as usize); +        for v in pixels.chunks_exact(3) { +            vec.extend_from_slice(&[v[0], v[1], v[2], 0xFF]) +        } +        Frame::from_rgba_speed(width, height, &mut vec, speed) +    } + +    pub(crate) fn required_bytes(&self) -> usize { +        usize::from(self.width) * usize::from(self.height) +    } +} + +#[test] +#[cfg(feature = "color_quant")] +// Creating the `colors_lookup` hashmap in Frame::from_rgba_speed panics due to +// overflow while bypassing NeuQuant and zipping a RangeFrom with 256 colors. +// Changing .zip(0_u8..) to .zip(0_u8..=255) fixes this issue. +fn rgba_speed_avoid_panic_256_colors() { +    let side = 16; +    let pixel_data: Vec<u8> = (0..=255).map(|a| vec![a, a, a]).flatten().collect(); +    Frame::from_rgb(side, side, &pixel_data); +} diff --git a/vendor/gif/src/encoder.rs b/vendor/gif/src/encoder.rs new file mode 100644 index 0000000..693a8cb --- /dev/null +++ b/vendor/gif/src/encoder.rs @@ -0,0 +1,434 @@ +//! # Minimal gif encoder +use std::io; +use std::io::prelude::*; +use std::fmt; +use std::error; +use std::borrow::Cow; + +use weezl::{BitOrder, encode::Encoder as LzwEncoder}; + +use crate::traits::{WriteBytesExt}; +use crate::common::{AnyExtension, Block, DisposalMethod, Extension, Frame}; + +#[derive(Debug)] +enum FormatErrorKind { +    /// The image has too many colors. +    TooManyColors, +    /// The image has no color palette which is required. +    MissingColorPalette, +} + +/// The image has incorrect properties, making it impossible to encode as a gif. +#[derive(Debug)] +pub struct EncodingFormatError { +    kind: FormatErrorKind +} + +impl error::Error for EncodingFormatError {} +impl fmt::Display for EncodingFormatError { +    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { +        match self.kind { +            FormatErrorKind::TooManyColors => write!(fmt, "the image has too many colors"), +            FormatErrorKind::MissingColorPalette => write!(fmt, "the GIF format requires a color palette but none was given") +        } +    } +} + +impl From<FormatErrorKind> for EncodingFormatError { +    fn from(kind: FormatErrorKind) -> Self { +        EncodingFormatError { kind } +    } +} + +#[derive(Debug)] +/// Encoding error. +pub enum EncodingError { +    /// Returned if the to image is not encodable as a gif. +    Format(EncodingFormatError), +    /// Wraps `std::io::Error`. +    Io(io::Error), +} + +impl fmt::Display for EncodingError { +    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { +        match self { +            EncodingError::Io(err) => err.fmt(fmt), +            EncodingError::Format(err) => err.fmt(fmt), +        } +    } +} + +impl error::Error for EncodingError { +    fn source(&self) -> Option<&(dyn error::Error + 'static)> { +        match self { +            EncodingError::Io(err) => Some(err), +            EncodingError::Format(err) => Some(err), +        } +    } +} + +impl From<io::Error> for EncodingError { +    fn from(err: io::Error) -> Self { +        EncodingError::Io(err) +    } +} + +impl From<EncodingFormatError> for EncodingError { +    fn from(err: EncodingFormatError) -> Self { +        EncodingError::Format(err) +    } +} + +impl From<FormatErrorKind> for EncodingError { +    fn from(kind: FormatErrorKind) -> Self { +        EncodingError::Format(kind.into()) +    } +} + + +/// Number of repetitions +#[derive(Copy, Clone, Debug)] +pub enum Repeat { +    /// Finite number of repetitions +    Finite(u16), +    /// Infinite number of repetitions +    Infinite +} + +/// Extension data. +pub enum ExtensionData { +    /// Control extension. Use `ExtensionData::new_control_ext` to construct. +    Control { +        /// Flags. +        flags: u8, +        /// Frame delay. +        delay: u16, +        /// Transparent index. +        trns: u8 +    }, +    /// Sets the number of repetitions +    Repetitions(Repeat) +} + +impl ExtensionData { +    /// Constructor for control extension data. +    /// +    /// `delay` is given in units of 10 ms. +    pub fn new_control_ext(delay: u16, dispose: DisposalMethod, +                           needs_user_input: bool, trns: Option<u8>) -> ExtensionData { +        let mut flags = 0; +        let trns = match trns { +            Some(trns) => { +                flags |= 1; +                trns as u8 +            }, +            None => 0 +        }; +        flags |= (needs_user_input as u8) << 1; +        flags |= (dispose as u8) << 2; +        ExtensionData::Control { +            flags: flags, +            delay: delay, +            trns: trns +        } +    } +} + +impl<W: Write> Encoder<W> { +    /// Creates a new encoder. +    /// +    /// `global_palette` gives the global color palette in the format `[r, g, b, ...]`, +    /// if no global palette shall be used an empty slice may be supplied. +    pub fn new(w: W, width: u16, height: u16, global_palette: &[u8]) -> Result<Self, EncodingError> { +        let buffer_size = (width as usize) * (height as usize); +        Encoder { +            w: Some(w), +            global_palette: false, +            width: width, +            height: height, +            buffer: Vec::with_capacity(buffer_size) +        }.write_global_palette(global_palette) +    } + +    /// Write an extension block that signals a repeat behaviour. +    pub fn set_repeat(&mut self, repeat: Repeat) -> Result<(), EncodingError> { +        self.write_extension(ExtensionData::Repetitions(repeat)) +    } + +    /// Writes the global color palette. +    pub fn write_global_palette(mut self, palette: &[u8]) -> Result<Self, EncodingError> { +        self.global_palette = true; +        let mut flags = 0; +        flags |= 0b1000_0000; +        let num_colors = palette.len() / 3; +        if num_colors > 256 { +            return Err(EncodingError::from(FormatErrorKind::TooManyColors)); +        } +        // Size of global color table. +        flags |= flag_size(num_colors); +        // Color resolution .. FIXME. This is mostly ignored (by ImageMagick at least) but hey, we +        // should use some sensible value here or even allow configuring it? +        flags |= flag_size(num_colors) << 4; // wtf flag +        self.write_screen_desc(flags)?; +        self.write_color_table(palette)?; +        Ok(self) +    } + +    /// Writes a frame to the image. +    /// +    /// Note: This function also writes a control extension if necessary. +    pub fn write_frame(&mut self, frame: &Frame) -> Result<(), EncodingError> { +        self.write_frame_header(frame)?; +        self.write_image_block(&frame.buffer) +    } + +    fn write_frame_header(&mut self, frame: &Frame) -> Result<(), EncodingError> { +        // TODO commented off to pass test in lib.rs +        //if frame.delay > 0 || frame.transparent.is_some() { +            self.write_extension(ExtensionData::new_control_ext( +                frame.delay, +                frame.dispose, +                frame.needs_user_input, +                frame.transparent + +            ))?; +        //} +        let writer = self.w.as_mut().unwrap(); +        writer.write_le(Block::Image as u8)?; +        writer.write_le(frame.left)?; +        writer.write_le(frame.top)?; +        writer.write_le(frame.width)?; +        writer.write_le(frame.height)?; +        let mut flags = 0; +        if frame.interlaced { +            flags |= 0b0100_0000; +        } +        match frame.palette { +            Some(ref palette) => { +                flags |= 0b1000_0000; +                let num_colors = palette.len() / 3; +                if num_colors > 256 { +                    return Err(EncodingError::from(FormatErrorKind::TooManyColors)); +                } +                flags |= flag_size(num_colors); +                writer.write_le(flags)?; +                self.write_color_table(palette) +            }, +            None => if !self.global_palette { +                Err(EncodingError::from(FormatErrorKind::MissingColorPalette)) +            } else { +                writer.write_le(flags).map_err(Into::into) +            } +        } +    } + +    fn write_image_block(&mut self, data: &[u8]) -> Result<(), EncodingError> { +        self.buffer.clear(); +        lzw_encode(data, &mut self.buffer); + +        let writer = self.w.as_mut().unwrap(); +        Self::write_encoded_image_block(writer, &self.buffer) +    } + +    fn write_encoded_image_block(writer: &mut W, data_with_min_code_size: &[u8]) -> Result<(), EncodingError> { +        let (&min_code_size, data) = data_with_min_code_size.split_first().unwrap_or((&2, &[])); +        writer.write_le(min_code_size)?; + +        // Write blocks. `chunks_exact` seems to be slightly faster +        // than `chunks` according to both Rust docs and benchmark results. +        let mut iter = data.chunks_exact(0xFF); +        while let Some(full_block) = iter.next() { +            writer.write_le(0xFFu8)?; +            writer.write_all(full_block)?; +        } +        let last_block = iter.remainder(); +        if !last_block.is_empty() { +            writer.write_le(last_block.len() as u8)?; +            writer.write_all(last_block)?; +        } +        writer.write_le(0u8).map_err(Into::into) +    } + +    fn write_color_table(&mut self, table: &[u8]) -> Result<(), EncodingError> { +        let writer = self.w.as_mut().unwrap(); +        let num_colors = table.len() / 3; +        if num_colors > 256 { +            return Err(EncodingError::from(FormatErrorKind::TooManyColors)); +        } +        let size = flag_size(num_colors); +        writer.write_all(&table[..num_colors * 3])?; +        // Waste some space as of gif spec +        for _ in 0..((2 << size) - num_colors) { +            writer.write_all(&[0, 0, 0])? +        } +        Ok(()) +    } + +    /// Writes an extension to the image. +    /// +    /// It is normally not necessary to call this method manually. +    pub fn write_extension(&mut self, extension: ExtensionData) -> Result<(), EncodingError> { +        use self::ExtensionData::*; +        // 0 finite repetitions can only be achieved +        // if the corresponting extension is not written +        if let Repetitions(Repeat::Finite(0)) = extension { +            return Ok(()) +        } +        let writer = self.w.as_mut().unwrap(); +        writer.write_le(Block::Extension as u8)?; +        match extension { +            Control { flags, delay, trns } => { +                writer.write_le(Extension::Control as u8)?; +                writer.write_le(4u8)?; +                writer.write_le(flags)?; +                writer.write_le(delay)?; +                writer.write_le(trns)?; +            } +            Repetitions(repeat) => { +                writer.write_le(Extension::Application as u8)?; +                writer.write_le(11u8)?; +                writer.write_all(b"NETSCAPE2.0")?; +                writer.write_le(3u8)?; +                writer.write_le(1u8)?; +                match repeat { +                    Repeat::Finite(no) => writer.write_le(no)?, +                    Repeat::Infinite => writer.write_le(0u16)?, +                } +            } +        } +        writer.write_le(0u8).map_err(Into::into) +    } + +    /// Writes a raw extension to the image. +    /// +    /// This method can be used to write an unsupported extension to the file. `func` is the extension +    /// identifier (e.g. `Extension::Application as u8`). `data` are the extension payload blocks. If any +    /// contained slice has a lenght > 255 it is automatically divided into sub-blocks. +    pub fn write_raw_extension(&mut self, func: AnyExtension, data: &[&[u8]]) -> io::Result<()> { +        let writer = self.w.as_mut().unwrap(); +        writer.write_le(Block::Extension as u8)?; +        writer.write_le(func.0)?; +        for block in data { +            for chunk in block.chunks(0xFF) { +                writer.write_le(chunk.len() as u8)?; +                writer.write_all(chunk)?; +            } +        } +        writer.write_le(0u8) +    } + +    /// Writes a frame to the image, but expects `Frame.buffer` to contain LZW-encoded data +    /// from [`Frame::make_lzw_pre_encoded`]. +    /// +    /// Note: This function also writes a control extension if necessary. +    pub fn write_lzw_pre_encoded_frame(&mut self, frame: &Frame) -> Result<(), EncodingError> { +        self.write_frame_header(frame)?; +        let writer = self.w.as_mut().unwrap(); +        Self::write_encoded_image_block(writer, &frame.buffer) +    } + +    /// Writes the logical screen desriptor +    fn write_screen_desc(&mut self, flags: u8) -> io::Result<()> { +        let writer = self.w.as_mut().unwrap(); +        writer.write_all(b"GIF89a")?; +        writer.write_le(self.width)?; +        writer.write_le(self.height)?; +        writer.write_le(flags)?; // packed field +        writer.write_le(0u8)?; // bg index +        writer.write_le(0u8) // aspect ratio +    } + +    /// Gets a reference to the writer instance used by this encoder. +    pub fn get_ref(&self) -> &W { +        self.w.as_ref().unwrap() +    } + +    /// Gets a mutable reference to the writer instance used by this encoder. +    /// +    /// It is inadvisable to directly write to the underlying writer. +    pub fn get_mut(&mut self) -> &mut W { +        self.w.as_mut().unwrap() +    } + +    /// Returns writer instance used by this encoder +    pub fn into_inner(mut self) -> io::Result<W> { +        self.write_trailer()?; +        Ok(self.w.take().unwrap()) +    } + +    /// Write the final tailer. +    fn write_trailer(&mut self) -> io::Result<()> { +        self.w.as_mut().unwrap().write_le(Block::Trailer as u8) +    } +} + +/// Encodes the data into the provided buffer. +/// +/// The first byte is the minimum code size, followed by LZW data. +fn lzw_encode(data: &[u8], buffer: &mut Vec<u8>) { +    let min_code_size = match flag_size(1 + data.iter().copied().max().unwrap_or(0) as usize) + 1 { +        1 => 2, // As per gif spec: The minimal code size has to be >= 2 +        n => n +    }; +    buffer.push(min_code_size); +    let mut enc = LzwEncoder::new(BitOrder::Lsb, min_code_size); +    let len = enc.into_vec(buffer).encode_all(data).consumed_out; +    buffer.truncate(len+1); +} + +impl Frame<'_> { +    /// Replace frame's buffer with a LZW-compressed one for use with [`Encoder::write_lzw_pre_encoded_frame`]. +    /// +    /// Frames can be compressed in any order, separately from the `Encoder`, which can be used to compress frames in parallel. +    pub fn make_lzw_pre_encoded(&mut self) { +        let mut buffer = Vec::with_capacity(self.buffer.len() / 2); +        lzw_encode(&self.buffer, &mut buffer); +        self.buffer = Cow::Owned(buffer); +    } +} + +/// GIF encoder. +pub struct Encoder<W: Write> { +    w: Option<W>, +    global_palette: bool, +    width: u16, +    height: u16, +    buffer: Vec<u8> +} + +impl<W: Write> Drop for Encoder<W> { + +    #[cfg(feature = "raii_no_panic")] +    fn drop(&mut self) { +        if self.w.is_some() { +            let _ = self.write_trailer(); +        } +    } + +    #[cfg(not(feature = "raii_no_panic"))] +    fn drop(&mut self) { +        if self.w.is_some() { +            self.write_trailer().unwrap(); +        } +    } +} + +// Color table size converted to flag bits +fn flag_size(size: usize) -> u8 { +    match size { +        0  ..=2   => 0, +        3  ..=4   => 1, +        5  ..=8   => 2, +        9  ..=16  => 3, +        17 ..=32  => 4, +        33 ..=64  => 5, +        65 ..=128 => 6, +        129..=256 => 7, +        _ => 7 +    } +} + +#[test] +fn error_cast() { +    let _ : Box<dyn error::Error> = EncodingError::from(FormatErrorKind::MissingColorPalette).into(); +} diff --git a/vendor/gif/src/lib.rs b/vendor/gif/src/lib.rs new file mode 100644 index 0000000..8eb2a61 --- /dev/null +++ b/vendor/gif/src/lib.rs @@ -0,0 +1,154 @@ +//! # GIF en- and decoding library [](https://github.com/image-rs/image-gif/actions) +//!  +//! GIF en- and decoder written in Rust ([API Documentation](https://docs.rs/gif)). +//!  +//! # GIF encoding and decoding library +//!  +//! This library provides all functions necessary to de- and encode GIF files. +//!  +//! ## High level interface +//!  +//! The high level interface consists of the two types +//! [`Encoder`](struct.Encoder.html) and [`Decoder`](struct.Decoder.html). +//!  +//! ### Decoding GIF files +//!  +//! ```rust +//! // Open the file +//! use std::fs::File; +//! let mut decoder = gif::DecodeOptions::new(); +//! // Configure the decoder such that it will expand the image to RGBA. +//! decoder.set_color_output(gif::ColorOutput::RGBA); +//! // Read the file header +//! let file = File::open("tests/samples/sample_1.gif").unwrap(); +//! let mut decoder = decoder.read_info(file).unwrap(); +//! while let Some(frame) = decoder.read_next_frame().unwrap() { +//!     // Process every frame +//! } +//! ``` +//!  +//!  +//!  +//! ### Encoding GIF files +//! +//! The encoder can be used so save simple computer generated images: +//!  +//! ```rust +//! use gif::{Frame, Encoder, Repeat}; +//! use std::fs::File; +//! use std::borrow::Cow; +//!  +//! let color_map = &[0xFF, 0xFF, 0xFF, 0, 0, 0]; +//! let (width, height) = (6, 6); +//! let mut beacon_states = [[ +//!     0, 0, 0, 0, 0, 0, +//!     0, 1, 1, 0, 0, 0, +//!     0, 1, 1, 0, 0, 0, +//!     0, 0, 0, 1, 1, 0, +//!     0, 0, 0, 1, 1, 0, +//!     0, 0, 0, 0, 0, 0, +//! ], [ +//!     0, 0, 0, 0, 0, 0, +//!     0, 1, 1, 0, 0, 0, +//!     0, 1, 0, 0, 0, 0, +//!     0, 0, 0, 0, 1, 0, +//!     0, 0, 0, 1, 1, 0, +//!     0, 0, 0, 0, 0, 0, +//! ]]; +//! let mut image = File::create("tests/samples/beacon.gif").unwrap();; +//! let mut encoder = Encoder::new(&mut image, width, height, color_map).unwrap(); +//! encoder.set_repeat(Repeat::Infinite).unwrap(); +//! for state in &beacon_states { +//!     let mut frame = Frame::default(); +//!     frame.width = width; +//!     frame.height = height; +//!     frame.buffer = Cow::Borrowed(&*state); +//!     encoder.write_frame(&frame).unwrap(); +//! } +//! ``` +//! +//! [`Frame::from_*`](struct.Frame.html) can be used to convert a true color image to a paletted +//! image with a maximum of 256 colors: +//! +//! ```rust +//! # #[cfg(feature = "color_quant")] { +//! use std::fs::File; +//!  +//! // Get pixel data from some source +//! let mut pixels: Vec<u8> = vec![0; 30_000]; +//! // Create frame from data +//! let frame = gif::Frame::from_rgb(100, 100, &mut *pixels); +//! // Create encoder +//! let mut image = File::create("target/indexed_color.gif").unwrap(); +//! let mut encoder = gif::Encoder::new(&mut image, frame.width, frame.height, &[]).unwrap(); +//! // Write frame to file +//! encoder.write_frame(&frame).unwrap(); +//! # } +//! ``` + +// TODO: make this compile +// ```rust +// use gif::{Frame, Encoder}; +// use std::fs::File; +// let color_map = &[0, 0, 0, 0xFF, 0xFF, 0xFF]; +// let mut frame = Frame::default(); +// // Generate checkerboard lattice +// for (i, j) in (0..10).zip(0..10) { +//     frame.buffer.push(if (i * j) % 2 == 0 { +//         1 +//     } else { +//         0 +//     }) +// } +// # (|| { +// { +// let mut file = File::create("test.gif")?; +// let mut encoder = Encoder::new(&mut file, 100, 100); +// encoder.write_global_palette(color_map)?.write_frame(&frame) +// } +// # })().unwrap(); +// ``` +#![deny(missing_docs)] +#![cfg(feature = "std")] + +mod traits; +mod common; +mod reader; +mod encoder; + +pub use crate::common::{AnyExtension, Block, Extension, DisposalMethod, Frame}; + +pub use crate::reader::{StreamingDecoder, Decoded, DecodingError, DecodingFormatError}; +/// StreamingDecoder configuration parameters +pub use crate::reader::{ColorOutput, MemoryLimit, Extensions}; +pub use crate::reader::{DecodeOptions, Decoder, Version}; + +pub use crate::encoder::{Encoder, ExtensionData, Repeat, EncodingError}; + +#[cfg(test)] +#[test] +fn round_trip() { +    use std::io::prelude::*; +    use std::fs::File; +    let mut data = vec![]; +    File::open("tests/samples/sample_1.gif").unwrap().read_to_end(&mut data).unwrap(); +    let mut decoder = Decoder::new(&*data).unwrap(); +    let palette: Vec<u8> = decoder.palette().unwrap().into(); +    let frame = decoder.read_next_frame().unwrap().unwrap(); +    let mut data2 = vec![]; +    { +        let mut encoder = Encoder::new(&mut data2, frame.width, frame.height, &palette).unwrap(); +        encoder.write_frame(frame).unwrap(); +    } +    assert_eq!(&data[..], &data2[..]) +} + +macro_rules! insert_as_doc { +    { $content:expr } => { +        #[doc = $content] extern { } +    } +} + +// Provides the README.md as doc, to ensure the example works! +#[cfg(feature = "color_quant")] +insert_as_doc!(include_str!("../README.md")); diff --git a/vendor/gif/src/reader/decoder.rs b/vendor/gif/src/reader/decoder.rs new file mode 100644 index 0000000..f0f8eea --- /dev/null +++ b/vendor/gif/src/reader/decoder.rs @@ -0,0 +1,724 @@ +use std::cmp; +use std::error; +use std::fmt; +use std::io; +use std::mem; +use std::default::Default; + +use crate::common::{AnyExtension, Block, DisposalMethod, Extension, Frame}; +use crate::reader::DecodeOptions; + +use weezl::{BitOrder, decode::Decoder as LzwDecoder, LzwStatus}; + +/// GIF palettes are RGB +pub const PLTE_CHANNELS: usize = 3; + +/// An error returned in the case of the image not being formatted properly. +#[derive(Debug)] +pub struct DecodingFormatError { +    underlying: Box<dyn error::Error + Send + Sync + 'static> +} + +impl fmt::Display for DecodingFormatError { +    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { +        fmt::Display::fmt(&*self.underlying, fmt) +    } +} + +impl error::Error for DecodingFormatError { +    fn source(&self) -> Option<&(dyn error::Error + 'static)> { +        Some(&*self.underlying as _) +    } +} + +impl DecodingFormatError { +    fn new( +        err: impl Into<Box<dyn error::Error + Send + Sync>>, +    ) -> Self { +        DecodingFormatError { +            underlying: err.into(), +        } +    } +} + +#[derive(Debug)] +/// Decoding error. +pub enum DecodingError { +    /// Returned if the image is found to be malformed. +    Format(DecodingFormatError), +    /// Wraps `std::io::Error`. +    Io(io::Error), +} + +impl DecodingError { +    #[inline] +    pub(crate) fn format( +        err: impl Into<Box<dyn error::Error + Send + Sync>>, +    ) -> Self { +        DecodingError::Format(DecodingFormatError::new(err)) +    } +} + +impl fmt::Display for DecodingError { +    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { +        match *self { +            DecodingError::Format(ref d) => d.fmt(fmt), +            DecodingError::Io(ref err) => err.fmt(fmt), +        } +    } +} + +impl error::Error for DecodingError { +    fn source(&self) -> Option<&(dyn error::Error + 'static)> { +        match *self { +            DecodingError::Format(ref err) => Some(err), +            DecodingError::Io(ref err) => Some(err), +        } +    } +} + +impl From<io::Error> for DecodingError { +    fn from(err: io::Error) -> Self { +        DecodingError::Io(err) +    } +} + +impl From<DecodingFormatError> for DecodingError { +    fn from(err: DecodingFormatError) -> Self { +        DecodingError::Format(err) +    } +} + +/// Configures how extensions should be handled +#[derive(PartialEq, Debug)] +pub enum Extensions { +    /// Saves all extention data +    Save, +    /// Skips the data of unknown extensions +    /// and extracts the data from known ones +    Skip +} + +/// Indicates whether a certain object has been decoded +#[derive(Debug)] +pub enum Decoded<'a> { +    /// Decoded nothing. +    Nothing, +    /// Global palette. +    GlobalPalette(Vec<u8>), +    /// Index of the background color in the global palette. +    BackgroundColor(u8), +    /// Decoded the image trailer. +    Trailer, +    /// The start of a block. +    BlockStart(Block), +    /// Decoded a sub-block. More sub-block are available. +    /// +    /// Indicates the label of the extension which might be unknown. A label of `0` is used when +    /// the sub block does not belong to an extension. +    SubBlockFinished(AnyExtension, &'a [u8]), +    /// Decoded the last (or only) sub-block of a block. +    /// +    /// Indicates the label of the extension which might be unknown. A label of `0` is used when +    /// the sub block does not belong to an extension. +    BlockFinished(AnyExtension, &'a [u8]), +    /// Decoded all information of the next frame. +    /// +    /// The returned frame does **not** contain any owned image data. +    Frame(&'a Frame<'static>), +    /// Decoded some data of the current frame. +    Data(&'a [u8]), +    /// No more data available the current frame. +    DataEnd, + +} + +/// Internal state of the GIF decoder +#[derive(Debug)] +enum State { +    Magic(usize, [u8; 6]), +    U16Byte1(U16Value, u8), +    U16(U16Value), +    Byte(ByteValue), +    GlobalPalette(usize), +    BlockStart(Option<Block>), +    /// Block end, with remaining expected data. NonZero for invalid EOF. +    BlockEnd(u8), +    ExtensionBlock(AnyExtension), +    SkipBlock(usize), +    LocalPalette(usize), +    LzwInit(u8), +    DecodeSubBlock(usize), +    FrameDecoded, +    Trailer +} +use self::State::*; + +/// U16 values that may occur in a GIF image +#[derive(Debug)] +enum U16Value { +    /// Logical screen descriptor width +    ScreenWidth, +    /// Logical screen descriptor height +    ScreenHeight, +    /// Delay time +    Delay, +    /// Left frame offset +    ImageLeft, +    /// Top frame offset +    ImageTop, +    /// Frame width +    ImageWidth, +    /// Frame height +    ImageHeight, +} + +/// Single byte screen descriptor values +#[derive(Debug)] +enum ByteValue { +    GlobalFlags, +    Background { table_size: usize }, +    AspectRatio { table_size: usize }, +    ControlFlags, +    ImageFlags, +    TransparentIdx, +    CodeSize, +} + +/// GIF decoder which supports streaming +pub struct StreamingDecoder { +    state: Option<State>, +    lzw_reader: Option<LzwDecoder>, +    decode_buffer: Vec<u8>, +    skip_extensions: bool, +    check_frame_consistency: bool, +    check_for_end_code: bool, +    allow_unknown_blocks: bool, +    version: Version, +    width: u16, +    height: u16, +    global_color_table: Vec<u8>, +    background_color: [u8; 4], +    /// ext buffer +    ext: ExtensionData, +    /// Frame data +    current: Option<Frame<'static>>, +} + +/// One version number of the GIF standard. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[non_exhaustive] +pub enum Version { +    /// Version 87a, from May 1987. +    V87a, +    /// Version 89a, from July 1989. +    V89a, +} + +struct ExtensionData { +    id: AnyExtension, +    data: Vec<u8>, +    is_block_end: bool, +} + +impl StreamingDecoder { +    /// Creates a new streaming decoder +    pub fn new() -> StreamingDecoder { +        let options = DecodeOptions::new(); +        Self::with_options(&options) +    } + +    pub(crate) fn with_options(options: &DecodeOptions) -> Self { +        StreamingDecoder { +            state: Some(Magic(0, [0; 6])), +            lzw_reader: None, +            decode_buffer: vec![], +            skip_extensions: true, +            check_frame_consistency: options.check_frame_consistency, +            check_for_end_code: options.check_for_end_code, +            allow_unknown_blocks: options.allow_unknown_blocks, +            version: Version::V87a, +            width: 0, +            height: 0, +            global_color_table: Vec::new(), +            background_color: [0, 0, 0, 0xFF], +            ext: ExtensionData { +                id: AnyExtension(0), +                data: Vec::with_capacity(256), // 0xFF + 1 byte length +                is_block_end: true, +            }, +            current: None +        } +    } +     +    /// Updates the internal state of the decoder.  +    /// +    /// Returns the number of bytes consumed from the input buffer  +    /// and the last decoding result. +    pub fn update<'a>(&'a mut self, mut buf: &[u8]) +    -> Result<(usize, Decoded<'a>), DecodingError> { +        // NOTE: Do not change the function signature without double-checking the +        //       unsafe block! +        let len = buf.len(); +        while buf.len() > 0 && self.state.is_some() { +            match self.next_state(buf) { +                Ok((bytes, Decoded::Nothing)) => { +                    buf = &buf[bytes..] +                } +                Ok((bytes, Decoded::Trailer)) => { +                    buf = &buf[bytes..]; +                    break +                } +                Ok((bytes, result)) => { +                    buf = &buf[bytes..]; +                    return Ok( +                        (len-buf.len(),  +                        // This transmute just casts the lifetime away. Since Rust only  +                        // has SESE regions, this early return cannot be worked out and +                        // such that the borrow region of self includes the whole block. +                        // The explixit lifetimes in the function signature ensure that +                        // this is safe. +                        // ### NOTE +                        // To check that everything is sound, return the result without +                        // the match (e.g. `return Ok(self.next_state(buf)?)`). If +                        // it compiles the returned lifetime is correct. +                        unsafe {  +                            mem::transmute::<Decoded, Decoded>(result) +                        } +                    )) +                } +                Err(err) => return Err(err) +            } +        } +        Ok((len-buf.len(), Decoded::Nothing)) +         +    } +     +    /// Returns the data of the last extension that has been decoded. +    pub fn last_ext(&self) -> (AnyExtension, &[u8], bool) { +        (self.ext.id, &self.ext.data, self.ext.is_block_end) +    } +     +    #[inline(always)] +    /// Current frame info as a mutable ref. +    pub fn current_frame_mut<'a>(&'a mut self) -> &'a mut Frame<'static> { +        self.current.as_mut().unwrap() +    } +     +    #[inline(always)] +    /// Current frame info as a ref. +    pub fn current_frame<'a>(&'a self) -> &'a Frame<'static> { +        self.current.as_ref().unwrap() +    } + +    /// Width of the image +    pub fn width(&self) -> u16 { +        self.width +    } + +    /// Height of the image +    pub fn height(&self) -> u16 { +        self.height +    } + +    /// The version number of the GIF standard used in this image. +    /// +    /// We suppose a minimum of `V87a` compatibility. This value will be reported until we have +    /// read the version information in the magic header bytes. +    pub fn version(&self) -> Version { +        self.version +    } + +    /// Configure whether extensions are saved or skipped. +    #[deprecated = "Does not work as intended. In fact, doesn't do anything. This may disappear soon."] +    pub fn set_extensions(&mut self, extensions: Extensions) { +        self.skip_extensions = match extensions { +            Extensions::Skip => true, +            Extensions::Save => false, +        } +    } + +    fn next_state<'a>(&'a mut self, buf: &[u8]) -> Result<(usize, Decoded<'a>), DecodingError> { +        macro_rules! goto ( +            ($n:expr, $state:expr) => ({ +                self.state = Some($state);  +                Ok(($n, Decoded::Nothing)) +            }); +            ($state:expr) => ({ +                self.state = Some($state);  +                Ok((1, Decoded::Nothing)) +            }); +            ($n:expr, $state:expr, emit $res:expr) => ({ +                self.state = Some($state);  +                Ok(($n, $res)) +            }); +            ($state:expr, emit $res:expr) => ({ +                self.state = Some($state);  +                Ok((1, $res)) +            }) +        ); +         +        let b = buf[0]; +         +        // Driver should ensure that state is never None +        let state = self.state.take().unwrap(); +        //println!("{:?}", state); +         +        match state { +            Magic(i, mut version) => if i < 6 { +                version[i] = b; +                goto!(Magic(i+1, version)) +            } else if &version[..3] == b"GIF" { +                self.version = match &version[3..] { +                    b"87a" => Version::V87a, +                    b"89a" => Version::V89a, +                    _ => return Err(DecodingError::format("unsupported GIF version")) +                }; +                goto!(U16Byte1(U16Value::ScreenWidth, b)) +            } else { +                Err(DecodingError::format("malformed GIF header")) +            }, +            U16(next) => goto!(U16Byte1(next, b)), +            U16Byte1(next, value) => { +                use self::U16Value::*; +                let value = ((b as u16) << 8) | value as u16; +                match (next, value) { +                    (ScreenWidth, width) => { +                        self.width = width; +                        goto!(U16(U16Value::ScreenHeight)) +                    }, +                    (ScreenHeight, height) => { +                        self.height = height; +                        goto!(Byte(ByteValue::GlobalFlags)) +                    }, +                    (Delay, delay) => { +                        self.ext.data.push(value as u8); +                        self.ext.data.push(b); +                        self.current_frame_mut().delay = delay; +                        goto!(Byte(ByteValue::TransparentIdx)) +                    }, +                    (ImageLeft, left) => { +                        self.current_frame_mut().left = left; +                        goto!(U16(U16Value::ImageTop)) +                    }, +                    (ImageTop, top) => { +                        self.current_frame_mut().top = top; +                        goto!(U16(U16Value::ImageWidth)) +                    }, +                    (ImageWidth, width) => { +                        self.current_frame_mut().width = width; +                        goto!(U16(U16Value::ImageHeight)) +                    }, +                    (ImageHeight, height) => { +                        self.current_frame_mut().height = height; +                        goto!(Byte(ByteValue::ImageFlags)) +                    } +                } +            } +            Byte(value) => { +                use self::ByteValue::*; +                match value { +                    GlobalFlags => { +                        let global_table = b & 0x80 != 0; +                        let entries = if global_table { +                            let entries = PLTE_CHANNELS*(1 << ((b & 0b111) + 1) as usize); +                            self.global_color_table.reserve_exact(entries); +                            entries +                        } else { +                            0usize +                        }; +                        goto!(Byte(Background { table_size: entries })) +                    }, +                    Background { table_size } => { +                        goto!( +                            Byte(AspectRatio { table_size: table_size }), +                            emit Decoded::BackgroundColor(b) +                        ) +                    }, +                    AspectRatio { table_size } => { +                        goto!(GlobalPalette(table_size)) +                    }, +                    ControlFlags => { +                        self.ext.data.push(b); +                        let control_flags = b; +                        if control_flags & 1 != 0 { +                            // Set to Some(...), gets overwritten later +                            self.current_frame_mut().transparent = Some(0) +                        } +                        self.current_frame_mut().needs_user_input = +                            control_flags & 0b10 != 0; +                        self.current_frame_mut().dispose = match DisposalMethod::from_u8( +                            (control_flags & 0b11100) >> 2 +                        ) { +                            Some(method) => method, +                            None => DisposalMethod::Any +                        }; +                        goto!(U16(U16Value::Delay)) +                    } +                    TransparentIdx => { +                        self.ext.data.push(b); +                        if let Some(ref mut idx) = self.current_frame_mut().transparent { +                             *idx = b +                        } +                        goto!(SkipBlock(0)) +                        //goto!(AwaitBlockEnd) +                    } +                    ImageFlags => { +                        let local_table = (b & 0b1000_0000) != 0; +                        let interlaced   = (b & 0b0100_0000) != 0; +                        let table_size  =  b & 0b0000_0111; + +                        self.current_frame_mut().interlaced = interlaced; + +                        if self.check_frame_consistency { +                            // Consistency checks. +                            let (width, height) = (self.width, self.height); +                            let frame = self.current_frame_mut(); +                            if width.checked_sub(frame.width) < Some(frame.left) +                                || height.checked_sub(frame.height) < Some(frame.top) +                            { +                                return Err(DecodingError::format("frame descriptor is out-of-bounds")) +                            } +                        } + +                        if local_table { +                            let entries = PLTE_CHANNELS * (1 << (table_size + 1)); +                             +                            self.current_frame_mut().palette = +                                Some(Vec::with_capacity(entries)); +                            goto!(LocalPalette(entries)) +                        } else { +                            goto!(Byte(CodeSize)) +                        } +                    }, +                    CodeSize => goto!(LzwInit(b)) +                } +            } +            GlobalPalette(left) => { +                let n = cmp::min(left, buf.len()); +                if left > 0 { +                    self.global_color_table.extend_from_slice(&buf[..n]); +                    goto!(n, GlobalPalette(left - n)) +                } else { +                    let idx = self.background_color[0]; +                    match self.global_color_table.chunks(PLTE_CHANNELS).nth(idx as usize) { +                        Some(chunk) => self.background_color[..PLTE_CHANNELS] +                            .copy_from_slice(&chunk[..PLTE_CHANNELS]), +                        None => self.background_color[0] = 0 +                    } +                    goto!(BlockStart(Block::from_u8(b)), emit Decoded::GlobalPalette( +                        mem::replace(&mut self.global_color_table, Vec::new()) +                    )) +                } +            } +            BlockStart(type_) => { +                match type_ { +                    Some(Block::Image) => { +                        self.add_frame(); +                        goto!(U16Byte1(U16Value::ImageLeft, b), emit Decoded::BlockStart(Block::Image)) +                    } +                    Some(Block::Extension) => { +                        goto!(ExtensionBlock(AnyExtension(b)), emit Decoded::BlockStart(Block::Extension)) +                    } +                    Some(Block::Trailer) => { +                        goto!(0, State::Trailer, emit Decoded::BlockStart(Block::Trailer)) +                    } +                    None => { +                        if self.allow_unknown_blocks { +                            goto!(SkipBlock(b as usize)) +                        } else { +                            Err(DecodingError::format("unknown block type encountered")) +                        } +                    } +                } +            } +            BlockEnd(terminator) => { +                if terminator == 0 { +                    if b == Block::Trailer as u8 { +                        goto!(0, BlockStart(Some(Block::Trailer))) +                    } else { +                        goto!(BlockStart(Block::from_u8(b))) +                    } +                } else { +                    return Err(DecodingError::format( +                        "expected block terminator not found" +                    )) +                } +            } +            ExtensionBlock(id) => { +                use Extension::*; +                self.ext.id = id; +                self.ext.data.clear(); +                self.ext.data.push(b); +                if let Some(ext) = Extension::from_u8(id.0) { +                    match ext { +                        Control => { +                            goto!(self.read_control_extension(b)?) +                        } +                        Text | Comment | Application => { +                            goto!(SkipBlock(b as usize)) +                        } +                    } +                } else { +                    return Err(DecodingError::format( +                        "unknown extention block encountered" +                    )) +                } +            } +            SkipBlock(left) => { +                let n = cmp::min(left, buf.len()); +                if left > 0 { +                    self.ext.data.extend_from_slice(&buf[..n]); +                    goto!(n, SkipBlock(left - n)) +                } else { +                    if b == 0 { +                        self.ext.is_block_end = true; +                        goto!(BlockEnd(b), emit Decoded::BlockFinished(self.ext.id, &self.ext.data)) +                    } else { +                        self.ext.is_block_end = false; +                        goto!(SkipBlock(b as usize), emit Decoded::SubBlockFinished(self.ext.id, &self.ext.data)) +                    } +                } +            } +            LocalPalette(left) => { +                let n = cmp::min(left, buf.len()); +                if left > 0 { +                     +                    self.current_frame_mut().palette +                        .as_mut().unwrap().extend(buf[..n].iter().cloned()); +                    goto!(n, LocalPalette(left - n)) +                } else { +                    goto!(LzwInit(b)) +                } +            } +            LzwInit(code_size) => { +                // LZW spec: max 12 bits per code +                if code_size > 11 { +                    return Err(DecodingError::format( +                        "invalid minimal code size" +                    )) +                } +                self.lzw_reader = Some(LzwDecoder::new(BitOrder::Lsb, code_size)); +                goto!(DecodeSubBlock(b as usize), emit Decoded::Frame(self.current_frame_mut())) +            } +            DecodeSubBlock(left) => { +                if left > 0 { +                    let n = cmp::min(left, buf.len()); +                    let max_bytes = self.current_frame().required_bytes(); +                    let decoder = self.lzw_reader.as_mut().unwrap(); +                    if decoder.has_ended() { +                        debug_assert!(n > 0, "Made forward progress after LZW end"); +                        return goto!(n, DecodeSubBlock(0), emit Decoded::Data(&[])); +                    } + +                    let mut dummy_target; +                    let decode_target; + +                    if self.decode_buffer.is_empty() { +                        let size = (1 << 14).min(max_bytes); +                        self.decode_buffer = vec![0; size]; +                    } + +                    if max_bytes == 0 { +                        dummy_target = [0; 16]; +                        decode_target = &mut dummy_target[..]; +                    } else { +                        decode_target = self.decode_buffer.as_mut_slice(); +                    } + +                    debug_assert!(!decode_target.is_empty(), "LZW decoding can make forward progress."); +                    let decoded = decoder.decode_bytes(&buf[..n], decode_target); + +                    if let Err(err) = decoded.status { +                        return Err(io::Error::new(io::ErrorKind::InvalidData, &*format!("{:?}", err)).into()); +                    } + +                    let bytes = &self.decode_buffer[..decoded.consumed_out.min(max_bytes)]; +                    let consumed = decoded.consumed_in; +                    goto!(consumed, DecodeSubBlock(left - consumed), emit Decoded::Data(bytes)) +                }  else if b != 0 { // decode next sub-block +                    goto!(DecodeSubBlock(b as usize)) +                } else { +                    let max_bytes = self.current_frame().required_bytes(); +                    // The end of the lzw stream is only reached if left == 0 and an additional call +                    // to `decode_bytes` results in an empty slice. +                    let decoder = self.lzw_reader.as_mut().unwrap(); +                    // Some mutable bytes to decode into. We need this for forward progress in +                    // `lzw`. However, in some cases we do not actually need any bytes, when +                    // `max_bytes` is `0`. +                    let mut dummy_target; +                    let decode_target; + +                    if self.decode_buffer.is_empty() { +                        let size = (1 << 14).min(max_bytes); +                        self.decode_buffer = vec![0; size]; +                    } + +                    if max_bytes == 0 { +                        dummy_target = [0; 16]; +                        decode_target = &mut dummy_target[..]; +                    } else { +                        decode_target = self.decode_buffer.as_mut_slice(); +                    } + +                    debug_assert!(!decode_target.is_empty(), "LZW decoding can make forward progress."); +                    let decoded = decoder.decode_bytes(&[], decode_target); + +                    match decoded.status { +                        Ok(LzwStatus::Done) | Ok(LzwStatus::Ok) => {}, +                        Ok(LzwStatus::NoProgress) => { +                            if self.check_for_end_code { +                                return Err(io::Error::new(io::ErrorKind::InvalidData, "No end code in lzw stream").into()); +                            } else { +                                self.current = None; +                                return goto!(0, FrameDecoded, emit Decoded::DataEnd); +                            } +                        }, +                        Err(err) => { +                            return Err(io::Error::new(io::ErrorKind::InvalidData, &*format!("{:?}", err)).into()); +                        } +                    } +                    let bytes = &self.decode_buffer[..decoded.consumed_out.min(max_bytes)]; + +                    if bytes.len() > 0 { +                        goto!(0, DecodeSubBlock(0), emit Decoded::Data(bytes)) +                    } else { +                        // end of image data reached +                        self.current = None; +                        goto!(0, FrameDecoded, emit Decoded::DataEnd) +                    } +                } +            } +            FrameDecoded => { +                goto!(BlockEnd(b)) +            } +            Trailer => { +                self.state = None; +                Ok((1, Decoded::Trailer)) +                //panic!("EOF {:?}", self) +            } +        } +    } +     +    fn read_control_extension(&mut self, b: u8) -> Result<State, DecodingError> { +        self.add_frame(); +        self.ext.data.push(b); +        if b != 4 { +            return Err(DecodingError::format( +                "control extension has wrong length" +            )) +        } +        Ok(Byte(ByteValue::ControlFlags)) +    } +     +    fn add_frame(&mut self) { +        if self.current.is_none() { +            self.current = Some(Frame::default()) +        } +    } +} + +#[test] +fn error_cast() { +    let _ : Box<dyn error::Error> = DecodingError::Format(DecodingFormatError::new("testing")).into(); +} diff --git a/vendor/gif/src/reader/mod.rs b/vendor/gif/src/reader/mod.rs new file mode 100644 index 0000000..a453e79 --- /dev/null +++ b/vendor/gif/src/reader/mod.rs @@ -0,0 +1,522 @@ +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<usize> { +        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<R: Read>(self, r: R) -> Result<Decoder<R>, DecodingError> { +        Decoder::with_no_init(r, StreamingDecoder::with_options(&self), self).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(Block::Trailer) => { +                    self.at_eof = true +                }, +                result => return Ok(unsafe{ +                    // FIXME: #6393 +                    Some(mem::transmute::<Decoded, Decoded>(result)) +                }), +            } +        } +        Ok(None) +    } +} + +#[allow(dead_code)] +/// GIF decoder +pub struct Decoder<R: Read> { +    decoder: ReadDecoder<R>, +    color_output: ColorOutput, +    memory_limit: MemoryLimit, +    bg_color: Option<u8>, +    global_palette: Option<Vec<u8>>, +    current_frame: Frame<'static>, +    buffer: Vec<u8>, +} + +impl<R> Decoder<R> where R: Read { +    /// Create a new decoder with default options. +    pub fn new(reader: R) -> Result<Self, DecodingError> { +        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<R> { +        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<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 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<Option<&Frame<'static>>, 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<Option<&Frame<'static>>, 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<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()); +                        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<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()).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); +        } +    } +} diff --git a/vendor/gif/src/traits.rs b/vendor/gif/src/traits.rs new file mode 100644 index 0000000..7fe326c --- /dev/null +++ b/vendor/gif/src/traits.rs @@ -0,0 +1,49 @@ +//! Traits used in this library +use std::io; + +/// Writer extension to write little endian data +pub trait WriteBytesExt<T> { +    /// Writes `T` to a bytes stream. Least significant byte first. +    fn write_le(&mut self, n: T) -> io::Result<()>; + +    /* +    #[inline] +    fn write_byte(&mut self, n: u8) -> io::Result<()> where Self: Write { +        self.write_all(&[n]) +    } +    */ +} + +impl<W: io::Write + ?Sized> WriteBytesExt<u8> for W { +    #[inline] +    fn write_le(&mut self, n: u8) -> io::Result<()> { +        self.write_all(&[n]) +         +    } +} + +impl<W: io::Write + ?Sized> WriteBytesExt<u16> for W { +    #[inline] +    fn write_le(&mut self, n: u16) -> io::Result<()> { +        self.write_all(&[n as u8, (n>>8) as u8]) +         +    } +} + +impl<W: io::Write + ?Sized> WriteBytesExt<u32> for W { +    #[inline] +    fn write_le(&mut self, n: u32) -> io::Result<()> { +        self.write_le(n as u16)?; +        self.write_le((n >> 16) as u16) +         +    } +} + +impl<W: io::Write + ?Sized> WriteBytesExt<u64> for W { +    #[inline] +    fn write_le(&mut self, n: u64) -> io::Result<()> { +        self.write_le(n as u32)?; +        self.write_le((n >> 32) as u32) +         +    } +} | 
