1 //! # Minimal gif encoder
2 use std::io;
3 use std::io::prelude::*;
4 use std::fmt;
5 use std::error;
6 
7 use weezl::{BitOrder, encode::Encoder as LzwEncoder};
8 
9 use crate::traits::{WriteBytesExt};
10 use crate::common::{AnyExtension, Block, DisposalMethod, Extension, Frame};
11 
12 #[derive(Debug)]
13 enum FormatErrorKind {
14     /// The image has too many colors.
15     TooManyColors,
16     /// The image has no color palette which is required.
17     MissingColorPalette,
18 }
19 
20 /// The image has incorrect properties, making it impossible to encode as a gif.
21 #[derive(Debug)]
22 pub struct EncodingFormatError {
23     kind: FormatErrorKind
24 }
25 
26 impl error::Error for EncodingFormatError {}
27 impl fmt::Display for EncodingFormatError {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result28     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
29         match self.kind {
30             FormatErrorKind::TooManyColors => write!(fmt, "the image has too many colors"),
31             FormatErrorKind::MissingColorPalette => write!(fmt, "the GIF format requires a color palette but none was given")
32         }
33     }
34 }
35 
36 impl From<FormatErrorKind> for EncodingFormatError {
from(kind: FormatErrorKind) -> Self37     fn from(kind: FormatErrorKind) -> Self {
38         EncodingFormatError { kind }
39     }
40 }
41 
42 #[derive(Debug)]
43 /// Encoding error.
44 pub enum EncodingError {
45     /// Returned if the to image is not encodable as a gif.
46     Format(EncodingFormatError),
47     /// Wraps `std::io::Error`.
48     Io(io::Error),
49 }
50 
51 impl fmt::Display for EncodingError {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result52     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
53         match self {
54             EncodingError::Io(err) => err.fmt(fmt),
55             EncodingError::Format(err) => err.fmt(fmt),
56         }
57     }
58 }
59 
60 impl error::Error for EncodingError {
source(&self) -> Option<&(dyn error::Error + 'static)>61     fn source(&self) -> Option<&(dyn error::Error + 'static)> {
62         match self {
63             EncodingError::Io(err) => Some(err),
64             EncodingError::Format(err) => Some(err),
65         }
66     }
67 }
68 
69 impl From<io::Error> for EncodingError {
from(err: io::Error) -> Self70     fn from(err: io::Error) -> Self {
71         EncodingError::Io(err)
72     }
73 }
74 
75 impl From<EncodingFormatError> for EncodingError {
from(err: EncodingFormatError) -> Self76     fn from(err: EncodingFormatError) -> Self {
77         EncodingError::Format(err)
78     }
79 }
80 
81 impl From<FormatErrorKind> for EncodingError {
from(kind: FormatErrorKind) -> Self82     fn from(kind: FormatErrorKind) -> Self {
83         EncodingError::Format(kind.into())
84     }
85 }
86 
87 
88 /// Number of repetitions
89 #[derive(Copy, Clone, Debug)]
90 pub enum Repeat {
91     /// Finite number of repetitions
92     Finite(u16),
93     /// Infinite number of repetitions
94     Infinite
95 }
96 
97 /// Extension data.
98 pub enum ExtensionData {
99     /// Control extension. Use `ExtensionData::new_control_ext` to construct.
100     Control {
101         /// Flags.
102         flags: u8,
103         /// Frame delay.
104         delay: u16,
105         /// Transparent index.
106         trns: u8
107     },
108     /// Sets the number of repetitions
109     Repetitions(Repeat)
110 }
111 
112 impl ExtensionData {
113     /// Constructor for control extension data.
114     ///
115     /// `delay` is given in units of 10 ms.
new_control_ext(delay: u16, dispose: DisposalMethod, needs_user_input: bool, trns: Option<u8>) -> ExtensionData116     pub fn new_control_ext(delay: u16, dispose: DisposalMethod,
117                            needs_user_input: bool, trns: Option<u8>) -> ExtensionData {
118         let mut flags = 0;
119         let trns = match trns {
120             Some(trns) => {
121                 flags |= 1;
122                 trns as u8
123             },
124             None => 0
125         };
126         flags |= (needs_user_input as u8) << 1;
127         flags |= (dispose as u8) << 2;
128         ExtensionData::Control {
129             flags: flags,
130             delay: delay,
131             trns: trns
132         }
133     }
134 }
135 
136 /// GIF encoder.
137 pub struct Encoder<W: Write> {
138     w: W,
139     global_palette: bool,
140     width: u16,
141     height: u16,
142     buffer: Vec<u8>
143 }
144 
145 impl<W: Write> Encoder<W> {
146     /// Creates a new encoder.
147     ///
148     /// `global_palette` gives the global color palette in the format `[r, g, b, ...]`,
149     /// if no global palette shall be used an empty slice may be supplied.
new(w: W, width: u16, height: u16, global_palette: &[u8]) -> Result<Self, EncodingError>150     pub fn new(w: W, width: u16, height: u16, global_palette: &[u8]) -> Result<Self, EncodingError> {
151         let buffer_size = (width as usize) * (height as usize);
152         Encoder {
153             w: w,
154             global_palette: false,
155             width: width,
156             height: height,
157             buffer: Vec::with_capacity(buffer_size)
158         }.write_global_palette(global_palette)
159     }
160 
161     /// Write an extension block that signals a repeat behaviour.
set_repeat(&mut self, repeat: Repeat) -> Result<(), EncodingError>162     pub fn set_repeat(&mut self, repeat: Repeat) -> Result<(), EncodingError> {
163         self.write_extension(ExtensionData::Repetitions(repeat))
164     }
165 
166     /// Writes the global color palette.
write_global_palette(mut self, palette: &[u8]) -> Result<Self, EncodingError>167     pub fn write_global_palette(mut self, palette: &[u8]) -> Result<Self, EncodingError> {
168         self.global_palette = true;
169         let mut flags = 0;
170         flags |= 0b1000_0000;
171         let num_colors = palette.len() / 3;
172         if num_colors > 256 {
173             return Err(EncodingError::from(FormatErrorKind::TooManyColors));
174         }
175         // Size of global color table.
176         flags |= flag_size(num_colors);
177         // Color resolution .. FIXME. This is mostly ignored (by ImageMagick at least) but hey, we
178         // should use some sensible value here or even allow configuring it?
179         flags |= flag_size(num_colors) << 4; // wtf flag
180         self.write_screen_desc(flags)?;
181         self.write_color_table(palette)?;
182         Ok(self)
183     }
184 
185     /// Writes a frame to the image.
186     ///
187     /// Note: This function also writes a control extension if necessary.
write_frame(&mut self, frame: &Frame) -> Result<(), EncodingError>188     pub fn write_frame(&mut self, frame: &Frame) -> Result<(), EncodingError> {
189         // TODO commented off to pass test in lib.rs
190         //if frame.delay > 0 || frame.transparent.is_some() {
191             self.write_extension(ExtensionData::new_control_ext(
192                 frame.delay,
193                 frame.dispose,
194                 frame.needs_user_input,
195                 frame.transparent
196 
197             ))?;
198         //}
199         self.w.write_le(Block::Image as u8)?;
200         self.w.write_le(frame.left)?;
201         self.w.write_le(frame.top)?;
202         self.w.write_le(frame.width)?;
203         self.w.write_le(frame.height)?;
204         let mut flags = 0;
205         if frame.interlaced {
206             flags |= 0b0100_0000;
207         }
208         match frame.palette {
209             Some(ref palette) => {
210                 flags |= 0b1000_0000;
211                 let num_colors = palette.len() / 3;
212                 if num_colors > 256 {
213                     return Err(EncodingError::from(FormatErrorKind::TooManyColors));
214                 }
215                 flags |= flag_size(num_colors);
216                 self.w.write_le(flags)?;
217                 self.write_color_table(palette)
218             },
219             None => if !self.global_palette {
220                 Err(EncodingError::from(FormatErrorKind::MissingColorPalette))
221             } else {
222                 self.w.write_le(flags).map_err(Into::into)
223             }
224         }?;
225         self.write_image_block(&frame.buffer)
226     }
227 
write_image_block(&mut self, data: &[u8]) -> Result<(), EncodingError>228     fn write_image_block(&mut self, data: &[u8]) -> Result<(), EncodingError> {
229         {
230             let min_code_size: u8 = match flag_size(*data.iter().max().unwrap_or(&0) as usize + 1) + 1 {
231                 1 => 2, // As per gif spec: The minimal code size has to be >= 2
232                 n => n
233             };
234             self.w.write_le(min_code_size)?;
235             self.buffer.clear();
236             let mut enc = LzwEncoder::new(BitOrder::Lsb, min_code_size);
237             let len = enc.into_vec(&mut self.buffer).encode_all(data).consumed_out;
238 
239             // Write blocks. `chunks_exact` seems to be slightly faster
240             // than `chunks` according to both Rust docs and benchmark results.
241             let mut iter = self.buffer[..len].chunks_exact(0xFF);
242             while let Some(full_block) = iter.next() {
243                 self.w.write_le(0xFFu8)?;
244                 self.w.write_all(full_block)?;
245             }
246             let last_block = iter.remainder();
247             if !last_block.is_empty() {
248                 self.w.write_le(last_block.len() as u8)?;
249                 self.w.write_all(last_block)?;
250             }
251         }
252         self.w.write_le(0u8).map_err(Into::into)
253     }
254 
write_color_table(&mut self, table: &[u8]) -> Result<(), EncodingError>255     fn write_color_table(&mut self, table: &[u8]) -> Result<(), EncodingError> {
256         let num_colors = table.len() / 3;
257         if num_colors > 256 {
258             return Err(EncodingError::from(FormatErrorKind::TooManyColors));
259         }
260         let size = flag_size(num_colors);
261         self.w.write_all(&table[..num_colors * 3])?;
262         // Waste some space as of gif spec
263         for _ in 0..((2 << size) - num_colors) {
264             self.w.write_all(&[0, 0, 0])?
265         }
266         Ok(())
267     }
268 
269     /// Writes an extension to the image.
270     ///
271     /// It is normally not necessary to call this method manually.
write_extension(&mut self, extension: ExtensionData) -> Result<(), EncodingError>272     pub fn write_extension(&mut self, extension: ExtensionData) -> Result<(), EncodingError> {
273         use self::ExtensionData::*;
274         // 0 finite repetitions can only be achieved
275         // if the corresponting extension is not written
276         if let Repetitions(Repeat::Finite(0)) = extension {
277             return Ok(())
278         }
279         self.w.write_le(Block::Extension as u8)?;
280         match extension {
281             Control { flags, delay, trns } => {
282                 self.w.write_le(Extension::Control as u8)?;
283                 self.w.write_le(4u8)?;
284                 self.w.write_le(flags)?;
285                 self.w.write_le(delay)?;
286                 self.w.write_le(trns)?;
287             }
288             Repetitions(repeat) => {
289                 self.w.write_le(Extension::Application as u8)?;
290                 self.w.write_le(11u8)?;
291                 self.w.write_all(b"NETSCAPE2.0")?;
292                 self.w.write_le(3u8)?;
293                 self.w.write_le(1u8)?;
294                 match repeat {
295                     Repeat::Finite(no) => self.w.write_le(no)?,
296                     Repeat::Infinite => self.w.write_le(0u16)?,
297                 }
298             }
299         }
300         self.w.write_le(0u8).map_err(Into::into)
301     }
302 
303     /// Writes a raw extension to the image.
304     ///
305     /// This method can be used to write an unsupported extension to the file. `func` is the extension
306     /// identifier (e.g. `Extension::Application as u8`). `data` are the extension payload blocks. If any
307     /// contained slice has a lenght > 255 it is automatically divided into sub-blocks.
write_raw_extension(&mut self, func: AnyExtension, data: &[&[u8]]) -> io::Result<()>308     pub fn write_raw_extension(&mut self, func: AnyExtension, data: &[&[u8]]) -> io::Result<()> {
309         self.w.write_le(Block::Extension as u8)?;
310         self.w.write_le(func.0)?;
311         for block in data {
312             for chunk in block.chunks(0xFF) {
313                 self.w.write_le(chunk.len() as u8)?;
314                 self.w.write_all(chunk)?;
315             }
316         }
317         self.w.write_le(0u8)
318     }
319 
320     /// Writes the logical screen desriptor
write_screen_desc(&mut self, flags: u8) -> io::Result<()>321     fn write_screen_desc(&mut self, flags: u8) -> io::Result<()> {
322         self.w.write_all(b"GIF89a")?;
323         self.w.write_le(self.width)?;
324         self.w.write_le(self.height)?;
325         self.w.write_le(flags)?; // packed field
326         self.w.write_le(0u8)?; // bg index
327         self.w.write_le(0u8) // aspect ratio
328     }
329 }
330 
331 impl<W: Write> Drop for Encoder<W> {
332 
333     #[cfg(feature = "raii_no_panic")]
drop(&mut self)334     fn drop(&mut self) {
335         let _ = self.w.write_le(Block::Trailer as u8);
336     }
337 
338     #[cfg(not(feature = "raii_no_panic"))]
drop(&mut self)339     fn drop(&mut self) {
340         self.w.write_le(Block::Trailer as u8).unwrap()
341     }
342 }
343 
344 // Color table size converted to flag bits
flag_size(size: usize) -> u8345 fn flag_size(size: usize) -> u8 {
346     match size {
347         0  ..=2   => 0,
348         3  ..=4   => 1,
349         5  ..=8   => 2,
350         9  ..=16  => 3,
351         17 ..=32  => 4,
352         33 ..=64  => 5,
353         65 ..=128 => 6,
354         129..=256 => 7,
355         _ => 7
356     }
357 }
358 
359 #[test]
error_cast()360 fn error_cast() {
361     let _ : Box<dyn error::Error> = EncodingError::from(FormatErrorKind::MissingColorPalette).into();
362 }
363