gift/
private.rs

1// private.rs
2//
3// Copyright (c) 2019-2023  Douglas Lau
4//
5//! Private module for top-level items
6use crate::{
7    block::{DisposalMethod, GraphicControl},
8    decode, encode, Result,
9};
10use pix::{gray::Gray8, rgb::SRgba8, Palette, Raster};
11use std::io::{Read, Write};
12
13/// Raster for an animation step.
14pub(crate) enum StepRaster {
15    /// True color 24-bit raster
16    TrueColor(Raster<SRgba8>),
17    /// Indexed color 8-bit raster
18    Indexed(Raster<Gray8>, Palette),
19}
20
21/// One step of an animation.
22#[derive(Clone)]
23pub struct Step {
24    /// Raster of the animation step
25    pub(crate) raster: StepRaster,
26    /// Graphic control for the step
27    pub(crate) graphic_control_ext: Option<GraphicControl>,
28}
29
30/// GIF file decoder
31///
32/// Can be converted to one of three `Iterator`s:
33/// * [into_iter] / [into_steps] for high-level [Step]s
34/// * [into_frames] for mid-level [Frame]s
35/// * [into_blocks] for low-level [Block]s
36///
37/// ## Example: Get a `Raster` from a GIF
38/// ```
39/// use gift::Decoder;
40///
41/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
42/// # let gif = &[
43/// #   0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x02, 0x00,
44/// #   0x02, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00,
45/// #   0xff, 0xff, 0xff, 0x2c, 0x00, 0x00, 0x00, 0x00,
46/// #   0x02, 0x00, 0x02, 0x00, 0x00, 0x02, 0x03, 0x0c,
47/// #   0x10, 0x05, 0x00, 0x3b,
48/// # ][..];
49/// // ... open a `File` as "gif"
50/// if let Some(step) = Decoder::new(gif).into_steps().next() {
51///     // was there a decoding error?
52///     let step = step?;
53///     let raster = step.raster();
54///     // ... work with raster
55/// }
56/// # Ok(())
57/// # }
58/// ```
59///
60/// [Block]: block/enum.Block.html
61/// [Frame]: block/struct.Frame.html
62/// [into_blocks]: struct.Decoder.html#method.into_blocks
63/// [into_frames]: struct.Decoder.html#method.into_frames
64/// [into_iter]: struct.Decoder.html#method.into_iter
65/// [into_steps]: struct.Decoder.html#method.into_steps
66/// [Step]: struct.Step.html
67///
68pub struct Decoder<R: Read> {
69    /// Reader for input data
70    reader: R,
71    /// Maximum image size, in bytes
72    max_image_sz: Option<usize>,
73}
74
75impl Clone for StepRaster {
76    fn clone(&self) -> Self {
77        match self {
78            StepRaster::TrueColor(r) => {
79                StepRaster::TrueColor(Raster::with_raster(r))
80            }
81            StepRaster::Indexed(r, p) => {
82                StepRaster::Indexed(Raster::with_raster(r), p.clone())
83            }
84        }
85    }
86}
87
88impl Step {
89    /// Create an animation step with a true color raster.
90    pub fn with_true_color(raster: Raster<SRgba8>) -> Self {
91        let raster = StepRaster::TrueColor(raster);
92        Step {
93            raster,
94            graphic_control_ext: None,
95        }
96    }
97
98    /// Create an animation step with an indexed raster.
99    pub fn with_indexed(raster: Raster<Gray8>, palette: Palette) -> Self {
100        let raster = StepRaster::Indexed(raster, palette);
101        Step {
102            raster,
103            graphic_control_ext: None,
104        }
105    }
106
107    /// Adjust the disposal method.
108    pub fn with_disposal_method(mut self, method: DisposalMethod) -> Self {
109        let mut control = self.graphic_control_ext.unwrap_or_default();
110        control.set_disposal_method(method);
111        if control != GraphicControl::default() {
112            self.graphic_control_ext = Some(control);
113        } else {
114            self.graphic_control_ext = None;
115        }
116        self
117    }
118
119    /// Adjust the transparent color.
120    pub fn with_transparent_color(mut self, clr: Option<u8>) -> Self {
121        let mut control = self.graphic_control_ext.unwrap_or_default();
122        control.set_transparent_color(clr);
123        if control != GraphicControl::default() {
124            self.graphic_control_ext = Some(control);
125        } else {
126            self.graphic_control_ext = None;
127        }
128        self
129    }
130
131    /// Get the transparent color
132    pub fn transparent_color(&self) -> Option<u8> {
133        self.graphic_control_ext.and_then(|c| c.transparent_color())
134    }
135
136    /// Adjust the delay time.
137    pub fn with_delay_time_cs(mut self, delay: Option<u16>) -> Self {
138        let mut control = self.graphic_control_ext.unwrap_or_default();
139        control.set_delay_time_cs(delay.unwrap_or_default());
140        if control != GraphicControl::default() {
141            self.graphic_control_ext = Some(control);
142        } else {
143            self.graphic_control_ext = None;
144        }
145        self
146    }
147
148    /// Get the raster
149    pub fn raster(&self) -> &Raster<SRgba8> {
150        match &self.raster {
151            StepRaster::TrueColor(ref r) => r,
152            StepRaster::Indexed(_, _) => todo!("convert to true color"),
153        }
154    }
155
156    /// Get the delay time in centiseconds
157    pub fn delay_time_cs(&self) -> Option<u16> {
158        self.graphic_control_ext.map(|c| c.delay_time_cs())
159    }
160}
161
162impl<R: Read> Decoder<R> {
163    /// Create a new GIF decoder.
164    pub fn new(reader: R) -> Self {
165        Decoder {
166            reader,
167            max_image_sz: Some(1 << 25),
168        }
169    }
170
171    /// Set the maximum image size (in bytes) to allow for decoding.
172    pub fn max_image_sz(mut self, max_image_sz: Option<usize>) -> Self {
173        self.max_image_sz = max_image_sz;
174        self
175    }
176
177    /// Convert into a block `Iterator`.
178    pub fn into_blocks(self) -> decode::Blocks<R> {
179        decode::Blocks::new(self.reader, self.max_image_sz)
180    }
181
182    /// Convert into a frame `Iterator`.
183    pub fn into_frames(self) -> decode::Frames<R> {
184        decode::Frames::new(self.into_blocks())
185    }
186
187    /// Convert into a step `Iterator` without looping.
188    pub fn into_steps(self) -> decode::Steps<R> {
189        decode::Steps::new_once(self.into_frames())
190    }
191}
192
193impl<R: Read> IntoIterator for Decoder<R> {
194    type Item = Result<Step>;
195    type IntoIter = decode::Steps<R>;
196
197    /// Convert into a step `Iterator` with looping
198    fn into_iter(self) -> Self::IntoIter {
199        decode::Steps::new_looping(self.into_frames())
200    }
201}
202
203/// GIF file encoder
204///
205/// Can be converted to one of three encoders:
206/// * [into_step_enc] for high-level [Step]s
207/// * [into_frame_enc] for mid-level [Frame]s
208/// * [into_block_enc] for low-level [Block]s
209///
210/// ## Encoding Example
211/// ```
212/// use gift::{Encoder, Step};
213/// use pix::{gray::Gray8, Palette, Raster, rgb::SRgb8};
214/// use std::error::Error;
215/// use std::io::Write;
216///
217/// fn encode<W: Write>(mut w: W) -> Result<(), Box<dyn Error>> {
218///     let mut enc = Encoder::new(&mut w).into_step_enc();
219///     let mut raster = Raster::with_clear(4, 4);
220///     *raster.pixel_mut(0, 0) = Gray8::new(1);
221///     *raster.pixel_mut(1, 1) = Gray8::new(1);
222///     *raster.pixel_mut(2, 2) = Gray8::new(1);
223///     *raster.pixel_mut(3, 3) = Gray8::new(1);
224///     let mut palette = Palette::new(2);
225///     palette.set_entry(SRgb8::new(0xFF, 0, 0));
226///     palette.set_entry(SRgb8::new(0xFF, 0xFF, 0));
227///     let step = Step::with_indexed(raster, palette);
228///     enc.encode_step(&step)?;
229///     Ok(())
230/// }
231/// ```
232///
233/// [Block]: block/enum.Block.html
234/// [Frame]: block/struct.Frame.html
235/// [into_block_enc]: struct.Encoder.html#method.into_block_enc
236/// [into_frame_enc]: struct.Encoder.html#method.into_frame_enc
237/// [into_step_enc]: struct.Encoder.html#method.into_step_enc
238/// [Step]: struct.Step.html
239pub struct Encoder<W: Write> {
240    /// Writer for output data
241    writer: W,
242}
243
244impl<W: Write> Encoder<W> {
245    /// Create a new GIF encoder.
246    pub fn new(writer: W) -> Self {
247        Encoder { writer }
248    }
249
250    /// Convert into a block encoder.
251    pub fn into_block_enc(self) -> encode::BlockEnc<W> {
252        encode::BlockEnc::new(self.writer)
253    }
254
255    /// Convert into a frame encoder.
256    pub fn into_frame_enc(self) -> encode::FrameEnc<W> {
257        encode::FrameEnc::new(self.into_block_enc())
258    }
259
260    /// Convert into a step encoder.
261    pub fn into_step_enc(self) -> encode::StepEnc<W> {
262        encode::StepEnc::new(self.into_frame_enc())
263    }
264}