1 //! Decoding and Encoding of PNG Images
2 //!
3 //! PNG (Portable Network Graphics) is an image format that supports lossless compression.
4 //!
5 //! # Related Links
6 //! * <http://www.w3.org/TR/PNG/> - The PNG Specification
7 //!
8 
9 use std::convert::TryFrom;
10 use std::io::{self, Read, Write};
11 
12 use num_rational::Ratio;
13 use png::{BlendOp, DisposeOp};
14 
15 use crate::{DynamicImage, GenericImage, ImageBuffer, Luma, LumaA, RgbaImage, Rgb, Rgba};
16 use crate::animation::{Delay, Frame, Frames};
17 use crate::color::{Blend, ColorType, ExtendedColorType};
18 use crate::error::{
19     DecodingError, ImageError, ImageResult, LimitError, LimitErrorKind, ParameterError, ParameterErrorKind, UnsupportedError, UnsupportedErrorKind
20 };
21 use crate::image::{AnimationDecoder, ImageDecoder, ImageEncoder, ImageFormat};
22 
23 /// Png Reader
24 ///
25 /// This reader will try to read the png one row at a time,
26 /// however for interlaced png files this is not possible and
27 /// these are therefore read at once.
28 pub struct PngReader<R: Read> {
29     reader: png::Reader<R>,
30     buffer: Vec<u8>,
31     index: usize,
32 }
33 
34 /// PNG Reader
35 ///
36 /// An alias of [`PngReader`].
37 ///
38 /// TODO: remove
39 ///
40 /// [`PngReader`]: struct.PngReader.html
41 #[allow(dead_code)]
42 #[deprecated(note = "Use `PngReader` instead")]
43 pub type PNGReader<R> = PngReader<R>;
44 
45 impl<R: Read> PngReader<R> {
new(mut reader: png::Reader<R>) -> ImageResult<PngReader<R>>46     fn new(mut reader: png::Reader<R>) -> ImageResult<PngReader<R>> {
47         let len = reader.output_buffer_size();
48         // Since interlaced images do not come in
49         // scanline order it is almost impossible to
50         // read them in a streaming fashion, however
51         // this shouldn't be a too big of a problem
52         // as most interlaced images should fit in memory.
53         let buffer = if reader.info().interlaced {
54             let mut buffer = vec![0; len];
55             reader.next_frame(&mut buffer).map_err(ImageError::from_png)?;
56             buffer
57         } else {
58             Vec::new()
59         };
60 
61         Ok(PngReader {
62             reader,
63             buffer,
64             index: 0,
65         })
66     }
67 }
68 
69 impl<R: Read> Read for PngReader<R> {
read(&mut self, mut buf: &mut [u8]) -> io::Result<usize>70     fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {
71         // io::Write::write for slice cannot fail
72         let readed = buf.write(&self.buffer[self.index..]).unwrap();
73 
74         let mut bytes = readed;
75         self.index += readed;
76 
77         while self.index >= self.buffer.len() {
78             match self.reader.next_row()? {
79                 Some(row) => {
80                     // Faster to copy directly to external buffer
81                     let readed  = buf.write(row).unwrap();
82                     bytes += readed;
83 
84                     self.buffer = (&row[readed..]).to_owned();
85                     self.index = 0;
86                 }
87                 None => return Ok(bytes)
88             }
89         }
90 
91         Ok(bytes)
92     }
93 
read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize>94     fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
95         let mut bytes = self.buffer.len();
96         if buf.is_empty() {
97             std::mem::swap(&mut self.buffer, buf);
98         } else {
99             buf.extend_from_slice(&self.buffer);
100             self.buffer.clear();
101         }
102 
103         self.index = 0;
104 
105         while let Some(row) = self.reader.next_row()? {
106             buf.extend_from_slice(row);
107             bytes += row.len();
108         }
109 
110         Ok(bytes)
111     }
112 }
113 
114 /// PNG decoder
115 pub struct PngDecoder<R: Read> {
116     color_type: ColorType,
117     reader: png::Reader<R>,
118 }
119 
120 impl<R: Read> PngDecoder<R> {
121     /// Creates a new decoder that decodes from the stream ```r```
new(r: R) -> ImageResult<PngDecoder<R>>122     pub fn new(r: R) -> ImageResult<PngDecoder<R>> {
123         let limits = png::Limits {
124             bytes: usize::max_value(),
125         };
126         let mut decoder = png::Decoder::new_with_limits(r, limits);
127         // By default the PNG decoder will scale 16 bpc to 8 bpc, so custom
128         // transformations must be set. EXPAND preserves the default behavior
129         // expanding bpc < 8 to 8 bpc.
130         decoder.set_transformations(png::Transformations::EXPAND);
131         let (_, mut reader) = decoder.read_info().map_err(ImageError::from_png)?;
132         let (color_type, bits) = reader.output_color_type();
133         let color_type = match (color_type, bits) {
134             (png::ColorType::Grayscale, png::BitDepth::Eight) => ColorType::L8,
135             (png::ColorType::Grayscale, png::BitDepth::Sixteen) => ColorType::L16,
136             (png::ColorType::GrayscaleAlpha, png::BitDepth::Eight) => ColorType::La8,
137             (png::ColorType::GrayscaleAlpha, png::BitDepth::Sixteen) => ColorType::La16,
138             (png::ColorType::RGB, png::BitDepth::Eight) => ColorType::Rgb8,
139             (png::ColorType::RGB, png::BitDepth::Sixteen) => ColorType::Rgb16,
140             (png::ColorType::RGBA, png::BitDepth::Eight) => ColorType::Rgba8,
141             (png::ColorType::RGBA, png::BitDepth::Sixteen) => ColorType::Rgba16,
142 
143             (png::ColorType::Grayscale, png::BitDepth::One) =>
144                 return Err(unsupported_color(ExtendedColorType::L1)),
145             (png::ColorType::GrayscaleAlpha, png::BitDepth::One) =>
146                 return Err(unsupported_color(ExtendedColorType::La1)),
147             (png::ColorType::RGB, png::BitDepth::One) =>
148                 return Err(unsupported_color(ExtendedColorType::Rgb1)),
149             (png::ColorType::RGBA, png::BitDepth::One) =>
150                 return Err(unsupported_color(ExtendedColorType::Rgba1)),
151 
152             (png::ColorType::Grayscale, png::BitDepth::Two) =>
153                 return Err(unsupported_color(ExtendedColorType::L2)),
154             (png::ColorType::GrayscaleAlpha, png::BitDepth::Two) =>
155                 return Err(unsupported_color(ExtendedColorType::La2)),
156             (png::ColorType::RGB, png::BitDepth::Two) =>
157                 return Err(unsupported_color(ExtendedColorType::Rgb2)),
158             (png::ColorType::RGBA, png::BitDepth::Two) =>
159                 return Err(unsupported_color(ExtendedColorType::Rgba2)),
160 
161             (png::ColorType::Grayscale, png::BitDepth::Four) =>
162                 return Err(unsupported_color(ExtendedColorType::L4)),
163             (png::ColorType::GrayscaleAlpha, png::BitDepth::Four) =>
164                 return Err(unsupported_color(ExtendedColorType::La4)),
165             (png::ColorType::RGB, png::BitDepth::Four) =>
166                 return Err(unsupported_color(ExtendedColorType::Rgb4)),
167             (png::ColorType::RGBA, png::BitDepth::Four) =>
168                 return Err(unsupported_color(ExtendedColorType::Rgba4)),
169 
170             (png::ColorType::Indexed, bits) =>
171                 return Err(unsupported_color(ExtendedColorType::Unknown(bits as u8))),
172         };
173 
174         Ok(PngDecoder { color_type, reader })
175     }
176 
177     /// Turn this into an iterator over the animation frames.
178     ///
179     /// Reading the complete animation requires more memory than reading the data from the IDAT
180     /// frame–multiple frame buffers need to be reserved at the same time. We further do not
181     /// support compositing 16-bit colors. In any case this would be lossy as the interface of
182     /// animation decoders does not support 16-bit colors.
183     ///
184     /// If something is not supported or a limit is violated then the decoding step that requires
185     /// them will fail and an error will be returned instead of the frame. No further frames will
186     /// be returned.
apng(self) -> ApngDecoder<R>187     pub fn apng(self) -> ApngDecoder<R> {
188         ApngDecoder::new(self)
189     }
190 
191     /// Returns if the image contains an animation.
192     ///
193     /// Note that the file itself decides if the default image is considered to be part of the
194     /// animation. When it is not the common interpretation is to use it as a thumbnail.
195     ///
196     /// If a non-animated image is converted into an `ApngDecoder` then its iterator is empty.
is_apng(&self) -> bool197     pub fn is_apng(&self) -> bool {
198         self.reader.info().animation_control.is_some()
199     }
200 }
201 
unsupported_color(ect: ExtendedColorType) -> ImageError202 fn unsupported_color(ect: ExtendedColorType) -> ImageError {
203     ImageError::Unsupported(UnsupportedError::from_format_and_kind(
204         ImageFormat::Png.into(),
205         UnsupportedErrorKind::Color(ect),
206     ))
207 }
208 
209 impl<'a, R: 'a + Read> ImageDecoder<'a> for PngDecoder<R> {
210     type Reader = PngReader<R>;
211 
dimensions(&self) -> (u32, u32)212     fn dimensions(&self) -> (u32, u32) {
213         self.reader.info().size()
214     }
215 
color_type(&self) -> ColorType216     fn color_type(&self) -> ColorType {
217         self.color_type
218     }
219 
into_reader(self) -> ImageResult<Self::Reader>220     fn into_reader(self) -> ImageResult<Self::Reader> {
221         PngReader::new(self.reader)
222     }
223 
read_image(mut self, buf: &mut [u8]) -> ImageResult<()>224     fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> {
225         use byteorder::{BigEndian, ByteOrder, NativeEndian};
226 
227         assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));
228         self.reader.next_frame(buf).map_err(ImageError::from_png)?;
229         // PNG images are big endian. For 16 bit per channel and larger types,
230         // the buffer may need to be reordered to native endianness per the
231         // contract of `read_image`.
232         // TODO: assumes equal channel bit depth.
233         let bpc = self.color_type().bytes_per_pixel() / self.color_type().channel_count();
234         match bpc {
235             1 => (),  // No reodering necessary for u8
236             2 => buf.chunks_mut(2).for_each(|c| {
237                 let v = BigEndian::read_u16(c);
238                 NativeEndian::write_u16(c, v)
239             }),
240             _ => unreachable!(),
241         }
242         Ok(())
243     }
244 
scanline_bytes(&self) -> u64245     fn scanline_bytes(&self) -> u64 {
246         let width = self.reader.info().width;
247         self.reader.output_line_size(width) as u64
248     }
249 }
250 
251 /// An [`AnimationDecoder`] adapter of [`PngDecoder`].
252 ///
253 /// See [`PngDecoder::apng`] for more information.
254 ///
255 /// [`AnimationDecoder`]: ../trait.AnimationDecoder.html
256 /// [`PngDecoder`]: struct.PngDecoder.html
257 /// [`PngDecoder::apng`]: struct.PngDecoder.html#method.apng
258 pub struct ApngDecoder<R: Read> {
259     inner: PngDecoder<R>,
260     /// The current output buffer.
261     current: RgbaImage,
262     /// The previous output buffer, used for dispose op previous.
263     previous: RgbaImage,
264     /// The dispose op of the current frame.
265     dispose: DisposeOp,
266     /// The number of image still expected to be able to load.
267     remaining: u32,
268     /// The next (first) image is the thumbnail.
269     has_thumbnail: bool,
270 }
271 
272 impl<R: Read> ApngDecoder<R> {
new(inner: PngDecoder<R>) -> Self273     fn new(inner: PngDecoder<R>) -> Self {
274         let (width, height) = inner.dimensions();
275         let info = inner.reader.info();
276         let remaining = match info.animation_control() {
277             // The expected number of fcTL in the remaining image.
278             Some(actl) => actl.num_frames,
279             None => 0,
280         };
281         // If the IDAT has no fcTL then it is not part of the animation counted by
282         // num_frames. All following fdAT chunks must be preceded by an fcTL
283         let has_thumbnail = info.frame_control.is_none();
284         ApngDecoder {
285             inner,
286             // TODO: should we delay this allocation? At least if we support limits we should.
287             current: RgbaImage::new(width, height),
288             previous: RgbaImage::new(width, height),
289             dispose: DisposeOp::Background,
290             remaining,
291             has_thumbnail,
292         }
293     }
294 
295     // TODO: thumbnail(&mut self) -> Option<impl ImageDecoder<'_>>
296 
297     /// Decode one subframe and overlay it on the canvas.
mix_next_frame(&mut self) -> Result<Option<&RgbaImage>, ImageError>298     fn mix_next_frame(&mut self) -> Result<Option<&RgbaImage>, ImageError> {
299         // Remove this image from remaining.
300         self.remaining = match self.remaining.checked_sub(1) {
301             None => return Ok(None),
302             Some(next) => next,
303         };
304 
305         // Shorten ourselves to 0 in case of error.
306         let remaining = self.remaining;
307         self.remaining = 0;
308 
309         // Skip the thumbnail that is not part of the animation.
310         if self.has_thumbnail {
311             self.has_thumbnail = false;
312             let mut buffer = vec![0; self.inner.reader.output_buffer_size()];
313             self.inner.reader.next_frame(&mut buffer).map_err(ImageError::from_png)?;
314         }
315 
316         self.animatable_color_type()?;
317 
318         // Dispose of the previous frame.
319         match self.dispose {
320             DisposeOp::None => {
321                 self.previous.clone_from(&self.current);
322             }
323             DisposeOp::Background => {
324                 self.previous.clone_from(&self.current);
325                 self.current.pixels_mut().for_each(|pixel| *pixel = Rgba([0, 0, 0, 0]));
326             }
327             DisposeOp::Previous => {
328                 self.current.clone_from(&self.previous);
329             }
330         }
331 
332         // Read next frame data.
333         let mut buffer = vec![0; self.inner.reader.output_buffer_size()];
334         self.inner.reader.next_frame(&mut buffer).map_err(ImageError::from_png)?;
335         let info = self.inner.reader.info();
336 
337         // Find out how to interpret the decoded frame.
338         let (width, height, px, py, blend);
339         match info.frame_control() {
340             None => {
341                 width = info.width;
342                 height = info.height;
343                 px = 0;
344                 py = 0;
345                 blend = BlendOp::Source;
346             }
347             Some(fc) => {
348                 width = fc.width;
349                 height = fc.height;
350                 px = fc.x_offset;
351                 py = fc.y_offset;
352                 blend = fc.blend_op;
353                 self.dispose = fc.dispose_op;
354             }
355         };
356 
357         // Turn the data into an rgba image proper.
358         let source = match self.inner.color_type {
359             ColorType::L8 => {
360                 let image = ImageBuffer::<Luma<_>, _>::from_raw(width, height, buffer).unwrap();
361                 DynamicImage::ImageLuma8(image).into_rgba8()
362             }
363             ColorType::La8 => {
364                 let image = ImageBuffer::<LumaA<_>, _>::from_raw(width, height, buffer).unwrap();
365                 DynamicImage::ImageLumaA8(image).into_rgba8()
366             }
367             ColorType::Rgb8 => {
368                 let image = ImageBuffer::<Rgb<_>, _>::from_raw(width, height, buffer).unwrap();
369                 DynamicImage::ImageRgb8(image).into_rgba8()
370             }
371             ColorType::Rgba8 => {
372                 ImageBuffer::<Rgba<_>, _>::from_raw(width, height, buffer).unwrap()
373             }
374             ColorType::L16 | ColorType::Rgb16 | ColorType::La16 | ColorType::Rgba16 => {
375                 // TODO: to enable remove restriction in `animatable_color_type` method.
376                 unreachable!("16-bit apng not yet support")
377             }
378             _ => unreachable!("Invalid png color"),
379         };
380 
381         match blend {
382             BlendOp::Source => {
383                 self.current.copy_from(&source, px, py)
384                     .expect("Invalid png image not detected in png");
385             }
386             BlendOp::Over => {
387                 // TODO: investigate speed, speed-ups, and bounds-checks.
388                 for (x, y, p) in source.enumerate_pixels() {
389                     self.current.get_pixel_mut(x + px, y + py).blend(p);
390                 }
391             }
392         }
393 
394         // Ok, we can proceed with actually remaining images.
395         self.remaining = remaining;
396         // Return composited output buffer.
397         Ok(Some(&self.current))
398     }
399 
animatable_color_type(&self) -> Result<(), ImageError>400     fn animatable_color_type(&self) -> Result<(), ImageError> {
401         match self.inner.color_type {
402             ColorType::L8 | ColorType::Rgb8 | ColorType::La8 | ColorType::Rgba8 => Ok(()),
403             // TODO: do not handle multi-byte colors. Remember to implement it in `mix_next_frame`.
404             ColorType::L16 | ColorType::Rgb16 | ColorType::La16 | ColorType::Rgba16  => {
405                 Err(unsupported_color(self.inner.color_type.into()))
406             },
407             _ => unreachable!("{:?} not a valid png color", self.inner.color_type),
408         }
409     }
410 }
411 
412 impl<'a, R: Read + 'a> AnimationDecoder<'a> for ApngDecoder<R> {
into_frames(self) -> Frames<'a>413     fn into_frames(self) -> Frames<'a> {
414         struct FrameIterator<R: Read>(ApngDecoder<R>);
415 
416         impl<R: Read> Iterator for FrameIterator<R> {
417             type Item = ImageResult<Frame>;
418 
419             fn next(&mut self) -> Option<Self::Item> {
420                 let image = match self.0.mix_next_frame() {
421                     Ok(Some(image)) => image.clone(),
422                     Ok(None) => return None,
423                     Err(err) => return Some(Err(err)),
424                 };
425 
426                 let info = self.0.inner.reader.info();
427                 let fc = info.frame_control().unwrap();
428                 // PNG delays are rations in seconds.
429                 let num = u32::from(fc.delay_num) * 1_000u32;
430                 let denom = match fc.delay_den {
431                     // The standard dictates to replace by 100 when the denominator is 0.
432                     0 => 100,
433                     d => u32::from(d),
434                 };
435                 let delay = Delay::from_ratio(Ratio::new(num, denom));
436                 Some(Ok(Frame::from_parts(image, 0, 0, delay)))
437             }
438         }
439 
440         Frames::new(Box::new(FrameIterator(self)))
441     }
442 }
443 
444 /// PNG encoder
445 pub struct PngEncoder<W: Write> {
446     w: W,
447     compression: CompressionType,
448     filter: FilterType,
449 }
450 
451 /// PNG Encoder
452 ///
453 /// An alias of [`PngEncoder`].
454 ///
455 /// TODO: remove
456 ///
457 /// [`PngEncoder`]: struct.PngEncoder.html
458 #[allow(dead_code)]
459 #[deprecated(note = "Use `PngEncoder` instead")]
460 pub type PNGEncoder<W> = PngEncoder<W>;
461 
462 /// Compression level of a PNG encoder. The default setting is `Fast`.
463 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
464 pub enum CompressionType {
465     /// Default compression level
466     Default,
467     /// Fast, minimal compression
468     Fast,
469     /// High compression level
470     Best,
471     /// Huffman coding compression
472     Huffman,
473     /// Run-length encoding compression
474     Rle,
475 
476     #[doc(hidden)]
477     __NonExhaustive(crate::utils::NonExhaustiveMarker),
478 }
479 
480 /// Filter algorithms used to process image data to improve compression.
481 ///
482 /// The default filter is `Sub` though this default may change in the future, most notable if an
483 /// adaptive encoding option is implemented.
484 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
485 pub enum FilterType {
486     /// No processing done, best used for low bit depth greyscale or data with a
487     /// low color count
488     NoFilter,
489     /// Filters based on previous pixel in the same scanline
490     Sub,
491     /// Filters based on the scanline above
492     Up,
493     /// Filters based on the average of left and right neighbor pixels
494     Avg,
495     /// Algorithm that takes into account the left, upper left, and above pixels
496     Paeth,
497 
498     #[doc(hidden)]
499     __NonExhaustive(crate::utils::NonExhaustiveMarker),
500 }
501 
502 impl<W: Write> PngEncoder<W> {
503     /// Create a new encoder that writes its output to ```w```
new(w: W) -> PngEncoder<W>504     pub fn new(w: W) -> PngEncoder<W> {
505         PngEncoder {
506             w,
507             compression: CompressionType::Fast,
508             filter: FilterType::Sub,
509         }
510     }
511 
512     /// Create a new encoder that writes its output to `w` with `CompressionType` `compression` and
513     /// `FilterType` `filter`.
514     ///
515     /// It is best to view the options as a _hint_ to the implementation on the smallest or fastest
516     /// option for encoding a particular image. That is, using options that map directly to a PNG
517     /// image parameter will use this parameter where possible. But variants that have no direct
518     /// mapping may be interpreted differently in minor versions. The exact output is expressly
519     /// __not__ part the SemVer stability guarantee.
520     ///
521     /// Note that it is not optimal to use a single filter type. It is likely that the library used
522     /// will at some point gain the ability to use adaptive filtering methods per pixel row (or
523     /// even interlaced row). We might make it the new default variant in which case choosing a
524     /// particular filter method likely produces larger images. Be sure to check the release notes
525     /// once in a while.
new_with_quality(w: W, compression: CompressionType, filter: FilterType) -> PngEncoder<W>526     pub fn new_with_quality(w: W, compression: CompressionType, filter: FilterType) -> PngEncoder<W> {
527         PngEncoder {
528             w,
529             compression,
530             filter,
531         }
532     }
533 
534     /// Encodes the image `data` that has dimensions `width` and `height` and `ColorType` `c`.
encode(self, data: &[u8], width: u32, height: u32, color: ColorType) -> ImageResult<()>535     pub fn encode(self, data: &[u8], width: u32, height: u32, color: ColorType) -> ImageResult<()> {
536         let (ct, bits) = match color {
537             ColorType::L8 => (png::ColorType::Grayscale, png::BitDepth::Eight),
538             ColorType::L16 => (png::ColorType::Grayscale,png::BitDepth::Sixteen),
539             ColorType::La8 => (png::ColorType::GrayscaleAlpha, png::BitDepth::Eight),
540             ColorType::La16 => (png::ColorType::GrayscaleAlpha,png::BitDepth::Sixteen),
541             ColorType::Rgb8 => (png::ColorType::RGB, png::BitDepth::Eight),
542             ColorType::Rgb16 => (png::ColorType::RGB,png::BitDepth::Sixteen),
543             ColorType::Rgba8 => (png::ColorType::RGBA, png::BitDepth::Eight),
544             ColorType::Rgba16 => (png::ColorType::RGBA,png::BitDepth::Sixteen),
545             _ => return Err(ImageError::Unsupported(UnsupportedError::from_format_and_kind(
546                 ImageFormat::Png.into(),
547                 UnsupportedErrorKind::Color(color.into()),
548             ))),
549         };
550         let comp = match self.compression {
551             CompressionType::Default => png::Compression::Default,
552             CompressionType::Fast => png::Compression::Fast,
553             CompressionType::Best => png::Compression::Best,
554             CompressionType::Huffman => png::Compression::Huffman,
555             CompressionType::Rle => png::Compression::Rle,
556             CompressionType::__NonExhaustive(marker) => match marker._private {},
557         };
558         let filt = match self.filter {
559             FilterType::NoFilter => png::FilterType::NoFilter,
560             FilterType::Sub => png::FilterType::Sub,
561             FilterType::Up => png::FilterType::Up,
562             FilterType::Avg => png::FilterType::Avg,
563             FilterType::Paeth => png::FilterType::Paeth,
564             FilterType::__NonExhaustive(marker) => match marker._private {},
565         };
566 
567         let mut encoder = png::Encoder::new(self.w, width, height);
568         encoder.set_color(ct);
569         encoder.set_depth(bits);
570         encoder.set_compression(comp);
571         encoder.set_filter(filt);
572         let mut writer = encoder.write_header().map_err(|e| ImageError::IoError(e.into()))?;
573         writer.write_image_data(data).map_err(|e| ImageError::IoError(e.into()))
574     }
575 }
576 
577 impl<W: Write> ImageEncoder for PngEncoder<W> {
write_image( self, buf: &[u8], width: u32, height: u32, color_type: ColorType, ) -> ImageResult<()>578     fn write_image(
579         self,
580         buf: &[u8],
581         width: u32,
582         height: u32,
583         color_type: ColorType,
584     ) -> ImageResult<()> {
585         use byteorder::{BigEndian, ByteOrder, NativeEndian};
586 
587         // PNG images are big endian. For 16 bit per channel and larger types,
588         // the buffer may need to be reordered to big endian per the
589         // contract of `write_image`.
590         // TODO: assumes equal channel bit depth.
591         let bpc = color_type.bytes_per_pixel() / color_type.channel_count();
592         match bpc {
593             1 => self.encode(buf, width, height, color_type),  // No reodering necessary for u8
594             2 => {
595                 // Because the buffer is immutable and the PNG encoder does not
596                 // yet take Write/Read traits, create a temporary buffer for
597                 // big endian reordering.
598                 let mut reordered = vec![0; buf.len()];
599                 buf.chunks(2)
600                     .zip(reordered.chunks_mut(2))
601                     .for_each(|(b, r)| BigEndian::write_u16(r, NativeEndian::read_u16(b)));
602                 self.encode(&reordered, width, height, color_type)
603             },
604             _ => unreachable!(),
605         }
606     }
607 }
608 
609 impl ImageError {
from_png(err: png::DecodingError) -> ImageError610     fn from_png(err: png::DecodingError) -> ImageError {
611         use png::DecodingError::*;
612         match err {
613             IoError(err) => ImageError::IoError(err),
614             err @ Format(_) => ImageError::Decoding(DecodingError::new(
615                 ImageFormat::Png.into(),
616                 err,
617             )),
618             LimitsExceeded => ImageError::Limits(LimitError::from_kind(
619                 LimitErrorKind::InsufficientMemory,
620             )),
621             // Other is used when the buffer to `Reader::next_frame` is too small.
622             Other(message) => ImageError::Parameter(ParameterError::from_kind(
623                 ParameterErrorKind::Generic(message.into_owned())
624             )),
625             err @ InvalidSignature
626             | err @ CrcMismatch { .. }
627             | err @ CorruptFlateStream => {
628                 ImageError::Decoding(DecodingError::new(
629                     ImageFormat::Png.into(),
630                     err,
631                 ))
632             }
633         }
634     }
635 }
636 
637 impl Default for CompressionType {
default() -> Self638     fn default() -> Self {
639         CompressionType::Fast
640     }
641 }
642 
643 impl Default for FilterType {
default() -> Self644     fn default() -> Self {
645         FilterType::Sub
646     }
647 }
648 
649 #[cfg(test)]
650 mod tests {
651     use crate::image::ImageDecoder;
652     use std::io::Read;
653     use super::*;
654 
655     #[test]
ensure_no_decoder_off_by_one()656     fn ensure_no_decoder_off_by_one() {
657         let dec = PngDecoder::new(std::fs::File::open("tests/images/png/bugfixes/debug_triangle_corners_widescreen.png").unwrap())
658             .expect("Unable to read PNG file (does it exist?)");
659 
660         assert_eq![(2000, 1000), dec.dimensions()];
661 
662         assert_eq![
663             ColorType::Rgb8,
664             dec.color_type(),
665             "Image MUST have the Rgb8 format"
666         ];
667 
668         let correct_bytes = dec
669             .into_reader()
670             .expect("Unable to read file")
671             .bytes()
672             .map(|x| x.expect("Unable to read byte"))
673             .collect::<Vec<u8>>();
674 
675         assert_eq![6_000_000, correct_bytes.len()];
676     }
677 
678     #[test]
underlying_error()679     fn underlying_error() {
680         use std::error::Error;
681 
682         let mut not_png = std::fs::read("tests/images/png/bugfixes/debug_triangle_corners_widescreen.png").unwrap();
683         not_png[0] = 0;
684 
685         let error = PngDecoder::new(&not_png[..]).err().unwrap();
686         let _ = error
687             .source()
688             .unwrap()
689             .downcast_ref::<png::DecodingError>()
690             .expect("Caused by a png error");
691     }
692 }
693