1 
2 //! # Minimal gif encoder
3 
4 
5 
6 use std::cmp::min;
7 use std::io;
8 use std::io::prelude::*;
9 
10 use lzw;
11 
12 use traits::{Parameter, WriteBytesExt};
13 use common::{Block, Frame, Extension, DisposalMethod};
14 
15 /// Number of repetitions
16 pub enum Repeat {
17     /// Finite number of repetitions
18     Finite(u16),
19     /// Infinite number of repetitions
20     Infinite
21 }
22 
23 impl<W: Write> Parameter<Encoder<W>> for Repeat {
24     type Result = Result<(), io::Error>;
set_param(self, this: &mut Encoder<W>) -> Self::Result25     fn set_param(self, this: &mut Encoder<W>) -> Self::Result {
26         this.write_extension(ExtensionData::Repetitions(self))
27     }
28 }
29 
30 /// Extension data.
31 pub enum ExtensionData {
32     /// Control extension. Use `ExtensionData::new_control_ext` to construct.
33     Control {
34         /// Flags.
35         flags: u8,
36         /// Frame delay.
37         delay: u16,
38         /// Transparent index.
39         trns: u8
40     },
41     /// Sets the number of repetitions
42     Repetitions(Repeat)
43 }
44 
45 impl ExtensionData {
46     /// Constructor for control extension data.
47     ///
48     /// `delay` is given in units of 10 ms.
new_control_ext(delay: u16, dispose: DisposalMethod, needs_user_input: bool, trns: Option<u8>) -> ExtensionData49     pub fn new_control_ext(delay: u16, dispose: DisposalMethod,
50                            needs_user_input: bool, trns: Option<u8>) -> ExtensionData {
51         let mut flags = 0;
52         let trns = match trns {
53             Some(trns) => {
54                 flags |= 1;
55                 trns as u8
56             },
57             None => 0
58         };
59         flags |= (needs_user_input as u8) << 1;
60         flags |= (dispose as u8) << 2;
61         ExtensionData::Control {
62             flags: flags,
63             delay: delay,
64             trns: trns
65         }
66     }
67 }
68 
69 struct BlockWriter<'a, W: Write + 'a> {
70     w: &'a mut W,
71     bytes: usize,
72     buf: [u8; 0xFF]
73 }
74 
75 
76 impl<'a, W: Write + 'a> BlockWriter<'a, W> {
new(w: &'a mut W) -> BlockWriter<'a, W>77     fn new(w: &'a mut W) -> BlockWriter<'a, W> {
78         BlockWriter {
79             w: w,
80             bytes: 0,
81             buf: [0; 0xFF]
82         }
83     }
84 }
85 
86 impl<'a, W: Write + 'a> Write for BlockWriter<'a, W> {
87 
write(&mut self, buf: &[u8]) -> io::Result<usize>88     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
89         let to_copy = min(buf.len(), 0xFF - self.bytes);
90         { // isolation to please borrow checker
91             let destination = &mut self.buf[self.bytes..];
92             destination[..to_copy].copy_from_slice(&buf[..to_copy]);
93         }
94         self.bytes += to_copy;
95         if self.bytes == 0xFF {
96             self.bytes = 0;
97             self.w.write_le(0xFFu8)?;
98             self.w.write_all(&self.buf)?;
99         }
100         Ok(to_copy)
101     }
flush(&mut self) -> io::Result<()>102     fn flush(&mut self) -> io::Result<()> {
103         return Err(io::Error::new(
104             io::ErrorKind::Other,
105             "Cannot flush a BlockWriter, use `drop` instead."
106         ))
107     }
108 }
109 
110 impl<'a, W: Write + 'a> Drop for BlockWriter<'a, W> {
111 
112     #[cfg(feature = "raii_no_panic")]
drop(&mut self)113     fn drop(&mut self) {
114         if self.bytes > 0 {
115             let _ = self.w.write_le(self.bytes as u8);
116             let _ = self.w.write_all(&self.buf[..self.bytes]);
117         }
118     }
119 
120     #[cfg(not(feature = "raii_no_panic"))]
drop(&mut self)121     fn drop(&mut self) {
122         if self.bytes > 0 {
123             self.w.write_le(self.bytes as u8).unwrap();
124             self.w.write_all(&self.buf[..self.bytes]).unwrap();
125         }
126     }
127 }
128 
129 /// GIF encoder.
130 pub struct Encoder<W: Write> {
131     w: W,
132     global_palette: bool,
133     width: u16,
134     height: u16
135 }
136 
137 impl<W: Write> Encoder<W> {
138     /// Creates a new encoder.
139     ///
140     /// `global_palette` gives the global color palette in the format `[r, g, b, ...]`,
141     /// if no global palette shall be used an empty slice may be supplied.
new(w: W, width: u16, height: u16, global_palette: &[u8]) -> io::Result<Self>142     pub fn new(w: W, width: u16, height: u16, global_palette: &[u8]) -> io::Result<Self> {
143         Encoder {
144             w: w,
145             global_palette: false,
146             width: width,
147             height: height
148         }.write_global_palette(global_palette)
149     }
150 
151     /// Writes the global color palette.
write_global_palette(mut self, palette: &[u8]) -> io::Result<Self>152     pub fn write_global_palette(mut self, palette: &[u8]) -> io::Result<Self> {
153         self.global_palette = true;
154         let mut flags = 0;
155         flags |= 0b1000_0000;
156         let num_colors = palette.len() / 3;
157         if num_colors > 256 {
158             return Err(io::Error::new(io::ErrorKind::InvalidInput, "Too many colors"));
159         }
160         flags |= flag_size(num_colors);
161         flags |= flag_size(num_colors) << 4; // wtf flag
162         self.write_screen_desc(flags)?;
163         self.write_color_table(palette)?;
164         Ok(self)
165     }
166 
167     /// Writes a frame to the image.
168     ///
169     /// Note: This function also writes a control extension if necessary.
write_frame(&mut self, frame: &Frame) -> io::Result<()>170     pub fn write_frame(&mut self, frame: &Frame) -> io::Result<()> {
171         // TODO commented off to pass test in lib.rs
172         //if frame.delay > 0 || frame.transparent.is_some() {
173             self.write_extension(ExtensionData::new_control_ext(
174                 frame.delay,
175                 frame.dispose,
176                 frame.needs_user_input,
177                 frame.transparent
178 
179             ))?;
180         //}
181         self.w.write_le(Block::Image as u8)?;
182         self.w.write_le(frame.left)?;
183         self.w.write_le(frame.top)?;
184         self.w.write_le(frame.width)?;
185         self.w.write_le(frame.height)?;
186         let mut flags = 0;
187         if frame.interlaced {
188             flags |= 0b0100_0000;
189         }
190         match frame.palette {
191             Some(ref palette) => {
192                 flags |= 0b1000_0000;
193                 let num_colors = palette.len() / 3;
194                 if num_colors > 256 {
195                     return Err(io::Error::new(io::ErrorKind::InvalidInput, "Too many colors"));
196                 }
197                 flags |= flag_size(num_colors);
198                 self.w.write_le(flags)?;
199                 self.write_color_table(palette)
200             },
201             None => if !self.global_palette {
202                 return Err(io::Error::new(
203                     io::ErrorKind::InvalidInput,
204                     "The GIF format requires a color palette but none was given."
205                 ))
206             } else {
207                 self.w.write_le(flags)
208             }
209         }?;
210         self.write_image_block(&frame.buffer)
211     }
212 
write_image_block(&mut self, data: &[u8]) -> io::Result<()>213     fn write_image_block(&mut self, data: &[u8]) -> io::Result<()> {
214         {
215             let min_code_size: u8 = match flag_size(*data.iter().max().unwrap_or(&0) as usize + 1) + 1 {
216                 1 => 2, // As per gif spec: The minimal code size has to be >= 2
217                 n => n
218             };
219             self.w.write_le(min_code_size)?;
220             let mut bw = BlockWriter::new(&mut self.w);
221             let mut enc = lzw::Encoder::new(lzw::LsbWriter::new(&mut bw), min_code_size)?;
222             enc.encode_bytes(data)?;
223         }
224         self.w.write_le(0u8)
225     }
226 
write_color_table(&mut self, table: &[u8]) -> io::Result<()>227     fn write_color_table(&mut self, table: &[u8]) -> io::Result<()> {
228         let num_colors = table.len() / 3;
229         if num_colors > 256 {
230             return Err(io::Error::new(io::ErrorKind::InvalidInput, "Too many colors"));
231         }
232         let size = flag_size(num_colors);
233         self.w.write_all(&table[..num_colors * 3])?;
234         // Waste some space as of gif spec
235         for _ in 0..((2 << size) - num_colors) {
236             self.w.write_all(&[0, 0, 0])?
237         }
238         Ok(())
239     }
240 
241     /// Writes an extension to the image.
242     ///
243     /// It is normally not necessary to call this method manually.
write_extension(&mut self, extension: ExtensionData) -> io::Result<()>244     pub fn write_extension(&mut self, extension: ExtensionData) -> io::Result<()> {
245         use self::ExtensionData::*;
246         // 0 finite repetitions can only be achieved
247         // if the corresponting extension is not written
248         if let Repetitions(Repeat::Finite(0)) = extension {
249             return Ok(())
250         }
251         self.w.write_le(Block::Extension as u8)?;
252         match extension {
253             Control { flags, delay, trns } => {
254                 self.w.write_le(Extension::Control as u8)?;
255                 self.w.write_le(4u8)?;
256                 self.w.write_le(flags)?;
257                 self.w.write_le(delay)?;
258                 self.w.write_le(trns)?;
259             }
260             Repetitions(repeat) => {
261                 self.w.write_le(Extension::Application as u8)?;
262                 self.w.write_le(11u8)?;
263                 self.w.write(b"NETSCAPE2.0")?;
264                 self.w.write_le(3u8)?;
265                 self.w.write_le(1u8)?;
266                 match repeat {
267                     Repeat::Finite(no) => self.w.write_le(no)?,
268                     Repeat::Infinite => self.w.write_le(0u16)?,
269                 }
270             }
271         }
272         self.w.write_le(0u8)
273     }
274 
275     /// Writes a raw extension to the image.
276     ///
277     /// This method can be used to write an unsupported extesion to the file. `func` is the extension
278     /// identifier (e.g. `Extension::Application as u8`). `data` are the extension payload blocks. If any
279     /// contained slice has a lenght > 255 it is automatically divided into sub-blocks.
write_raw_extension(&mut self, func: u8, data: &[&[u8]]) -> io::Result<()>280     pub fn write_raw_extension(&mut self, func: u8, data: &[&[u8]]) -> io::Result<()> {
281         self.w.write_le(Block::Extension as u8)?;
282         self.w.write_le(func as u8)?;
283         for block in data {
284             for chunk in block.chunks(0xFF) {
285                 self.w.write_le(chunk.len() as u8)?;
286                 self.w.write_all(chunk)?;
287             }
288         }
289         self.w.write_le(0u8)
290     }
291 
292     /// Writes the logical screen desriptor
write_screen_desc(&mut self, flags: u8) -> io::Result<()>293     fn write_screen_desc(&mut self, flags: u8) -> io::Result<()> {
294         self.w.write_all(b"GIF89a")?;
295         self.w.write_le(self.width)?;
296         self.w.write_le(self.height)?;
297         self.w.write_le(flags)?; // packed field
298         self.w.write_le(0u8)?; // bg index
299         self.w.write_le(0u8) // aspect ratio
300     }
301 }
302 
303 impl<W: Write> Drop for Encoder<W> {
304 
305     #[cfg(feature = "raii_no_panic")]
drop(&mut self)306     fn drop(&mut self) {
307         let _ = self.w.write_le(Block::Trailer as u8);
308     }
309 
310     #[cfg(not(feature = "raii_no_panic"))]
drop(&mut self)311     fn drop(&mut self) {
312         self.w.write_le(Block::Trailer as u8).unwrap()
313     }
314 }
315 
316 // Color table size converted to flag bits
flag_size(size: usize) -> u8317 fn flag_size(size: usize) -> u8 {
318     match size {
319         0  ...2   => 0,
320         3  ...4   => 1,
321         5  ...8   => 2,
322         7  ...16  => 3,
323         17 ...32  => 4,
324         33 ...64  => 5,
325         65 ...128 => 6,
326         129...256 => 7,
327         _ => 7
328     }
329 }
330