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 crate::color::{ColorType, ExtendedColorType};
13 use crate::error::{DecodingError, ImageError, ImageResult, ParameterError, ParameterErrorKind};
14 use crate::image::{ImageDecoder, ImageEncoder, ImageFormat};
15 
16 /// PNG Reader
17 ///
18 /// This reader will try to read the png one row at a time,
19 /// however for interlaced png files this is not possible and
20 /// these are therefore read at once.
21 pub struct PNGReader<R: Read> {
22     reader: png::Reader<R>,
23     buffer: Vec<u8>,
24     index: usize,
25 }
26 
27 impl<R: Read> PNGReader<R> {
new(mut reader: png::Reader<R>) -> ImageResult<PNGReader<R>>28     fn new(mut reader: png::Reader<R>) -> ImageResult<PNGReader<R>> {
29         let len = reader.output_buffer_size();
30         // Since interlaced images do not come in
31         // scanline order it is almost impossible to
32         // read them in a streaming fashion, however
33         // this shouldn't be a too big of a problem
34         // as most interlaced images should fit in memory.
35         let buffer = if reader.info().interlaced {
36             let mut buffer = vec![0; len];
37             reader.next_frame(&mut buffer).map_err(ImageError::from_png)?;
38             buffer
39         } else {
40             Vec::new()
41         };
42 
43         Ok(PNGReader {
44             reader,
45             buffer,
46             index: 0,
47         })
48     }
49 }
50 
51 impl<R: Read> Read for PNGReader<R> {
read(&mut self, mut buf: &mut [u8]) -> io::Result<usize>52     fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {
53         // io::Write::write for slice cannot fail
54         let readed = buf.write(&self.buffer[self.index..]).unwrap();
55 
56         let mut bytes = readed;
57         self.index += readed;
58 
59         while self.index >= self.buffer.len() {
60             match self.reader.next_row()? {
61                 Some(row) => {
62                     // Faster to copy directly to external buffer
63                     let readed  = buf.write(row).unwrap();
64                     bytes += readed;
65 
66                     self.buffer = (&row[readed..]).to_owned();
67                     self.index = 0;
68                 }
69                 None => return Ok(bytes)
70             }
71         }
72 
73         Ok(bytes)
74     }
75 
read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize>76     fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
77         let mut bytes = self.buffer.len();
78         buf.extend_from_slice(&self.buffer);
79         self.buffer = Vec::new();
80         self.index = 0;
81 
82         while let Some(row) = self.reader.next_row()? {
83             buf.extend_from_slice(row);
84             bytes += row.len();
85         }
86 
87         Ok(bytes)
88     }
89 }
90 
91 /// PNG decoder
92 pub struct PngDecoder<R: Read> {
93     color_type: ColorType,
94     reader: png::Reader<R>,
95 }
96 
97 impl<R: Read> PngDecoder<R> {
98     /// Creates a new decoder that decodes from the stream ```r```
new(r: R) -> ImageResult<PngDecoder<R>>99     pub fn new(r: R) -> ImageResult<PngDecoder<R>> {
100         let limits = png::Limits {
101             bytes: usize::max_value(),
102         };
103         let mut decoder = png::Decoder::new_with_limits(r, limits);
104         // By default the PNG decoder will scale 16 bpc to 8 bpc, so custom
105         // transformations must be set. EXPAND preserves the default behavior
106         // expanding bpc < 8 to 8 bpc.
107         decoder.set_transformations(png::Transformations::EXPAND);
108         let (_, mut reader) = decoder.read_info().map_err(ImageError::from_png)?;
109         let (color_type, bits) = reader.output_color_type();
110         let color_type = match (color_type, bits) {
111             (png::ColorType::Grayscale, png::BitDepth::Eight) => ColorType::L8,
112             (png::ColorType::Grayscale, png::BitDepth::Sixteen) => ColorType::L16,
113             (png::ColorType::GrayscaleAlpha, png::BitDepth::Eight) => ColorType::La8,
114             (png::ColorType::GrayscaleAlpha, png::BitDepth::Sixteen) => ColorType::La16,
115             (png::ColorType::RGB, png::BitDepth::Eight) => ColorType::Rgb8,
116             (png::ColorType::RGB, png::BitDepth::Sixteen) => ColorType::Rgb16,
117             (png::ColorType::RGBA, png::BitDepth::Eight) => ColorType::Rgba8,
118             (png::ColorType::RGBA, png::BitDepth::Sixteen) => ColorType::Rgba16,
119 
120             (png::ColorType::Grayscale, png::BitDepth::One) =>
121                 return Err(ImageError::UnsupportedColor(ExtendedColorType::L1)),
122             (png::ColorType::GrayscaleAlpha, png::BitDepth::One) =>
123                 return Err(ImageError::UnsupportedColor(ExtendedColorType::La1)),
124             (png::ColorType::RGB, png::BitDepth::One) =>
125                 return Err(ImageError::UnsupportedColor(ExtendedColorType::Rgb1)),
126             (png::ColorType::RGBA, png::BitDepth::One) =>
127                 return Err(ImageError::UnsupportedColor(ExtendedColorType::Rgba1)),
128 
129             (png::ColorType::Grayscale, png::BitDepth::Two) =>
130                 return Err(ImageError::UnsupportedColor(ExtendedColorType::L2)),
131             (png::ColorType::GrayscaleAlpha, png::BitDepth::Two) =>
132                 return Err(ImageError::UnsupportedColor(ExtendedColorType::La2)),
133             (png::ColorType::RGB, png::BitDepth::Two) =>
134                 return Err(ImageError::UnsupportedColor(ExtendedColorType::Rgb2)),
135             (png::ColorType::RGBA, png::BitDepth::Two) =>
136                 return Err(ImageError::UnsupportedColor(ExtendedColorType::Rgba2)),
137 
138             (png::ColorType::Grayscale, png::BitDepth::Four) =>
139                 return Err(ImageError::UnsupportedColor(ExtendedColorType::L4)),
140             (png::ColorType::GrayscaleAlpha, png::BitDepth::Four) =>
141                 return Err(ImageError::UnsupportedColor(ExtendedColorType::La4)),
142             (png::ColorType::RGB, png::BitDepth::Four) =>
143                 return Err(ImageError::UnsupportedColor(ExtendedColorType::Rgb4)),
144             (png::ColorType::RGBA, png::BitDepth::Four) =>
145                 return Err(ImageError::UnsupportedColor(ExtendedColorType::Rgba4)),
146 
147             (png::ColorType::Indexed, bits) =>
148                 return Err(ImageError::UnsupportedColor(ExtendedColorType::Unknown(bits as u8))),
149         };
150 
151         Ok(PngDecoder { color_type, reader })
152     }
153 }
154 
155 impl<'a, R: 'a + Read> ImageDecoder<'a> for PngDecoder<R> {
156     type Reader = PNGReader<R>;
157 
dimensions(&self) -> (u32, u32)158     fn dimensions(&self) -> (u32, u32) {
159         self.reader.info().size()
160     }
161 
color_type(&self) -> ColorType162     fn color_type(&self) -> ColorType {
163         self.color_type
164     }
165 
into_reader(self) -> ImageResult<Self::Reader>166     fn into_reader(self) -> ImageResult<Self::Reader> {
167         PNGReader::new(self.reader)
168     }
169 
read_image(mut self, buf: &mut [u8]) -> ImageResult<()>170     fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> {
171         use byteorder::{BigEndian, ByteOrder, NativeEndian};
172 
173         assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));
174         self.reader.next_frame(buf).map_err(ImageError::from_png)?;
175         // PNG images are big endian. For 16 bit per channel and larger types,
176         // the buffer may need to be reordered to native endianness per the
177         // contract of `read_image`.
178         // TODO: assumes equal channel bit depth.
179         let bpc = self.color_type().bytes_per_pixel() / self.color_type().channel_count();
180         match bpc {
181             1 => (),  // No reodering necessary for u8
182             2 => buf.chunks_mut(2).for_each(|c| {
183                 let v = BigEndian::read_u16(c);
184                 NativeEndian::write_u16(c, v)
185             }),
186             _ => unreachable!(),
187         }
188         Ok(())
189     }
190 
scanline_bytes(&self) -> u64191     fn scanline_bytes(&self) -> u64 {
192         let width = self.reader.info().width;
193         self.reader.output_line_size(width) as u64
194     }
195 }
196 
197 /// PNG encoder
198 pub struct PNGEncoder<W: Write> {
199     w: W,
200 }
201 
202 impl<W: Write> PNGEncoder<W> {
203     /// Create a new encoder that writes its output to ```w```
new(w: W) -> PNGEncoder<W>204     pub fn new(w: W) -> PNGEncoder<W> {
205         PNGEncoder { w }
206     }
207 
208     /// Encodes the image ```image```
209     /// that has dimensions ```width``` and ```height```
210     /// and ```ColorType``` ```c```
encode(self, data: &[u8], width: u32, height: u32, color: ColorType) -> ImageResult<()>211     pub fn encode(self, data: &[u8], width: u32, height: u32, color: ColorType) -> ImageResult<()> {
212         let (ct, bits) = match color {
213             ColorType::L8 => (png::ColorType::Grayscale, png::BitDepth::Eight),
214             ColorType::L16 => (png::ColorType::Grayscale,png::BitDepth::Sixteen),
215             ColorType::La8 => (png::ColorType::GrayscaleAlpha, png::BitDepth::Eight),
216             ColorType::La16 => (png::ColorType::GrayscaleAlpha,png::BitDepth::Sixteen),
217             ColorType::Rgb8 => (png::ColorType::RGB, png::BitDepth::Eight),
218             ColorType::Rgb16 => (png::ColorType::RGB,png::BitDepth::Sixteen),
219             ColorType::Rgba8 => (png::ColorType::RGBA, png::BitDepth::Eight),
220             ColorType::Rgba16 => (png::ColorType::RGBA,png::BitDepth::Sixteen),
221             _ => return Err(ImageError::UnsupportedColor(color.into())),
222         };
223 
224         let mut encoder = png::Encoder::new(self.w, width, height);
225         encoder.set_color(ct);
226         encoder.set_depth(bits);
227         let mut writer = encoder.write_header().map_err(|e| ImageError::IoError(e.into()))?;
228         writer.write_image_data(data).map_err(|e| ImageError::IoError(e.into()))
229     }
230 }
231 
232 impl<W: Write> ImageEncoder for PNGEncoder<W> {
write_image( self, buf: &[u8], width: u32, height: u32, color_type: ColorType, ) -> ImageResult<()>233     fn write_image(
234         self,
235         buf: &[u8],
236         width: u32,
237         height: u32,
238         color_type: ColorType,
239     ) -> ImageResult<()> {
240         use byteorder::{BigEndian, ByteOrder, NativeEndian};
241 
242         // PNG images are big endian. For 16 bit per channel and larger types,
243         // the buffer may need to be reordered to big endian per the
244         // contract of `write_image`.
245         // TODO: assumes equal channel bit depth.
246         let bpc = color_type.bytes_per_pixel() / color_type.channel_count();
247         match bpc {
248             1 => self.encode(buf, width, height, color_type),  // No reodering necessary for u8
249             2 => {
250                 // Because the buffer is immutable and the PNG encoder does not
251                 // yet take Write/Read traits, create a temporary buffer for
252                 // big endian reordering.
253                 let mut reordered = vec![0; buf.len()];
254                 buf.chunks(2)
255                     .zip(reordered.chunks_mut(2))
256                     .for_each(|(b, r)| BigEndian::write_u16(r, NativeEndian::read_u16(b)));
257                 self.encode(&reordered, width, height, color_type)
258             },
259             _ => unreachable!(),
260         }
261     }
262 }
263 
264 impl ImageError {
from_png(err: png::DecodingError) -> ImageError265     fn from_png(err: png::DecodingError) -> ImageError {
266         use png::DecodingError::*;
267         match err {
268             IoError(err) => ImageError::IoError(err),
269             Format(message) => ImageError::Decoding(DecodingError::with_message(
270                 ImageFormat::Png.into(),
271                 message.into_owned(),
272             )),
273             LimitsExceeded => ImageError::InsufficientMemory,
274             // Other is used when the buffer to `Reader::next_frame` is too small.
275             Other(message) => ImageError::Parameter(ParameterError::from_kind(
276                 ParameterErrorKind::Generic(message.into_owned())
277             )),
278             err @ InvalidSignature
279             | err @ CrcMismatch { .. }
280             | err @ CorruptFlateStream => {
281                 ImageError::Decoding(DecodingError::new(
282                     ImageFormat::Png.into(),
283                     err,
284                 ))
285             }
286         }
287     }
288 }
289 
290 #[cfg(test)]
291 mod tests {
292     use crate::image::ImageDecoder;
293     use std::io::Read;
294     use super::*;
295 
296     #[test]
ensure_no_decoder_off_by_one()297     fn ensure_no_decoder_off_by_one() {
298         let dec = PngDecoder::new(std::fs::File::open("tests/images/png/bugfixes/debug_triangle_corners_widescreen.png").unwrap())
299             .expect("Unable to read PNG file (does it exist?)");
300 
301         assert_eq![(2000, 1000), dec.dimensions()];
302 
303         assert_eq![
304             ColorType::Rgb8,
305             dec.color_type(),
306             "Image MUST have the Rgb8 format"
307         ];
308 
309         let correct_bytes = dec
310             .into_reader()
311             .expect("Unable to read file")
312             .bytes()
313             .map(|x| x.expect("Unable to read byte"))
314             .collect::<Vec<u8>>();
315 
316         assert_eq![6_000_000, correct_bytes.len()];
317     }
318 
319     #[test]
underlying_error()320     fn underlying_error() {
321         use std::error::Error;
322 
323         let mut not_png = std::fs::read("tests/images/png/bugfixes/debug_triangle_corners_widescreen.png").unwrap();
324         not_png[0] = 0;
325 
326         let error = PngDecoder::new(&not_png[..]).err().unwrap();
327         let _ = error
328             .source()
329             .unwrap()
330             .downcast_ref::<png::DecodingError>()
331             .expect("Caused by a png error");
332     }
333 }
334