1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// private.rs
//
// Copyright (c) 2019-2020  Douglas Lau
//
//! Private module for top-level items
use crate::{decode, encode, Error};
use pix::{Raster, Rgba8};
use std::io::{BufReader, BufWriter, Read, Write};

/// GIF file decoder
///
/// Can be converted to one of three `Iterator`s:
/// * [into_iter] / [into_rasters] for high-level `Raster`s
/// * [into_frames] for mid-level [Frame]s
/// * [into_blocks] for low-level [Block]s
///
/// ## Example: Get a `Raster` from a GIF
/// ```
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// # let gif = &[
/// #   0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x02, 0x00,
/// #   0x02, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00,
/// #   0xff, 0xff, 0xff, 0x2c, 0x00, 0x00, 0x00, 0x00,
/// #   0x02, 0x00, 0x02, 0x00, 0x00, 0x02, 0x03, 0x0c,
/// #   0x10, 0x05, 0x00, 0x3b,
/// # ][..];
/// // ... open a `File` as "gif"
/// if let Some(raster) = gift::Decoder::new(gif).into_iter().next() {
///     // was there a decoding error?
///     let raster = raster?;
///     // ... work with raster
/// }
/// # Ok(())
/// # }
/// ```
///
/// [Block]: block/enum.Block.html
/// [Frame]: block/struct.Frame.html
/// [into_blocks]: struct.Decoder.html#method.into_blocks
/// [into_frames]: struct.Decoder.html#method.into_frames
/// [into_iter]: struct.Decoder.html#method.into_iter
/// [into_rasters]: struct.Decoder.html#method.into_rasters
///
pub struct Decoder<R: Read> {
    /// Reader for input data
    reader: R,
    /// Maximum image size, in bytes
    max_image_sz: Option<usize>,
}

impl<R: Read> Decoder<BufReader<R>> {
    /// Create a new GIF decoder.
    pub fn new(reader: R) -> Self {
        Self::new_unbuffered(BufReader::new(reader))
    }
}
impl<R: Read> Decoder<R> {
    /// Create a new unbuffered GIF decoder.
    pub fn new_unbuffered(reader: R) -> Self {
        Decoder {
            reader,
            max_image_sz: Some(1 << 25),
        }
    }
    /// Set the maximum image size (in bytes) to allow for decoding.
    pub fn max_image_sz(mut self, max_image_sz: Option<usize>) -> Self {
        self.max_image_sz = max_image_sz;
        self
    }
    /// Convert into a block `Iterator`.
    pub fn into_blocks(self) -> decode::Blocks<R> {
        decode::Blocks::new(self.reader, self.max_image_sz)
    }
    /// Convert into a frame `Iterator`.
    pub fn into_frames(self) -> decode::Frames<R> {
        decode::Frames::new(self.into_blocks())
    }
    /// Convert into a raster `Iterator`.
    pub fn into_rasters(self) -> decode::Rasters<R> {
        decode::Rasters::new(self.into_frames())
    }
}

impl<R: Read> IntoIterator for Decoder<R> {
    type Item = Result<Raster<Rgba8>, Error>;
    type IntoIter = decode::Rasters<R>;

    /// Convert into a raster `Iterator`
    fn into_iter(self) -> Self::IntoIter {
        self.into_rasters()
    }
}

/// GIF file encoder
///
/// Can be converted to one of three encoders:
/// * [into_raster_enc] for high-level `Raster`s
/// * [into_frame_enc] for mid-level [Frame]s
/// * [into_block_enc] for low-level [Block]s
///
/// [Block]: block/enum.Block.html
/// [Frame]: block/struct.Frame.html
/// [into_block_enc]: struct.Encoder.html#method.into_block_enc
/// [into_frame_enc]: struct.Encoder.html#method.into_frame_enc
/// [into_raster_enc]: struct.Encoder.html#method.into_raster_enc
pub struct Encoder<W: Write> {
    /// Writer for output data
    writer: W,
}
impl<W: Write> Encoder<BufWriter<W>> {
    /// Create a new GIF encoder.
    pub fn new(writer: W) -> Self {
        Self::new_unbuffered(BufWriter::new(writer))
    }
}
impl<W: Write> Encoder<W> {
    /// Create a new unbuffered GIF encoder.
    pub fn new_unbuffered(writer: W) -> Self {
        Encoder {
            writer,
        }
    }
    /// Convert into a block encoder.
    pub fn into_block_enc(self) -> encode::BlockEnc<W> {
        encode::BlockEnc::new(self.writer)
    }
    /// Convert into a frame encoder.
    pub fn into_frame_enc(self) -> encode::FrameEnc<W> {
        encode::FrameEnc::new(self.into_block_enc())
    }
    /// Convert into a raster encoder.
    pub fn into_raster_enc(self) -> encode::RasterEnc<W> {
        encode::RasterEnc::new(self.into_frame_enc())
    }
}