1 use borrow::Cow;
2 use io::{Read, Write};
3 use ops::{Deref, DerefMut};
4 use std::{borrow, error, fmt, io, mem, ops, result};
5 
6 use crc32fast::Hasher as Crc32;
7 use deflate::write::ZlibEncoder;
8 
9 use crate::chunk::{self, ChunkType};
10 use crate::common::{
11     AnimationControl, BitDepth, BlendOp, BytesPerPixel, ColorType, Compression, DisposeOp,
12     FrameControl, Info, ParameterError, ParameterErrorKind, ScaledFloat,
13 };
14 use crate::filter::{filter, AdaptiveFilterType, FilterType};
15 use crate::traits::WriteBytesExt;
16 
17 pub type Result<T> = result::Result<T, EncodingError>;
18 
19 #[derive(Debug)]
20 pub enum EncodingError {
21     IoError(io::Error),
22     Format(FormatError),
23     Parameter(ParameterError),
24     LimitsExceeded,
25 }
26 
27 #[derive(Debug)]
28 pub struct FormatError {
29     inner: FormatErrorKind,
30 }
31 
32 #[derive(Debug)]
33 enum FormatErrorKind {
34     ZeroWidth,
35     ZeroHeight,
36     InvalidColorCombination(BitDepth, ColorType),
37     NoPalette,
38     // TODO: wait, what?
39     WrittenTooMuch(usize),
40     NotAnimated,
41     OutOfBounds,
42     EndReached,
43     ZeroFrames,
44     MissingFrames,
45     MissingData(usize),
46     Unrecoverable,
47 }
48 
49 impl error::Error for EncodingError {
cause(&self) -> Option<&(dyn error::Error + 'static)>50     fn cause(&self) -> Option<&(dyn error::Error + 'static)> {
51         match self {
52             EncodingError::IoError(err) => Some(err),
53             _ => None,
54         }
55     }
56 }
57 
58 impl fmt::Display for EncodingError {
fmt(&self, fmt: &mut fmt::Formatter) -> result::Result<(), fmt::Error>59     fn fmt(&self, fmt: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
60         use self::EncodingError::*;
61         match self {
62             IoError(err) => write!(fmt, "{}", err),
63             Format(desc) => write!(fmt, "{}", desc),
64             Parameter(desc) => write!(fmt, "{}", desc),
65             LimitsExceeded => write!(fmt, "Limits are exceeded."),
66         }
67     }
68 }
69 
70 impl fmt::Display for FormatError {
fmt(&self, fmt: &mut fmt::Formatter) -> result::Result<(), fmt::Error>71     fn fmt(&self, fmt: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
72         use FormatErrorKind::*;
73         match self.inner {
74             ZeroWidth => write!(fmt, "Zero width not allowed"),
75             ZeroHeight => write!(fmt, "Zero height not allowed"),
76             ZeroFrames => write!(fmt, "Zero frames not allowed"),
77             InvalidColorCombination(depth, color) => write!(
78                 fmt,
79                 "Invalid combination of bit-depth '{:?}' and color-type '{:?}'",
80                 depth, color
81             ),
82             NoPalette => write!(fmt, "can't write indexed image without palette"),
83             WrittenTooMuch(index) => write!(fmt, "wrong data size, got {} bytes too many", index),
84             NotAnimated => write!(fmt, "not an animation"),
85             OutOfBounds => write!(
86                 fmt,
87                 "the dimension and position go over the frame boundaries"
88             ),
89             EndReached => write!(fmt, "all the frames have been already written"),
90             MissingFrames => write!(fmt, "there are still frames to be written"),
91             MissingData(n) => write!(fmt, "there are still {} bytes to be written", n),
92             Unrecoverable => write!(
93                 fmt,
94                 "a previous error put the writer into an unrecoverable state"
95             ),
96         }
97     }
98 }
99 
100 impl From<io::Error> for EncodingError {
from(err: io::Error) -> EncodingError101     fn from(err: io::Error) -> EncodingError {
102         EncodingError::IoError(err)
103     }
104 }
105 
106 impl From<EncodingError> for io::Error {
from(err: EncodingError) -> io::Error107     fn from(err: EncodingError) -> io::Error {
108         io::Error::new(io::ErrorKind::Other, err.to_string())
109     }
110 }
111 
112 // Private impl.
113 impl From<FormatErrorKind> for FormatError {
from(kind: FormatErrorKind) -> Self114     fn from(kind: FormatErrorKind) -> Self {
115         FormatError { inner: kind }
116     }
117 }
118 
119 /// PNG Encoder
120 pub struct Encoder<'a, W: Write> {
121     w: W,
122     info: Info<'a>,
123     filter: FilterType,
124     adaptive_filter: AdaptiveFilterType,
125     sep_def_img: bool,
126 }
127 
128 impl<'a, W: Write> Encoder<'a, W> {
new(w: W, width: u32, height: u32) -> Encoder<'static, W>129     pub fn new(w: W, width: u32, height: u32) -> Encoder<'static, W> {
130         Encoder {
131             w,
132             info: Info::with_size(width, height),
133             filter: FilterType::default(),
134             adaptive_filter: AdaptiveFilterType::default(),
135             sep_def_img: false,
136         }
137     }
138 
139     /// Specify that the image is animated.
140     ///
141     /// `num_frames` controls how many frames the animation has, while
142     /// `num_plays` controls how many times the animation should be
143     /// repeaded until it stops, if it's zero then it will repeat
144     /// inifinitely
145     ///
146     /// This method returns an error if `num_frames` is 0.
set_animated(&mut self, num_frames: u32, num_plays: u32) -> Result<()>147     pub fn set_animated(&mut self, num_frames: u32, num_plays: u32) -> Result<()> {
148         if num_frames == 0 {
149             return Err(EncodingError::Format(FormatErrorKind::ZeroFrames.into()));
150         }
151         let actl = AnimationControl {
152             num_frames,
153             num_plays,
154         };
155         let fctl = FrameControl {
156             sequence_number: 0,
157             width: self.info.width,
158             height: self.info.height,
159             ..Default::default()
160         };
161         self.info.animation_control = Some(actl);
162         self.info.frame_control = Some(fctl);
163         Ok(())
164     }
165 
set_sep_def_img(&mut self, sep_def_img: bool) -> Result<()>166     pub fn set_sep_def_img(&mut self, sep_def_img: bool) -> Result<()> {
167         if self.info.animation_control.is_none() {
168             self.sep_def_img = sep_def_img;
169             Ok(())
170         } else {
171             Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
172         }
173     }
174 
175     /// Sets the raw byte contents of the PLTE chunk. This method accepts
176     /// both borrowed and owned byte data.
set_palette<T: Into<Cow<'a, [u8]>>>(&mut self, palette: T)177     pub fn set_palette<T: Into<Cow<'a, [u8]>>>(&mut self, palette: T) {
178         self.info.palette = Some(palette.into());
179     }
180 
181     /// Sets the raw byte contents of the tRNS chunk. This method accepts
182     /// both borrowed and owned byte data.
set_trns<T: Into<Cow<'a, [u8]>>>(&mut self, trns: T)183     pub fn set_trns<T: Into<Cow<'a, [u8]>>>(&mut self, trns: T) {
184         self.info.trns = Some(trns.into());
185     }
186 
187     /// Set the display gamma of the source system on which the image was generated or last edited.
set_source_gamma(&mut self, source_gamma: ScaledFloat)188     pub fn set_source_gamma(&mut self, source_gamma: ScaledFloat) {
189         self.info.source_gamma = Some(source_gamma);
190     }
191 
192     /// Set the chromaticities for the source system's display channels (red, green, blue) and the whitepoint
193     /// of the source system on which the image was generated or last edited.
set_source_chromaticities( &mut self, source_chromaticities: super::SourceChromaticities, )194     pub fn set_source_chromaticities(
195         &mut self,
196         source_chromaticities: super::SourceChromaticities,
197     ) {
198         self.info.source_chromaticities = Some(source_chromaticities);
199     }
200 
201     /// Mark the image data as conforming to the SRGB color space with the specified rendering intent.
202     ///
203     /// Matching source gamma and chromaticities chunks are added automatically.
204     /// Any manually specified source gamma or chromaticities will be ignored.
set_srgb(&mut self, rendering_intent: super::SrgbRenderingIntent)205     pub fn set_srgb(&mut self, rendering_intent: super::SrgbRenderingIntent) {
206         self.info.srgb = Some(rendering_intent);
207     }
208 
write_header(self) -> Result<Writer<W>>209     pub fn write_header(self) -> Result<Writer<W>> {
210         Writer::new(
211             self.w,
212             PartialInfo::new(&self.info),
213             self.filter,
214             self.adaptive_filter,
215             self.sep_def_img,
216         )
217         .init(&self.info)
218     }
219 
220     /// Set the color of the encoded image.
221     ///
222     /// These correspond to the color types in the png IHDR data that will be written. The length
223     /// of the image data that is later supplied must match the color type, otherwise an error will
224     /// be emitted.
set_color(&mut self, color: ColorType)225     pub fn set_color(&mut self, color: ColorType) {
226         self.info.color_type = color;
227     }
228 
229     /// Set the indicated depth of the image data.
set_depth(&mut self, depth: BitDepth)230     pub fn set_depth(&mut self, depth: BitDepth) {
231         self.info.bit_depth = depth;
232     }
233 
234     /// Set compression parameters.
235     ///
236     /// Accepts a `Compression` or any type that can transform into a `Compression`. Notably `deflate::Compression` and
237     /// `deflate::CompressionOptions` which "just work".
set_compression(&mut self, compression: Compression)238     pub fn set_compression(&mut self, compression: Compression) {
239         self.info.compression = compression;
240     }
241 
242     /// Set the used filter type.
243     ///
244     /// The default filter is [`FilterType::Sub`] which provides a basic prediction algorithm for
245     /// sample values based on the previous. For a potentially better compression ratio, at the
246     /// cost of more complex processing, try out [`FilterType::Paeth`].
247     ///
248     /// [`FilterType::Sub`]: enum.FilterType.html#variant.Sub
249     /// [`FilterType::Paeth`]: enum.FilterType.html#variant.Paeth
set_filter(&mut self, filter: FilterType)250     pub fn set_filter(&mut self, filter: FilterType) {
251         self.filter = filter;
252     }
253 
254     /// Set the adaptive filter type.
255     ///
256     /// Adaptive filtering attempts to select the best filter for each line
257     /// based on heuristics which minimize the file size for compression rather
258     /// than use a single filter for the entire image. The default method is
259     /// [`AdaptiveFilterType::NonAdaptive`].
260     ///
261     /// [`AdaptiveFilterType::NonAdaptive`]: enum.AdaptiveFilterType.html
set_adaptive_filter(&mut self, adaptive_filter: AdaptiveFilterType)262     pub fn set_adaptive_filter(&mut self, adaptive_filter: AdaptiveFilterType) {
263         self.adaptive_filter = adaptive_filter;
264     }
265 
266     /// Set the fraction of time every frame is going to be displayed, in seconds.
267     ///
268     /// *Note that this parameter can be set for each individual frame after
269     /// [`write_header`] is called. (see [`Writer::set_frame_delay`])*
270     ///
271     /// If the denominator is 0, it is to be treated as if it were 100
272     /// (that is, the numerator then specifies 1/100ths of a second).
273     /// If the the value of the numerator is 0 the decoder should render the next frame
274     /// as quickly as possible, though viewers may impose a reasonable lower bound.
275     ///
276     /// The default value is 0 for both the numerator and denominator.
277     ///
278     /// This method will return an error if the image is not animated.
279     /// (see [`set_animated`])
280     ///
281     /// [`write_header`]: struct.Encoder.html#method.write_header
282     /// [`set_animated`]: struct.Encoder.html#method.set_animated
283     /// [`Writer::set_frame_delay`]: struct.Writer#method.set_frame_delay
set_frame_delay(&mut self, numerator: u16, denominator: u16) -> Result<()>284     pub fn set_frame_delay(&mut self, numerator: u16, denominator: u16) -> Result<()> {
285         if let Some(ref mut fctl) = self.info.frame_control {
286             fctl.delay_den = denominator;
287             fctl.delay_num = numerator;
288             Ok(())
289         } else {
290             Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
291         }
292     }
293 
294     /// Set the blend operation for every frame.
295     ///
296     /// The blend operation specifies whether the frame is to be alpha blended
297     /// into the current output buffer content, or whether it should completely
298     /// replace its region in the output buffer.
299     ///
300     /// *Note that this parameter can be set for each individual frame after
301     /// [`writer_header`] is called. (see [`Writer::set_blend_op`])*
302     ///
303     /// See the [`BlendOp`] documentaion for the possible values and their effects.
304     ///
305     /// *Note that for the first frame the two blend modes are functionally
306     /// equivalent due to the clearing of the output buffer at the beginning
307     /// of each play.*
308     ///
309     /// The default value is [`BlendOp::Source`].
310     ///
311     /// This method will return an error if the image is not animated.
312     /// (see [`set_animated`])
313     ///
314     /// [`BlendOP`]: enum.BlendOp.html
315     /// [`BlendOP::Source`]: enum.BlendOp.html#variant.Source
316     /// [`write_header`]: struct.Encoder.html#method.write_header
317     /// [`set_animated`]: struct.Encoder.html#method.set_animated
318     /// [`Writer::set_blend_op`]: struct.Writer#method.set_blend_op
set_blend_op(&mut self, op: BlendOp) -> Result<()>319     pub fn set_blend_op(&mut self, op: BlendOp) -> Result<()> {
320         if let Some(ref mut fctl) = self.info.frame_control {
321             fctl.blend_op = op;
322             Ok(())
323         } else {
324             Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
325         }
326     }
327 
328     /// Set the dispose operation for every frame.
329     ///
330     /// The dispose operation specifies how the output buffer should be changed
331     /// at the end of the delay (before rendering the next frame)
332     ///
333     /// *Note that this parameter can be set for each individual frame after
334     /// [`writer_header`] is called (see [`Writer::set_dispose_op`])*
335     ///
336     /// See the [`DisposeOp`] documentaion for the possible values and their effects.
337     ///
338     /// *Note that if the first frame uses [`DisposeOp::Previous`]
339     /// it will be treated as [`DisposeOp::Background`].*
340     ///
341     /// The default value is [`DisposeOp::None`].
342     ///
343     /// This method will return an error if the image is not animated.
344     /// (see [`set_animated`])
345     ///
346     /// [`DisposeOp`]: ../common/enum.BlendOp.html
347     /// [`DisposeOp::Previous`]: ../common/enum.BlendOp.html#variant.Previous
348     /// [`DisposeOp::Background`]: ../common/enum.BlendOp.html#variant.Background
349     /// [`DisposeOp::None`]: ../common/enum.BlendOp.html#variant.None
350     /// [`write_header`]: struct.Encoder.html#method.write_header
351     /// [`set_animated`]: struct.Encoder.html#method.set_animated
352     /// [`Writer::set_dispose_op`]: struct.Writer#method.set_dispose_op
set_dispose_op(&mut self, op: DisposeOp) -> Result<()>353     pub fn set_dispose_op(&mut self, op: DisposeOp) -> Result<()> {
354         if let Some(ref mut fctl) = self.info.frame_control {
355             fctl.dispose_op = op;
356             Ok(())
357         } else {
358             Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
359         }
360     }
361 }
362 
363 /// PNG writer
364 pub struct Writer<W: Write> {
365     w: W,
366     info: PartialInfo,
367     filter: FilterType,
368     adaptive_filter: AdaptiveFilterType,
369     sep_def_img: bool,
370     written: u64,
371 }
372 
373 /// Contains the subset of attributes of [Info] needed for [Writer] to function
374 struct PartialInfo {
375     width: u32,
376     height: u32,
377     bit_depth: BitDepth,
378     color_type: ColorType,
379     frame_control: Option<FrameControl>,
380     animation_control: Option<AnimationControl>,
381     compression: Compression,
382     has_palette: bool,
383 }
384 
385 impl PartialInfo {
new(info: &Info) -> Self386     fn new(info: &Info) -> Self {
387         PartialInfo {
388             width: info.width,
389             height: info.height,
390             bit_depth: info.bit_depth,
391             color_type: info.color_type,
392             frame_control: info.frame_control,
393             animation_control: info.animation_control,
394             compression: info.compression,
395             has_palette: info.palette.is_some(),
396         }
397     }
398 
bpp_in_prediction(&self) -> BytesPerPixel399     fn bpp_in_prediction(&self) -> BytesPerPixel {
400         // Passthrough
401         self.to_info().bpp_in_prediction()
402     }
403 
raw_row_length(&self) -> usize404     fn raw_row_length(&self) -> usize {
405         // Passthrough
406         self.to_info().raw_row_length()
407     }
408 
raw_row_length_from_width(&self, width: u32) -> usize409     fn raw_row_length_from_width(&self, width: u32) -> usize {
410         // Passthrough
411         self.to_info().raw_row_length_from_width(width)
412     }
413 
414     /// Converts this partial info to an owned Info struct,
415     /// setting missing values to their defaults
to_info(&self) -> Info<'static>416     fn to_info(&self) -> Info<'static> {
417         let mut info = Info::default();
418         info.width = self.width;
419         info.height = self.height;
420         info.bit_depth = self.bit_depth;
421         info.color_type = self.color_type;
422         info.frame_control = self.frame_control;
423         info.animation_control = self.animation_control;
424         info.compression = self.compression;
425         info
426     }
427 }
428 
429 const DEFAULT_BUFFER_LENGTH: usize = 4 * 1024;
430 
write_chunk<W: Write>(mut w: W, name: chunk::ChunkType, data: &[u8]) -> Result<()>431 pub(crate) fn write_chunk<W: Write>(mut w: W, name: chunk::ChunkType, data: &[u8]) -> Result<()> {
432     w.write_be(data.len() as u32)?;
433     w.write_all(&name.0)?;
434     w.write_all(data)?;
435     let mut crc = Crc32::new();
436     crc.update(&name.0);
437     crc.update(data);
438     w.write_be(crc.finalize())?;
439     Ok(())
440 }
441 
442 impl<W: Write> Writer<W> {
new( w: W, info: PartialInfo, filter: FilterType, adaptive_filter: AdaptiveFilterType, sep_def_img: bool, ) -> Writer<W>443     fn new(
444         w: W,
445         info: PartialInfo,
446         filter: FilterType,
447         adaptive_filter: AdaptiveFilterType,
448         sep_def_img: bool,
449     ) -> Writer<W> {
450         Writer {
451             w,
452             info,
453             filter,
454             adaptive_filter,
455             sep_def_img,
456             written: 0,
457         }
458     }
459 
init(mut self, info: &Info<'_>) -> Result<Self>460     fn init(mut self, info: &Info<'_>) -> Result<Self> {
461         if self.info.width == 0 {
462             return Err(EncodingError::Format(FormatErrorKind::ZeroWidth.into()));
463         }
464 
465         if self.info.height == 0 {
466             return Err(EncodingError::Format(FormatErrorKind::ZeroHeight.into()));
467         }
468 
469         if self
470             .info
471             .color_type
472             .is_combination_invalid(self.info.bit_depth)
473         {
474             return Err(EncodingError::Format(
475                 FormatErrorKind::InvalidColorCombination(self.info.bit_depth, self.info.color_type)
476                     .into(),
477             ));
478         }
479 
480         self.w.write_all(&[137, 80, 78, 71, 13, 10, 26, 10])?; // PNG signature
481         info.encode(&mut self.w)?;
482 
483         Ok(self)
484     }
485 
write_chunk(&mut self, name: ChunkType, data: &[u8]) -> Result<()>486     pub fn write_chunk(&mut self, name: ChunkType, data: &[u8]) -> Result<()> {
487         write_chunk(&mut self.w, name, data)
488     }
489 
max_frames(&self) -> u64490     fn max_frames(&self) -> u64 {
491         match self.info.animation_control {
492             Some(a) if self.sep_def_img => a.num_frames as u64 + 1,
493             Some(a) => a.num_frames as u64,
494             None => 1,
495         }
496     }
497 
498     /// Writes the image data.
write_image_data(&mut self, data: &[u8]) -> Result<()>499     pub fn write_image_data(&mut self, data: &[u8]) -> Result<()> {
500         const MAX_IDAT_CHUNK_LEN: u32 = std::u32::MAX >> 1;
501         #[allow(non_upper_case_globals)]
502         const MAX_fdAT_CHUNK_LEN: u32 = (std::u32::MAX >> 1) - 4;
503 
504         if self.info.color_type == ColorType::Indexed && !self.info.has_palette {
505             return Err(EncodingError::Format(FormatErrorKind::NoPalette.into()));
506         }
507 
508         if self.written > self.max_frames() {
509             return Err(EncodingError::Format(FormatErrorKind::EndReached.into()));
510         }
511 
512         let width: usize;
513         let height: usize;
514         if let Some(ref mut fctl) = self.info.frame_control {
515             width = fctl.width as usize;
516             height = fctl.height as usize;
517         } else {
518             width = self.info.width as usize;
519             height = self.info.height as usize;
520         }
521 
522         let in_len = self.info.raw_row_length_from_width(width as u32) - 1;
523         let data_size = in_len * height;
524         if data_size != data.len() {
525             return Err(EncodingError::Parameter(
526                 ParameterErrorKind::ImageBufferSize {
527                     expected: data_size,
528                     actual: data.len(),
529                 }
530                 .into(),
531             ));
532         }
533 
534         let prev = vec![0; in_len];
535         let mut prev = prev.as_slice();
536         let mut current = vec![0; in_len];
537 
538         let mut zlib = deflate::write::ZlibEncoder::new(
539             Vec::new(),
540             self.info.compression.clone().to_options(),
541         );
542         let bpp = self.info.bpp_in_prediction();
543         let filter_method = self.filter;
544         let adaptive_method = self.adaptive_filter;
545         for line in data.chunks(in_len) {
546             current.copy_from_slice(&line);
547             let filter_type = filter(filter_method, adaptive_method, bpp, &prev, &mut current);
548             zlib.write_all(&[filter_type as u8])?;
549             zlib.write_all(&current)?;
550             prev = line;
551         }
552         let zlib_encoded = zlib.finish()?;
553         if self.sep_def_img || self.info.frame_control.is_none() {
554             self.sep_def_img = false;
555             for chunk in zlib_encoded.chunks(MAX_IDAT_CHUNK_LEN as usize) {
556                 self.write_chunk(chunk::IDAT, &chunk)?;
557             }
558         } else if let Some(ref mut fctl) = self.info.frame_control {
559             fctl.encode(&mut self.w)?;
560             fctl.sequence_number = fctl.sequence_number.wrapping_add(1);
561 
562             if self.written == 0 {
563                 for chunk in zlib_encoded.chunks(MAX_IDAT_CHUNK_LEN as usize) {
564                     self.write_chunk(chunk::IDAT, &chunk)?;
565                 }
566             } else {
567                 let buff_size = zlib_encoded.len().min(MAX_fdAT_CHUNK_LEN as usize);
568                 let mut alldata = vec![0u8; 4 + buff_size];
569                 for chunk in zlib_encoded.chunks(MAX_fdAT_CHUNK_LEN as usize) {
570                     alldata[..4].copy_from_slice(&fctl.sequence_number.to_be_bytes());
571                     alldata[4..][..chunk.len()].copy_from_slice(chunk);
572                     write_chunk(&mut self.w, chunk::fdAT, &alldata[..4 + chunk.len()])?;
573                     fctl.sequence_number = fctl.sequence_number.wrapping_add(1);
574                 }
575             }
576         } else {
577             unreachable!(); // this should be unreachable
578         }
579         self.written += 1;
580         Ok(())
581     }
582 
583     /// Set the used filter type for the following frames.
584     ///
585     /// The default filter is [`FilterType::Sub`] which provides a basic prediction algorithm for
586     /// sample values based on the previous. For a potentially better compression ratio, at the
587     /// cost of more complex processing, try out [`FilterType::Paeth`].
588     ///
589     /// [`FilterType::Sub`]: enum.FilterType.html#variant.Sub
590     /// [`FilterType::Paeth`]: enum.FilterType.html#variant.Paeth
set_filter(&mut self, filter: FilterType)591     pub fn set_filter(&mut self, filter: FilterType) {
592         self.filter = filter;
593     }
594 
595     /// Set the adaptive filter type for the following frames.
596     ///
597     /// Adaptive filtering attempts to select the best filter for each line
598     /// based on heuristics which minimize the file size for compression rather
599     /// than use a single filter for the entire image. The default method is
600     /// [`AdaptiveFilterType::NonAdaptive`].
601     ///
602     /// [`AdaptiveFilterType::NonAdaptive`]: enum.AdaptiveFilterType.html
set_adaptive_filter(&mut self, adaptive_filter: AdaptiveFilterType)603     pub fn set_adaptive_filter(&mut self, adaptive_filter: AdaptiveFilterType) {
604         self.adaptive_filter = adaptive_filter;
605     }
606 
607     /// Set the fraction of time the following frames are going to be displayed,
608     /// in seconds
609     ///
610     /// If the denominator is 0, it is to be treated as if it were 100
611     /// (that is, the numerator then specifies 1/100ths of a second).
612     /// If the the value of the numerator is 0 the decoder should render the next frame
613     /// as quickly as possible, though viewers may impose a reasonable lower bound.
614     ///
615     /// This method will return an error if the image is not animated.
set_frame_delay(&mut self, numerator: u16, denominator: u16) -> Result<()>616     pub fn set_frame_delay(&mut self, numerator: u16, denominator: u16) -> Result<()> {
617         if let Some(ref mut fctl) = self.info.frame_control {
618             fctl.delay_den = denominator;
619             fctl.delay_num = numerator;
620             Ok(())
621         } else {
622             Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
623         }
624     }
625 
626     /// Set the dimension of the following frames.
627     ///
628     /// This function will return an error when:
629     /// - The image is not an animated;
630     ///
631     /// - The selected dimension, considering also the current frame position,
632     ///   goes outside the image boudries;
633     ///
634     /// - One or both the width and height are 0;
635     ///
636     // ??? TODO ???
637     // - The next frame is the default image
set_frame_dimension(&mut self, width: u32, height: u32) -> Result<()>638     pub fn set_frame_dimension(&mut self, width: u32, height: u32) -> Result<()> {
639         if let Some(ref mut fctl) = self.info.frame_control {
640             if Some(width) > self.info.width.checked_sub(fctl.x_offset)
641                 || Some(height) > self.info.height.checked_sub(fctl.y_offset)
642             {
643                 return Err(EncodingError::Format(FormatErrorKind::OutOfBounds.into()));
644             } else if width == 0 {
645                 return Err(EncodingError::Format(FormatErrorKind::ZeroWidth.into()));
646             } else if height == 0 {
647                 return Err(EncodingError::Format(FormatErrorKind::ZeroHeight.into()));
648             }
649             fctl.width = width;
650             fctl.height = height;
651             Ok(())
652         } else {
653             Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
654         }
655     }
656 
657     /// Set the position of the following frames.
658     ///
659     /// An error will be returned if:
660     /// - The image is not animated;
661     ///
662     /// - The selected position, considering also the current frame dimension,
663     ///   goes outside the image boudries;
664     ///
665     // ??? TODO ???
666     // - The next frame is the default image
set_frame_position(&mut self, x: u32, y: u32) -> Result<()>667     pub fn set_frame_position(&mut self, x: u32, y: u32) -> Result<()> {
668         if let Some(ref mut fctl) = self.info.frame_control {
669             if Some(x) > self.info.width.checked_sub(fctl.width)
670                 || Some(y) > self.info.height.checked_sub(fctl.height)
671             {
672                 return Err(EncodingError::Format(FormatErrorKind::OutOfBounds.into()));
673             }
674             fctl.x_offset = x;
675             fctl.y_offset = y;
676             Ok(())
677         } else {
678             Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
679         }
680     }
681 
682     /// Set the frame dimension to occupy all the image, starting from
683     /// the current position.
684     ///
685     /// To reset the frame to the full image size [`reset_frame_position`]
686     /// should be called first.
687     ///
688     /// This method will return an error if the image is not animated.
689     ///
690     /// [`reset_frame_position`]: struct.Writer.html#method.reset_frame_position
reset_frame_dimension(&mut self) -> Result<()>691     pub fn reset_frame_dimension(&mut self) -> Result<()> {
692         if let Some(ref mut fctl) = self.info.frame_control {
693             fctl.width = self.info.width - fctl.x_offset;
694             fctl.height = self.info.height - fctl.y_offset;
695             Ok(())
696         } else {
697             Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
698         }
699     }
700 
701     /// Set the frame position to (0, 0).
702     ///
703     /// Equivalent to calling [`set_frame_position(0, 0)`].
704     ///
705     /// This method will return an error if the image is not animated.
706     ///
707     /// [`set_frame_position(0, 0)`]: struct.Writer.html#method.set_frame_position
reset_frame_position(&mut self) -> Result<()>708     pub fn reset_frame_position(&mut self) -> Result<()> {
709         if let Some(ref mut fctl) = self.info.frame_control {
710             fctl.x_offset = 0;
711             fctl.y_offset = 0;
712             Ok(())
713         } else {
714             Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
715         }
716     }
717 
718     /// Set the blend operation for the following frames.
719     ///
720     /// The blend operation specifies whether the frame is to be alpha blended
721     /// into the current output buffer content, or whether it should completely
722     /// replace its region in the output buffer.
723     ///
724     /// See the [`BlendOp`] documentaion for the possible values and their effects.
725     ///
726     /// *Note that for the first frame the two blend modes are functionally
727     /// equivalent due to the clearing of the output buffer at the beginning
728     /// of each play.*
729     ///
730     /// This method will return an error if the image is not animated.
731     ///
732     /// [`BlendOP`]: enum.BlendOp.html
set_blend_op(&mut self, op: BlendOp) -> Result<()>733     pub fn set_blend_op(&mut self, op: BlendOp) -> Result<()> {
734         if let Some(ref mut fctl) = self.info.frame_control {
735             fctl.blend_op = op;
736             Ok(())
737         } else {
738             Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
739         }
740     }
741 
742     /// Set the dispose operation for the following frames.
743     ///
744     /// The dispose operation specifies how the output buffer should be changed
745     /// at the end of the delay (before rendering the next frame)
746     ///
747     /// See the [`DisposeOp`] documentaion for the possible values and their effects.
748     ///
749     /// *Note that if the first frame uses [`DisposeOp::Previous`]
750     /// it will be treated as [`DisposeOp::Background`].*
751     ///
752     /// This method will return an error if the image is not animated.
753     ///
754     /// [`DisposeOp`]: ../common/enum.BlendOp.html
755     /// [`DisposeOp::Previous`]: ../common/enum.BlendOp.html#variant.Previous
756     /// [`DisposeOp::Background`]: ../common/enum.BlendOp.html#variant.Background
set_dispose_op(&mut self, op: DisposeOp) -> Result<()>757     pub fn set_dispose_op(&mut self, op: DisposeOp) -> Result<()> {
758         if let Some(ref mut fctl) = self.info.frame_control {
759             fctl.dispose_op = op;
760             Ok(())
761         } else {
762             Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
763         }
764     }
765 
766     /// Create a stream writer.
767     ///
768     /// This allows you to create images that do not fit in memory. The default
769     /// chunk size is 4K, use `stream_writer_with_size` to set another chunk
770     /// size.
771     ///
772     /// This borrows the writer which allows for manually appending additional
773     /// chunks after the image data has been written.
stream_writer(&mut self) -> Result<StreamWriter<W>>774     pub fn stream_writer(&mut self) -> Result<StreamWriter<W>> {
775         self.stream_writer_with_size(DEFAULT_BUFFER_LENGTH)
776     }
777 
778     /// Create a stream writer with custom buffer size.
779     ///
780     /// See [`stream_writer`].
781     ///
782     /// [`stream_writer`]: #fn.stream_writer
stream_writer_with_size(&mut self, size: usize) -> Result<StreamWriter<W>>783     pub fn stream_writer_with_size(&mut self, size: usize) -> Result<StreamWriter<W>> {
784         StreamWriter::new(ChunkOutput::Borrowed(self), size)
785     }
786 
787     /// Turn this into a stream writer for image data.
788     ///
789     /// This allows you to create images that do not fit in memory. The default
790     /// chunk size is 4K, use `stream_writer_with_size` to set another chunk
791     /// size.
into_stream_writer(self) -> Result<StreamWriter<'static, W>>792     pub fn into_stream_writer(self) -> Result<StreamWriter<'static, W>> {
793         self.into_stream_writer_with_size(DEFAULT_BUFFER_LENGTH)
794     }
795 
796     /// Turn this into a stream writer with custom buffer size.
797     ///
798     /// See [`into_stream_writer`].
799     ///
800     /// [`into_stream_writer`]: #fn.into_stream_writer
into_stream_writer_with_size(self, size: usize) -> Result<StreamWriter<'static, W>>801     pub fn into_stream_writer_with_size(self, size: usize) -> Result<StreamWriter<'static, W>> {
802         StreamWriter::new(ChunkOutput::Owned(self), size)
803     }
804 }
805 
806 impl<W: Write> Drop for Writer<W> {
drop(&mut self)807     fn drop(&mut self) {
808         let _ = self.write_chunk(chunk::IEND, &[]);
809     }
810 }
811 
812 enum ChunkOutput<'a, W: Write> {
813     Borrowed(&'a mut Writer<W>),
814     Owned(Writer<W>),
815 }
816 
817 // opted for deref for practical reasons
818 impl<'a, W: Write> Deref for ChunkOutput<'a, W> {
819     type Target = Writer<W>;
820 
deref(&self) -> &Self::Target821     fn deref(&self) -> &Self::Target {
822         match self {
823             ChunkOutput::Borrowed(writer) => writer,
824             ChunkOutput::Owned(writer) => writer,
825         }
826     }
827 }
828 
829 impl<'a, W: Write> DerefMut for ChunkOutput<'a, W> {
deref_mut(&mut self) -> &mut Self::Target830     fn deref_mut(&mut self) -> &mut Self::Target {
831         match self {
832             ChunkOutput::Borrowed(writer) => writer,
833             ChunkOutput::Owned(writer) => writer,
834         }
835     }
836 }
837 
838 /// This writer is used between the actual writer and the
839 /// ZlibEncoder and has the job of packaging the compressed
840 /// data into a PNG chunk, based on the image metadata
841 ///
842 /// Currently the way it works is that the specified buffer
843 /// will hold one chunk at the time and bufferize the incoming
844 /// data until `flush` is called or the maximum chunk size
845 /// is reached.
846 ///
847 /// The maximum chunk is the smallest between the selected buffer size
848 /// and `u32::MAX >> 1` (`0x7fffffff` or `2147483647` dec)
849 ///
850 /// When a chunk has to be flushed the length (that is now known)
851 /// and the CRC will be written at the correct locations in the chunk.
852 struct ChunkWriter<'a, W: Write> {
853     writer: ChunkOutput<'a, W>,
854     buffer: Vec<u8>,
855     /// keeps track of where the last byte was written
856     index: usize,
857     curr_chunk: ChunkType,
858 }
859 
860 impl<'a, W: Write> ChunkWriter<'a, W> {
new(writer: ChunkOutput<'a, W>, buf_len: usize) -> ChunkWriter<'a, W>861     fn new(writer: ChunkOutput<'a, W>, buf_len: usize) -> ChunkWriter<'a, W> {
862         // currently buf_len will determine the size of each chunk
863         // the len is capped to the maximum size every chunk can hold
864         // (this wont ever overflow an u32)
865         //
866         // TODO (maybe): find a way to hold two chunks at a time if `usize`
867         //               is 64 bits.
868         const CAP: usize = std::u32::MAX as usize >> 1;
869         let curr_chunk;
870         if writer.sep_def_img || writer.info.frame_control.is_none() || writer.written == 0 {
871             curr_chunk = chunk::IDAT;
872         } else {
873             curr_chunk = chunk::fdAT;
874         }
875         ChunkWriter {
876             writer,
877             buffer: vec![0; CAP.min(buf_len)],
878             index: 0,
879             curr_chunk,
880         }
881     }
882 
883     /// Returns the size of each scanline for the next frame
884     /// paired with the size of the whole frame
885     ///
886     /// This is used by the `StreamWriter` to know when the scanline ends
887     /// so it can filter compress it and also to know when to start
888     /// the next one
next_frame_info(&self) -> (usize, usize)889     fn next_frame_info(&self) -> (usize, usize) {
890         let wrt = self.writer.deref();
891 
892         let width: usize;
893         let height: usize;
894         if let Some(fctl) = wrt.info.frame_control {
895             width = fctl.width as usize;
896             height = fctl.height as usize;
897         } else {
898             width = wrt.info.width as usize;
899             height = wrt.info.height as usize;
900         }
901 
902         let in_len = wrt.info.raw_row_length_from_width(width as u32) - 1;
903         let data_size = in_len * height;
904 
905         (in_len, data_size)
906     }
907 
908     /// NOTE: this bypasses the internal buffer so the flush method should be called before this
909     ///       in the case there is some data left in the buffer when this is called, it will panic
write_header(&mut self) -> Result<()>910     fn write_header(&mut self) -> Result<()> {
911         assert_eq!(self.index, 0, "Called when not flushed");
912         let wrt = self.writer.deref_mut();
913 
914         self.curr_chunk = match wrt.info.frame_control {
915             _ if wrt.sep_def_img => chunk::IDAT,
916             None => chunk::IDAT,
917             Some(ref mut fctl) => {
918                 fctl.encode(&mut wrt.w)?;
919                 fctl.sequence_number += 1;
920                 match wrt.written {
921                     0 => chunk::IDAT,
922                     _ => chunk::fdAT,
923                 }
924             }
925         };
926         Ok(())
927     }
928 
929     /// Set the `FrameControl` for the following frame
930     ///
931     /// It will ignore the `sequence_number` of the parameter
932     /// as it is updated internally.
set_fctl(&mut self, f: FrameControl)933     fn set_fctl(&mut self, f: FrameControl) {
934         if let Some(ref mut fctl) = self.writer.info.frame_control {
935             // ingnore the sequence number
936             *fctl = FrameControl {
937                 sequence_number: fctl.sequence_number,
938                 ..f
939             };
940         } else {
941             panic!("This function must be called on an animated PNG")
942         }
943     }
944 
945     /// Flushes the current chunk
flush_inner(&mut self) -> io::Result<()>946     fn flush_inner(&mut self) -> io::Result<()> {
947         if self.index > 0 {
948             // flush the chunk and reset everything
949             write_chunk(
950                 &mut self.writer.w,
951                 self.curr_chunk,
952                 &self.buffer[..self.index],
953             )?;
954             self.index = 0;
955         }
956         Ok(())
957     }
958 }
959 
960 impl<'a, W: Write> Write for ChunkWriter<'a, W> {
write(&mut self, mut data: &[u8]) -> io::Result<usize>961     fn write(&mut self, mut data: &[u8]) -> io::Result<usize> {
962         if data.is_empty() {
963             return Ok(0);
964         }
965 
966         // index == 0 means a chunk as been flushed out
967         if self.index == 0 {
968             let wrt = self.writer.deref_mut();
969             // ??? maybe use self.curr_chunk == chunk::fdAT ???
970             if !wrt.sep_def_img && wrt.info.frame_control.is_some() && wrt.written > 0 {
971                 let fctl = wrt.info.frame_control.as_mut().unwrap();
972                 self.buffer[0..4].copy_from_slice(&fctl.sequence_number.to_be_bytes());
973                 fctl.sequence_number += 1;
974                 self.index = 4;
975             }
976         }
977 
978         // cap the buffer length to the maximum nuber of bytes that can't still
979         // be added to the current chunk
980         let written = data.len().min(self.buffer.len() - self.index);
981         data = &data[..written];
982 
983         self.buffer[self.index..][..written].copy_from_slice(data);
984         self.index += written;
985 
986         // if the maximum data for this chunk as been reached it needs to be flushed
987         if self.index == self.buffer.len() {
988             self.flush_inner()?;
989         }
990         Ok(written)
991     }
992 
flush(&mut self) -> io::Result<()>993     fn flush(&mut self) -> io::Result<()> {
994         self.flush_inner()
995     }
996 }
997 
998 impl<W: Write> Drop for ChunkWriter<'_, W> {
drop(&mut self)999     fn drop(&mut self) {
1000         let _ = self.flush();
1001     }
1002 }
1003 
1004 // TODO: find a better name
1005 //
1006 /// This enum is used to be allow the `StreamWriter` to keep
1007 /// its inner `ChunkWriter` without wrapping it inside a
1008 /// `ZlibEncoder`. This is used in the case that between the
1009 /// change of state that happens when the last write of a frame
1010 /// is performed an error occurs, which obviously has to be returned.
1011 /// This creates the problem of where to store the writer before
1012 /// exiting the function, and this is where `Wrapper` comes in.
1013 ///
1014 /// Unfortunately the `ZlibWriter` can't be used because on the
1015 /// write following the error, `finish` wuold be called and that
1016 /// would write some data even if 0 bytes where compressed.
1017 ///
1018 /// If the `finish` function fails then there is nothing much to
1019 /// do as the `ChunkWriter` would get lost so the `Unrecoverable`
1020 /// variant is used to signal that.
1021 enum Wrapper<'a, W: Write> {
1022     Chunk(ChunkWriter<'a, W>),
1023     Zlib(ZlibEncoder<ChunkWriter<'a, W>>),
1024     Unrecoverable,
1025     /// This is used in-between, should never be matched
1026     None,
1027 }
1028 
1029 impl<'a, W: Write> Wrapper<'a, W> {
1030     /// Like `Option::take` this returns the `Wrapper` contained
1031     /// in `self` and replaces it with `Wrapper::None`
take(&mut self) -> Wrapper<'a, W>1032     fn take(&mut self) -> Wrapper<'a, W> {
1033         let mut swap = Wrapper::None;
1034         mem::swap(self, &mut swap);
1035         swap
1036     }
1037 }
1038 
1039 /// Streaming PNG writer
1040 ///
1041 /// This may silently fail in the destructor, so it is a good idea to call
1042 /// [`finish`](#method.finish) or [`flush`] before dropping.
1043 ///
1044 /// [`flush`]: https://doc.rust-lang.org/stable/std/io/trait.Write.html#tymethod.flush
1045 pub struct StreamWriter<'a, W: Write> {
1046     /// The option here is needed in order to access the inner `ChunkWriter` in-between
1047     /// each frame, which is needed for writing the fcTL chunks between each frame
1048     writer: Wrapper<'a, W>,
1049     prev_buf: Vec<u8>,
1050     curr_buf: Vec<u8>,
1051     /// Amount of data already written
1052     index: usize,
1053     /// length of the current scanline
1054     line_len: usize,
1055     /// size of the frame (width * height * sample_size)
1056     to_write: usize,
1057     /// Flag used to signal the end of the image
1058     end: bool,
1059 
1060     width: u32,
1061     height: u32,
1062 
1063     bpp: BytesPerPixel,
1064     filter: FilterType,
1065     adaptive_filter: AdaptiveFilterType,
1066     fctl: Option<FrameControl>,
1067     compression: Compression,
1068 }
1069 
1070 impl<'a, W: Write> StreamWriter<'a, W> {
new(writer: ChunkOutput<'a, W>, buf_len: usize) -> Result<StreamWriter<'a, W>>1071     fn new(writer: ChunkOutput<'a, W>, buf_len: usize) -> Result<StreamWriter<'a, W>> {
1072         if writer.max_frames() < writer.written {
1073             return Err(EncodingError::Format(FormatErrorKind::EndReached.into()));
1074         }
1075 
1076         let PartialInfo {
1077             width,
1078             height,
1079             frame_control: fctl,
1080             compression,
1081             ..
1082         } = writer.info;
1083 
1084         let bpp = writer.info.bpp_in_prediction();
1085         let in_len = writer.info.raw_row_length() - 1;
1086         let filter = writer.filter;
1087         let adaptive_filter = writer.adaptive_filter;
1088         let prev_buf = vec![0; in_len];
1089         let curr_buf = vec![0; in_len];
1090 
1091         let mut chunk_writer = ChunkWriter::new(writer, buf_len);
1092         let (line_len, to_write) = chunk_writer.next_frame_info();
1093         chunk_writer.write_header()?;
1094         let zlib = ZlibEncoder::new(chunk_writer, compression.to_options());
1095 
1096         Ok(StreamWriter {
1097             writer: Wrapper::Zlib(zlib),
1098             index: 0,
1099             prev_buf,
1100             curr_buf,
1101             end: false,
1102             bpp,
1103             filter,
1104             width,
1105             height,
1106             adaptive_filter,
1107             line_len,
1108             to_write,
1109             fctl,
1110             compression,
1111         })
1112     }
1113 
1114     /// Set the used filter type for the next frame.
1115     ///
1116     /// The default filter is [`FilterType::Sub`] which provides a basic prediction algorithm for
1117     /// sample values based on the previous. For a potentially better compression ratio, at the
1118     /// cost of more complex processing, try out [`FilterType::Paeth`].
1119     ///
1120     /// [`FilterType::Sub`]: enum.FilterType.html#variant.Sub
1121     /// [`FilterType::Paeth`]: enum.FilterType.html#variant.Paeth
set_filter(&mut self, filter: FilterType)1122     pub fn set_filter(&mut self, filter: FilterType) {
1123         self.filter = filter;
1124     }
1125 
1126     /// Set the adaptive filter type for the next frame.
1127     ///
1128     /// Adaptive filtering attempts to select the best filter for each line
1129     /// based on heuristics which minimize the file size for compression rather
1130     /// than use a single filter for the entire image. The default method is
1131     /// [`AdaptiveFilterType::NonAdaptive`].
1132     ///
1133     /// [`AdaptiveFilterType::NonAdaptive`]: enum.AdaptiveFilterType.html
set_adaptive_filter(&mut self, adaptive_filter: AdaptiveFilterType)1134     pub fn set_adaptive_filter(&mut self, adaptive_filter: AdaptiveFilterType) {
1135         self.adaptive_filter = adaptive_filter;
1136     }
1137 
1138     /// Set the fraction of time the following frames are going to be displayed,
1139     /// in seconds
1140     ///
1141     /// If the denominator is 0, it is to be treated as if it were 100
1142     /// (that is, the numerator then specifies 1/100ths of a second).
1143     /// If the the value of the numerator is 0 the decoder should render the next frame
1144     /// as quickly as possible, though viewers may impose a reasonable lower bound.
1145     ///
1146     /// This method will return an error if the image is not animated.
set_frame_delay(&mut self, numerator: u16, denominator: u16) -> Result<()>1147     pub fn set_frame_delay(&mut self, numerator: u16, denominator: u16) -> Result<()> {
1148         if let Some(ref mut fctl) = self.fctl {
1149             fctl.delay_den = denominator;
1150             fctl.delay_num = numerator;
1151             Ok(())
1152         } else {
1153             Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
1154         }
1155     }
1156 
1157     /// Set the dimension of the following frames.
1158     ///
1159     /// This function will return an error when:
1160     /// - The image is not an animated;
1161     ///
1162     /// - The selected dimension, considering also the current frame position,
1163     ///   goes outside the image boudries;
1164     ///
1165     /// - One or both the width and height are 0;
1166     ///
set_frame_dimension(&mut self, width: u32, height: u32) -> Result<()>1167     pub fn set_frame_dimension(&mut self, width: u32, height: u32) -> Result<()> {
1168         if let Some(ref mut fctl) = self.fctl {
1169             if Some(width) > self.width.checked_sub(fctl.x_offset)
1170                 || Some(height) > self.height.checked_sub(fctl.y_offset)
1171             {
1172                 return Err(EncodingError::Format(FormatErrorKind::OutOfBounds.into()));
1173             } else if width == 0 {
1174                 return Err(EncodingError::Format(FormatErrorKind::ZeroWidth.into()));
1175             } else if height == 0 {
1176                 return Err(EncodingError::Format(FormatErrorKind::ZeroHeight.into()));
1177             }
1178             fctl.width = width;
1179             fctl.height = height;
1180             Ok(())
1181         } else {
1182             Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
1183         }
1184     }
1185 
1186     /// Set the position of the following frames.
1187     ///
1188     /// An error will be returned if:
1189     /// - The image is not animated;
1190     ///
1191     /// - The selected position, considering also the current frame dimension,
1192     ///   goes outside the image boudries;
1193     ///
set_frame_position(&mut self, x: u32, y: u32) -> Result<()>1194     pub fn set_frame_position(&mut self, x: u32, y: u32) -> Result<()> {
1195         if let Some(ref mut fctl) = self.fctl {
1196             if Some(x) > self.width.checked_sub(fctl.width)
1197                 || Some(y) > self.height.checked_sub(fctl.height)
1198             {
1199                 return Err(EncodingError::Format(FormatErrorKind::OutOfBounds.into()));
1200             }
1201             fctl.x_offset = x;
1202             fctl.y_offset = y;
1203             Ok(())
1204         } else {
1205             Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
1206         }
1207     }
1208 
1209     /// Set the frame dimension to occupy all the image, starting from
1210     /// the current position.
1211     ///
1212     /// To reset the frame to the full image size [`reset_frame_position`]
1213     /// should be called first.
1214     ///
1215     /// This method will return an error if the image is not animated.
1216     ///
1217     /// [`reset_frame_position`]: struct.Writer.html#method.reset_frame_position
reset_frame_dimension(&mut self) -> Result<()>1218     pub fn reset_frame_dimension(&mut self) -> Result<()> {
1219         if let Some(ref mut fctl) = self.fctl {
1220             fctl.width = self.width - fctl.x_offset;
1221             fctl.height = self.height - fctl.y_offset;
1222             Ok(())
1223         } else {
1224             Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
1225         }
1226     }
1227 
1228     /// Set the frame position to (0, 0).
1229     ///
1230     /// Equivalent to calling [`set_frame_position(0, 0)`].
1231     ///
1232     /// This method will return an error if the image is not animated.
1233     ///
1234     /// [`set_frame_position(0, 0)`]: struct.Writer.html#method.set_frame_position
reset_frame_position(&mut self) -> Result<()>1235     pub fn reset_frame_position(&mut self) -> Result<()> {
1236         if let Some(ref mut fctl) = self.fctl {
1237             fctl.x_offset = 0;
1238             fctl.y_offset = 0;
1239             Ok(())
1240         } else {
1241             Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
1242         }
1243     }
1244 
1245     /// Set the blend operation for the following frames.
1246     ///
1247     /// The blend operation specifies whether the frame is to be alpha blended
1248     /// into the current output buffer content, or whether it should completely
1249     /// replace its region in the output buffer.
1250     ///
1251     /// See the [`BlendOp`] documentaion for the possible values and their effects.
1252     ///
1253     /// *Note that for the first frame the two blend modes are functionally
1254     /// equivalent due to the clearing of the output buffer at the beginning
1255     /// of each play.*
1256     ///
1257     /// This method will return an error if the image is not animated.
1258     ///
1259     /// [`BlendOP`]: enum.BlendOp.html
set_blend_op(&mut self, op: BlendOp) -> Result<()>1260     pub fn set_blend_op(&mut self, op: BlendOp) -> Result<()> {
1261         if let Some(ref mut fctl) = self.fctl {
1262             fctl.blend_op = op;
1263             Ok(())
1264         } else {
1265             Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
1266         }
1267     }
1268 
1269     /// Set the dispose operation for the following frames.
1270     ///
1271     /// The dispose operation specifies how the output buffer should be changed
1272     /// at the end of the delay (before rendering the next frame)
1273     ///
1274     /// See the [`DisposeOp`] documentaion for the possible values and their effects.
1275     ///
1276     /// *Note that if the first frame uses [`DisposeOp::Previous`]
1277     /// it will be treated as [`DisposeOp::Background`].*
1278     ///
1279     /// This method will return an error if the image is not animated.
1280     ///
1281     /// [`DisposeOp`]: ../common/enum.BlendOp.html
1282     /// [`DisposeOp::Previous`]: ../common/enum.BlendOp.html#variant.Previous
1283     /// [`DisposeOp::Background`]: ../common/enum.BlendOp.html#variant.Background
set_dispose_op(&mut self, op: DisposeOp) -> Result<()>1284     pub fn set_dispose_op(&mut self, op: DisposeOp) -> Result<()> {
1285         if let Some(ref mut fctl) = self.fctl {
1286             fctl.dispose_op = op;
1287             Ok(())
1288         } else {
1289             Err(EncodingError::Format(FormatErrorKind::NotAnimated.into()))
1290         }
1291     }
1292 
finish(mut self) -> Result<()>1293     pub fn finish(mut self) -> Result<()> {
1294         if !self.end {
1295             let err = FormatErrorKind::MissingFrames.into();
1296             return Err(EncodingError::Format(err));
1297         } else if self.to_write > 0 {
1298             let err = FormatErrorKind::MissingData(self.to_write).into();
1299             return Err(EncodingError::Format(err));
1300         }
1301         // TODO: call `writer.finish` somehow?
1302         self.flush()?;
1303         Ok(())
1304     }
1305 
1306     /// Flushes the buffered chunk, checks if it was the last frame,
1307     /// writes the next frame header and gets the next frame scanline size
1308     /// and image size.
new_frame(&mut self) -> Result<()>1309     fn new_frame(&mut self) -> Result<()> {
1310         let wrt = match &mut self.writer {
1311             Wrapper::Chunk(wrt) => wrt,
1312             _ => unreachable!(),
1313         };
1314         wrt.flush()?;
1315         if let Some(fctl) = self.fctl {
1316             wrt.set_fctl(fctl);
1317         }
1318         let (scansize, size) = wrt.next_frame_info();
1319         self.line_len = scansize;
1320         self.to_write = size;
1321         wrt.writer.written += 1;
1322         wrt.write_header()?;
1323         self.end = wrt.writer.written + 1 == wrt.writer.max_frames();
1324 
1325         // now it can be taken because the next statements cannot cause any errors
1326         let wrt = match self.writer.take() {
1327             Wrapper::Chunk(wrt) => wrt,
1328             _ => unreachable!(),
1329         };
1330         self.writer = Wrapper::Zlib(ZlibEncoder::new(wrt, self.compression.to_options()));
1331         Ok(())
1332     }
1333 }
1334 
1335 impl<'a, W: Write> Write for StreamWriter<'a, W> {
write(&mut self, mut data: &[u8]) -> io::Result<usize>1336     fn write(&mut self, mut data: &[u8]) -> io::Result<usize> {
1337         if let Wrapper::Unrecoverable = self.writer {
1338             let err = FormatErrorKind::Unrecoverable.into();
1339             return Err(EncodingError::Format(err).into());
1340         }
1341 
1342         if data.is_empty() {
1343             return Ok(0);
1344         }
1345 
1346         if self.to_write == 0 {
1347             if self.end {
1348                 let err = FormatErrorKind::EndReached.into();
1349                 return Err(EncodingError::Format(err).into());
1350             }
1351             match self.writer.take() {
1352                 Wrapper::Zlib(wrt) => match wrt.finish() {
1353                     Ok(chunk) => self.writer = Wrapper::Chunk(chunk),
1354                     Err(err) => {
1355                         self.writer = Wrapper::Unrecoverable;
1356                         return Err(err);
1357                     }
1358                 },
1359                 chunk @ Wrapper::Chunk(_) => self.writer = chunk,
1360                 Wrapper::None | Wrapper::Unrecoverable => unreachable!(),
1361             };
1362             self.new_frame()?;
1363         }
1364         let written = data.read(&mut self.curr_buf[..self.line_len][self.index..])?;
1365         self.index += written;
1366         self.to_write -= written;
1367 
1368         if self.index == self.line_len {
1369             let filter_type = filter(
1370                 self.filter,
1371                 self.adaptive_filter,
1372                 self.bpp,
1373                 &self.prev_buf,
1374                 &mut self.curr_buf,
1375             );
1376             // This can't fail as the other variant is used only to allow the zlib encoder to finish
1377             let wrt = match &mut self.writer {
1378                 Wrapper::Zlib(wrt) => wrt,
1379                 _ => unreachable!(),
1380             };
1381             wrt.write_all(&[filter_type as u8])?;
1382             wrt.write_all(&self.curr_buf)?;
1383             mem::swap(&mut self.prev_buf, &mut self.curr_buf);
1384             self.index = 0;
1385         }
1386         Ok(written)
1387     }
1388 
flush(&mut self) -> io::Result<()>1389     fn flush(&mut self) -> io::Result<()> {
1390         match &mut self.writer {
1391             Wrapper::Zlib(wrt) => wrt.flush()?,
1392             _ => unreachable!(),
1393         }
1394         if self.index > 0 {
1395             let err = FormatErrorKind::WrittenTooMuch(self.index).into();
1396             return Err(EncodingError::Format(err).into());
1397         }
1398         Ok(())
1399     }
1400 }
1401 
1402 impl<W: Write> Drop for StreamWriter<'_, W> {
drop(&mut self)1403     fn drop(&mut self) {
1404         let _ = self.flush();
1405     }
1406 }
1407 
1408 #[cfg(test)]
1409 mod tests {
1410     use super::*;
1411     use crate::Decoder;
1412 
1413     use rand::{thread_rng, Rng};
1414     use std::fs::File;
1415     use std::io::Write;
1416     use std::{cmp, io};
1417 
1418     #[test]
roundtrip()1419     fn roundtrip() {
1420         // More loops = more random testing, but also more test wait time
1421         for _ in 0..10 {
1422             for path in glob::glob("tests/pngsuite/*.png")
1423                 .unwrap()
1424                 .map(|r| r.unwrap())
1425             {
1426                 if path.file_name().unwrap().to_str().unwrap().starts_with('x') {
1427                     // x* files are expected to fail to decode
1428                     continue;
1429                 }
1430                 eprintln!("{}", path.display());
1431                 // Decode image
1432                 let decoder = Decoder::new(File::open(path).unwrap());
1433                 let mut reader = decoder.read_info().unwrap();
1434                 let mut buf = vec![0; reader.output_buffer_size()];
1435                 let info = reader.next_frame(&mut buf).unwrap();
1436                 // Encode decoded image
1437                 let mut out = Vec::new();
1438                 {
1439                     let mut wrapper = RandomChunkWriter {
1440                         rng: thread_rng(),
1441                         w: &mut out,
1442                     };
1443 
1444                     let mut encoder = Encoder::new(&mut wrapper, info.width, info.height);
1445                     encoder.set_color(info.color_type);
1446                     encoder.set_depth(info.bit_depth);
1447                     if let Some(palette) = &reader.info().palette {
1448                         encoder.set_palette(palette.clone());
1449                     }
1450                     let mut encoder = encoder.write_header().unwrap();
1451                     encoder.write_image_data(&buf).unwrap();
1452                 }
1453                 // Decode encoded decoded image
1454                 let decoder = Decoder::new(&*out);
1455                 let mut reader = decoder.read_info().unwrap();
1456                 let mut buf2 = vec![0; reader.output_buffer_size()];
1457                 reader.next_frame(&mut buf2).unwrap();
1458                 // check if the encoded image is ok:
1459                 assert_eq!(buf, buf2);
1460             }
1461         }
1462     }
1463 
1464     #[test]
roundtrip_stream()1465     fn roundtrip_stream() {
1466         // More loops = more random testing, but also more test wait time
1467         for _ in 0..10 {
1468             for path in glob::glob("tests/pngsuite/*.png")
1469                 .unwrap()
1470                 .map(|r| r.unwrap())
1471             {
1472                 if path.file_name().unwrap().to_str().unwrap().starts_with('x') {
1473                     // x* files are expected to fail to decode
1474                     continue;
1475                 }
1476                 // Decode image
1477                 let decoder = Decoder::new(File::open(path).unwrap());
1478                 let mut reader = decoder.read_info().unwrap();
1479                 let mut buf = vec![0; reader.output_buffer_size()];
1480                 let info = reader.next_frame(&mut buf).unwrap();
1481                 // Encode decoded image
1482                 let mut out = Vec::new();
1483                 {
1484                     let mut wrapper = RandomChunkWriter {
1485                         rng: thread_rng(),
1486                         w: &mut out,
1487                     };
1488 
1489                     let mut encoder = Encoder::new(&mut wrapper, info.width, info.height);
1490                     encoder.set_color(info.color_type);
1491                     encoder.set_depth(info.bit_depth);
1492                     if let Some(palette) = &reader.info().palette {
1493                         encoder.set_palette(palette.clone());
1494                     }
1495                     let mut encoder = encoder.write_header().unwrap();
1496                     let mut stream_writer = encoder.stream_writer().unwrap();
1497 
1498                     let mut outer_wrapper = RandomChunkWriter {
1499                         rng: thread_rng(),
1500                         w: &mut stream_writer,
1501                     };
1502 
1503                     outer_wrapper.write_all(&buf).unwrap();
1504                 }
1505                 // Decode encoded decoded image
1506                 let decoder = Decoder::new(&*out);
1507                 let mut reader = decoder.read_info().unwrap();
1508                 let mut buf2 = vec![0; reader.output_buffer_size()];
1509                 reader.next_frame(&mut buf2).unwrap();
1510                 // check if the encoded image is ok:
1511                 assert_eq!(buf, buf2);
1512             }
1513         }
1514     }
1515 
1516     #[test]
image_palette() -> Result<()>1517     fn image_palette() -> Result<()> {
1518         for &bit_depth in &[1u8, 2, 4, 8] {
1519             // Do a reference decoding, choose a fitting palette image from pngsuite
1520             let path = format!("tests/pngsuite/basn3p0{}.png", bit_depth);
1521             let decoder = Decoder::new(File::open(&path).unwrap());
1522             let mut reader = decoder.read_info().unwrap();
1523 
1524             let mut decoded_pixels = vec![0; reader.output_buffer_size()];
1525             let info = reader.info();
1526             assert_eq!(
1527                 info.width as usize * info.height as usize * usize::from(bit_depth),
1528                 decoded_pixels.len() * 8
1529             );
1530             let info = reader.next_frame(&mut decoded_pixels).unwrap();
1531             let indexed_data = decoded_pixels;
1532 
1533             let palette = reader.info().palette.as_ref().unwrap();
1534             let mut out = Vec::new();
1535             {
1536                 let mut encoder = Encoder::new(&mut out, info.width, info.height);
1537                 encoder.set_depth(BitDepth::from_u8(bit_depth).unwrap());
1538                 encoder.set_color(ColorType::Indexed);
1539                 encoder.set_palette(palette.as_ref());
1540 
1541                 let mut writer = encoder.write_header().unwrap();
1542                 writer.write_image_data(&indexed_data).unwrap();
1543             }
1544 
1545             // Decode re-encoded image
1546             let decoder = Decoder::new(&*out);
1547             let mut reader = decoder.read_info().unwrap();
1548             let mut redecoded = vec![0; reader.output_buffer_size()];
1549             reader.next_frame(&mut redecoded).unwrap();
1550             // check if the encoded image is ok:
1551             assert_eq!(indexed_data, redecoded);
1552         }
1553         Ok(())
1554     }
1555 
1556     #[test]
expect_error_on_wrong_image_len() -> Result<()>1557     fn expect_error_on_wrong_image_len() -> Result<()> {
1558         use std::io::Cursor;
1559 
1560         let width = 10;
1561         let height = 10;
1562 
1563         let output = vec![0u8; 1024];
1564         let writer = Cursor::new(output);
1565         let mut encoder = Encoder::new(writer, width as u32, height as u32);
1566         encoder.set_depth(BitDepth::Eight);
1567         encoder.set_color(ColorType::Rgb);
1568         let mut png_writer = encoder.write_header()?;
1569 
1570         let correct_image_size = width * height * 3;
1571         let image = vec![0u8; correct_image_size + 1];
1572         let result = png_writer.write_image_data(image.as_ref());
1573         assert!(result.is_err());
1574 
1575         Ok(())
1576     }
1577 
1578     #[test]
expect_error_on_empty_image() -> Result<()>1579     fn expect_error_on_empty_image() -> Result<()> {
1580         use std::io::Cursor;
1581 
1582         let output = vec![0u8; 1024];
1583         let mut writer = Cursor::new(output);
1584 
1585         let encoder = Encoder::new(&mut writer, 0, 0);
1586         assert!(encoder.write_header().is_err());
1587 
1588         let encoder = Encoder::new(&mut writer, 100, 0);
1589         assert!(encoder.write_header().is_err());
1590 
1591         let encoder = Encoder::new(&mut writer, 0, 100);
1592         assert!(encoder.write_header().is_err());
1593 
1594         Ok(())
1595     }
1596 
1597     #[test]
expect_error_on_invalid_bit_depth_color_type_combination() -> Result<()>1598     fn expect_error_on_invalid_bit_depth_color_type_combination() -> Result<()> {
1599         use std::io::Cursor;
1600 
1601         let output = vec![0u8; 1024];
1602         let mut writer = Cursor::new(output);
1603 
1604         let mut encoder = Encoder::new(&mut writer, 1, 1);
1605         encoder.set_depth(BitDepth::One);
1606         encoder.set_color(ColorType::Rgb);
1607         assert!(encoder.write_header().is_err());
1608 
1609         let mut encoder = Encoder::new(&mut writer, 1, 1);
1610         encoder.set_depth(BitDepth::One);
1611         encoder.set_color(ColorType::GrayscaleAlpha);
1612         assert!(encoder.write_header().is_err());
1613 
1614         let mut encoder = Encoder::new(&mut writer, 1, 1);
1615         encoder.set_depth(BitDepth::One);
1616         encoder.set_color(ColorType::Rgba);
1617         assert!(encoder.write_header().is_err());
1618 
1619         let mut encoder = Encoder::new(&mut writer, 1, 1);
1620         encoder.set_depth(BitDepth::Two);
1621         encoder.set_color(ColorType::Rgb);
1622         assert!(encoder.write_header().is_err());
1623 
1624         let mut encoder = Encoder::new(&mut writer, 1, 1);
1625         encoder.set_depth(BitDepth::Two);
1626         encoder.set_color(ColorType::GrayscaleAlpha);
1627         assert!(encoder.write_header().is_err());
1628 
1629         let mut encoder = Encoder::new(&mut writer, 1, 1);
1630         encoder.set_depth(BitDepth::Two);
1631         encoder.set_color(ColorType::Rgba);
1632         assert!(encoder.write_header().is_err());
1633 
1634         let mut encoder = Encoder::new(&mut writer, 1, 1);
1635         encoder.set_depth(BitDepth::Four);
1636         encoder.set_color(ColorType::Rgb);
1637         assert!(encoder.write_header().is_err());
1638 
1639         let mut encoder = Encoder::new(&mut writer, 1, 1);
1640         encoder.set_depth(BitDepth::Four);
1641         encoder.set_color(ColorType::GrayscaleAlpha);
1642         assert!(encoder.write_header().is_err());
1643 
1644         let mut encoder = Encoder::new(&mut writer, 1, 1);
1645         encoder.set_depth(BitDepth::Four);
1646         encoder.set_color(ColorType::Rgba);
1647         assert!(encoder.write_header().is_err());
1648 
1649         let mut encoder = Encoder::new(&mut writer, 1, 1);
1650         encoder.set_depth(BitDepth::Sixteen);
1651         encoder.set_color(ColorType::Indexed);
1652         assert!(encoder.write_header().is_err());
1653 
1654         Ok(())
1655     }
1656 
1657     #[test]
can_write_header_with_valid_bit_depth_color_type_combination() -> Result<()>1658     fn can_write_header_with_valid_bit_depth_color_type_combination() -> Result<()> {
1659         use std::io::Cursor;
1660 
1661         let output = vec![0u8; 1024];
1662         let mut writer = Cursor::new(output);
1663 
1664         let mut encoder = Encoder::new(&mut writer, 1, 1);
1665         encoder.set_depth(BitDepth::One);
1666         encoder.set_color(ColorType::Grayscale);
1667         assert!(encoder.write_header().is_ok());
1668 
1669         let mut encoder = Encoder::new(&mut writer, 1, 1);
1670         encoder.set_depth(BitDepth::One);
1671         encoder.set_color(ColorType::Indexed);
1672         assert!(encoder.write_header().is_ok());
1673 
1674         let mut encoder = Encoder::new(&mut writer, 1, 1);
1675         encoder.set_depth(BitDepth::Two);
1676         encoder.set_color(ColorType::Grayscale);
1677         assert!(encoder.write_header().is_ok());
1678 
1679         let mut encoder = Encoder::new(&mut writer, 1, 1);
1680         encoder.set_depth(BitDepth::Two);
1681         encoder.set_color(ColorType::Indexed);
1682         assert!(encoder.write_header().is_ok());
1683 
1684         let mut encoder = Encoder::new(&mut writer, 1, 1);
1685         encoder.set_depth(BitDepth::Four);
1686         encoder.set_color(ColorType::Grayscale);
1687         assert!(encoder.write_header().is_ok());
1688 
1689         let mut encoder = Encoder::new(&mut writer, 1, 1);
1690         encoder.set_depth(BitDepth::Four);
1691         encoder.set_color(ColorType::Indexed);
1692         assert!(encoder.write_header().is_ok());
1693 
1694         let mut encoder = Encoder::new(&mut writer, 1, 1);
1695         encoder.set_depth(BitDepth::Eight);
1696         encoder.set_color(ColorType::Grayscale);
1697         assert!(encoder.write_header().is_ok());
1698 
1699         let mut encoder = Encoder::new(&mut writer, 1, 1);
1700         encoder.set_depth(BitDepth::Eight);
1701         encoder.set_color(ColorType::Rgb);
1702         assert!(encoder.write_header().is_ok());
1703 
1704         let mut encoder = Encoder::new(&mut writer, 1, 1);
1705         encoder.set_depth(BitDepth::Eight);
1706         encoder.set_color(ColorType::Indexed);
1707         assert!(encoder.write_header().is_ok());
1708 
1709         let mut encoder = Encoder::new(&mut writer, 1, 1);
1710         encoder.set_depth(BitDepth::Eight);
1711         encoder.set_color(ColorType::GrayscaleAlpha);
1712         assert!(encoder.write_header().is_ok());
1713 
1714         let mut encoder = Encoder::new(&mut writer, 1, 1);
1715         encoder.set_depth(BitDepth::Eight);
1716         encoder.set_color(ColorType::Rgba);
1717         assert!(encoder.write_header().is_ok());
1718 
1719         let mut encoder = Encoder::new(&mut writer, 1, 1);
1720         encoder.set_depth(BitDepth::Sixteen);
1721         encoder.set_color(ColorType::Grayscale);
1722         assert!(encoder.write_header().is_ok());
1723 
1724         let mut encoder = Encoder::new(&mut writer, 1, 1);
1725         encoder.set_depth(BitDepth::Sixteen);
1726         encoder.set_color(ColorType::Rgb);
1727         assert!(encoder.write_header().is_ok());
1728 
1729         let mut encoder = Encoder::new(&mut writer, 1, 1);
1730         encoder.set_depth(BitDepth::Sixteen);
1731         encoder.set_color(ColorType::GrayscaleAlpha);
1732         assert!(encoder.write_header().is_ok());
1733 
1734         let mut encoder = Encoder::new(&mut writer, 1, 1);
1735         encoder.set_depth(BitDepth::Sixteen);
1736         encoder.set_color(ColorType::Rgba);
1737         assert!(encoder.write_header().is_ok());
1738 
1739         Ok(())
1740     }
1741 
1742     #[test]
all_filters_roundtrip() -> io::Result<()>1743     fn all_filters_roundtrip() -> io::Result<()> {
1744         let pixel: Vec<_> = (0..48).collect();
1745 
1746         let roundtrip = |filter: FilterType| -> io::Result<()> {
1747             let mut buffer = vec![];
1748             let mut encoder = Encoder::new(&mut buffer, 4, 4);
1749             encoder.set_depth(BitDepth::Eight);
1750             encoder.set_color(ColorType::Rgb);
1751             encoder.set_filter(filter);
1752             encoder.write_header()?.write_image_data(&pixel)?;
1753 
1754             let decoder = crate::Decoder::new(io::Cursor::new(buffer));
1755             let mut reader = decoder.read_info()?;
1756             let info = reader.info();
1757             assert_eq!(info.width, 4);
1758             assert_eq!(info.height, 4);
1759             let mut dest = vec![0; pixel.len()];
1760             reader.next_frame(&mut dest)?;
1761             assert_eq!(dest, pixel, "Deviation with filter type {:?}", filter);
1762 
1763             Ok(())
1764         };
1765 
1766         roundtrip(FilterType::NoFilter)?;
1767         roundtrip(FilterType::Sub)?;
1768         roundtrip(FilterType::Up)?;
1769         roundtrip(FilterType::Avg)?;
1770         roundtrip(FilterType::Paeth)?;
1771 
1772         Ok(())
1773     }
1774 
1775     #[test]
some_gamma_roundtrip() -> io::Result<()>1776     fn some_gamma_roundtrip() -> io::Result<()> {
1777         let pixel: Vec<_> = (0..48).collect();
1778 
1779         let roundtrip = |gamma: Option<ScaledFloat>| -> io::Result<()> {
1780             let mut buffer = vec![];
1781             let mut encoder = Encoder::new(&mut buffer, 4, 4);
1782             encoder.set_depth(BitDepth::Eight);
1783             encoder.set_color(ColorType::Rgb);
1784             encoder.set_filter(FilterType::Avg);
1785             if let Some(gamma) = gamma {
1786                 encoder.set_source_gamma(gamma);
1787             }
1788             encoder.write_header()?.write_image_data(&pixel)?;
1789 
1790             let decoder = crate::Decoder::new(io::Cursor::new(buffer));
1791             let mut reader = decoder.read_info()?;
1792             assert_eq!(
1793                 reader.info().source_gamma,
1794                 gamma,
1795                 "Deviation with gamma {:?}",
1796                 gamma
1797             );
1798             let mut dest = vec![0; pixel.len()];
1799             let info = reader.next_frame(&mut dest)?;
1800             assert_eq!(info.width, 4);
1801             assert_eq!(info.height, 4);
1802 
1803             Ok(())
1804         };
1805 
1806         roundtrip(None)?;
1807         roundtrip(Some(ScaledFloat::new(0.35)))?;
1808         roundtrip(Some(ScaledFloat::new(0.45)))?;
1809         roundtrip(Some(ScaledFloat::new(0.55)))?;
1810         roundtrip(Some(ScaledFloat::new(0.7)))?;
1811         roundtrip(Some(ScaledFloat::new(1.0)))?;
1812         roundtrip(Some(ScaledFloat::new(2.5)))?;
1813 
1814         Ok(())
1815     }
1816 
1817     /// A Writer that only writes a few bytes at a time
1818     struct RandomChunkWriter<R: Rng, W: Write> {
1819         rng: R,
1820         w: W,
1821     }
1822 
1823     impl<R: Rng, W: Write> Write for RandomChunkWriter<R, W> {
write(&mut self, buf: &[u8]) -> io::Result<usize>1824         fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1825             // choose a random length to write
1826             let len = cmp::min(self.rng.gen_range(1, 50), buf.len());
1827 
1828             self.w.write(&buf[0..len])
1829         }
1830 
flush(&mut self) -> io::Result<()>1831         fn flush(&mut self) -> io::Result<()> {
1832             self.w.flush()
1833         }
1834     }
1835 }
1836 
1837 /// Mod to encapsulate the converters depending on the `deflate` crate.
1838 ///
1839 /// Since this only contains trait impls, there is no need to make this public, they are simply
1840 /// available when the mod is compiled as well.
1841 impl crate::common::Compression {
to_options(self) -> deflate::CompressionOptions1842     fn to_options(self) -> deflate::CompressionOptions {
1843         match self {
1844             Compression::Default => deflate::CompressionOptions::default(),
1845             Compression::Fast => deflate::CompressionOptions::fast(),
1846             Compression::Best => deflate::CompressionOptions::high(),
1847             Compression::Huffman => deflate::CompressionOptions::huffman_only(),
1848             Compression::Rle => deflate::CompressionOptions::rle(),
1849         }
1850     }
1851 }
1852