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(¬_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