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