1 use std::convert::TryFrom;
2 use std::error;
3 use std::io::{self, BufRead, BufReader, Cursor, Read};
4 use std::str::{self, FromStr};
5 use std::fmt::{self, Display};
6 use std::marker::PhantomData;
7 use std::mem;
8 use std::num::ParseIntError;
9 
10 use super::{ArbitraryHeader, ArbitraryTuplType, BitmapHeader, GraymapHeader, PixmapHeader};
11 use super::{HeaderRecord, PNMHeader, PNMSubtype, SampleEncoding};
12 use crate::color::{ColorType, ExtendedColorType};
13 use crate::error::{
14     DecodingError, ImageError, ImageResult, UnsupportedError, UnsupportedErrorKind,
15 };
16 use crate::image::{self, ImageDecoder, ImageFormat};
17 use crate::utils;
18 
19 use byteorder::{BigEndian, ByteOrder, NativeEndian};
20 
21 /// All errors that can occur when attempting to parse a PNM
22 #[derive(Debug, Clone)]
23 enum DecoderError {
24     /// PNM's "P[123456]" signature wrong or missing
25     PnmMagicInvalid([u8; 2]),
26     /// Couldn't parse the specified string as an integer from the specified source
27     UnparsableValue(ErrorDataSource, String, ParseIntError),
28 
29     /// More than the exactly one allowed plane specified by the format
30     NonAsciiByteInHeader(u8),
31     /// The PAM header contained a non-ASCII byte
32     NonAsciiLineInPamHeader,
33     /// A sample string contained a non-ASCII byte
34     NonAsciiSample,
35 
36     /// The byte after the P7 magic was not 0x0A NEWLINE
37     NotNewlineAfterP7Magic(u8),
38     /// The PNM header had too few lines
39     UnexpectedPnmHeaderEnd,
40 
41     /// The specified line was specified twice
42     HeaderLineDuplicated(PnmHeaderLine),
43     /// The line with the specified ID was not understood
44     HeaderLineUnknown(String),
45     /// At least one of the required lines were missing from the header (are `None` here)
46     ///
47     /// Same names as [`PnmHeaderLine`](enum.PnmHeaderLine.html)
48     #[allow(missing_docs)]
49     HeaderLineMissing {
50         height: Option<u32>,
51         width: Option<u32>,
52         depth: Option<u32>,
53         maxval: Option<u32>,
54     },
55 
56     /// Not enough data was provided to the Decoder to decode the image
57     InputTooShort,
58     /// Sample raster contained unexpected byte
59     UnexpectedByteInRaster(u8),
60     /// Specified sample was out of bounds (e.g. >1 in B&W)
61     SampleOutOfBounds(u8),
62     /// The image's maxval exceeds 0xFFFF
63     MaxvalTooBig(u32),
64 
65     /// The specified tuple type supports restricted depths and maxvals, those restrictions were not met
66     InvalidDepthOrMaxval {
67         tuple_type: ArbitraryTuplType,
68         depth: u32,
69         maxval: u32,
70     },
71     /// The specified tuple type supports restricted depths, those restrictions were not met
72     InvalidDepth {
73         tuple_type: ArbitraryTuplType,
74         depth: u32,
75     },
76     /// The tuple type was not recognised by the parser
77     TupleTypeUnrecognised,
78 }
79 
80 impl Display for DecoderError {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result81     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82         match self {
83             DecoderError::PnmMagicInvalid(magic) =>
84                 f.write_fmt(format_args!("Expected magic constant for PNM: P1..P7, got [{:#04X?}, {:#04X?}]", magic[0], magic[1])),
85             DecoderError::UnparsableValue(src, data, err) =>
86                 f.write_fmt(format_args!("Error parsing {:?} as {}: {}", data, src, err)),
87 
88             DecoderError::NonAsciiByteInHeader(c) =>
89                 f.write_fmt(format_args!("Non-ASCII character {:#04X?} in header", c)),
90             DecoderError::NonAsciiLineInPamHeader =>
91                 f.write_str("Non-ASCII line in PAM header"),
92             DecoderError::NonAsciiSample =>
93                 f.write_str("Non-ASCII character where sample value was expected"),
94 
95             DecoderError::NotNewlineAfterP7Magic(c) =>
96                 f.write_fmt(format_args!("Expected newline after P7 magic, got {:#04X?}", c)),
97             DecoderError::UnexpectedPnmHeaderEnd =>
98                 f.write_str("Unexpected end of PNM header"),
99 
100             DecoderError::HeaderLineDuplicated(line) =>
101                 f.write_fmt(format_args!("Duplicate {} line", line)),
102             DecoderError::HeaderLineUnknown(identifier) =>
103                 f.write_fmt(format_args!("Unknown header line with identifier {:?}", identifier)),
104             DecoderError::HeaderLineMissing { height, width, depth, maxval } =>
105                 f.write_fmt(format_args!("Missing header line: have height={:?}, width={:?}, depth={:?}, maxval={:?}", height, width, depth, maxval)),
106 
107             DecoderError::InputTooShort =>
108                 f.write_str("Not enough data was provided to the Decoder to decode the image"),
109             DecoderError::UnexpectedByteInRaster(c) =>
110                 f.write_fmt(format_args!("Unexpected character {:#04X?} within sample raster", c)),
111             DecoderError::SampleOutOfBounds(val) =>
112                 f.write_fmt(format_args!("Sample value {} outside of bounds", val)),
113             DecoderError::MaxvalTooBig(maxval) =>
114                 f.write_fmt(format_args!("Image MAXVAL exceeds {}: {}", 0xFFFF, maxval)),
115 
116             DecoderError::InvalidDepthOrMaxval { tuple_type, depth, maxval } =>
117                 f.write_fmt(format_args!("Invalid depth ({}) or maxval ({}) for tuple type {}", depth, maxval, tuple_type.name())),
118             DecoderError::InvalidDepth { tuple_type, depth } =>
119                 f.write_fmt(format_args!("Invalid depth ({}) for tuple type {}", depth, tuple_type.name())),
120             DecoderError::TupleTypeUnrecognised =>
121                 f.write_str("Tuple type not recognized"),
122         }
123     }
124 }
125 
126 /// Note: should `pnm` be extracted into a separate crate,
127 /// this will need to be hidden until that crate hits version `1.0`.
128 impl From<DecoderError> for ImageError {
from(e: DecoderError) -> ImageError129     fn from(e: DecoderError) -> ImageError {
130         ImageError::Decoding(DecodingError::new(ImageFormat::Pnm.into(), e))
131     }
132 }
133 
134 impl error::Error for DecoderError {
source(&self) -> Option<&(dyn error::Error + 'static)>135     fn source(&self) -> Option<&(dyn error::Error + 'static)> {
136         match self {
137             DecoderError::UnparsableValue(_, _, err) => Some(err),
138             _ => None,
139         }
140     }
141 }
142 
143 /// Single-value lines in a PNM header
144 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
145 enum PnmHeaderLine {
146     /// "HEIGHT"
147     Height,
148     /// "WIDTH"
149     Width,
150     /// "DEPTH"
151     Depth,
152     /// "MAXVAL", a.k.a. `maxwhite`
153     Maxval,
154 }
155 
156 impl Display for PnmHeaderLine {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result157     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
158         f.write_str(match self {
159             PnmHeaderLine::Height => "HEIGHT",
160             PnmHeaderLine::Width => "WIDTH",
161             PnmHeaderLine::Depth => "DEPTH",
162             PnmHeaderLine::Maxval => "MAXVAL",
163         })
164     }
165 }
166 
167 /// Single-value lines in a PNM header
168 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
169 enum ErrorDataSource {
170     /// One of the header lines
171     Line(PnmHeaderLine),
172     /// Value in the preamble
173     Preamble,
174     /// Sample/pixel data
175     Sample,
176 }
177 
178 impl Display for ErrorDataSource {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result179     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180         match self {
181             ErrorDataSource::Line(l) => l.fmt(f),
182             ErrorDataSource::Preamble => f.write_str("number in preamble"),
183             ErrorDataSource::Sample => f.write_str("sample"),
184         }
185     }
186 }
187 
188 /// Dynamic representation, represents all decodable (sample, depth) combinations.
189 #[derive(Clone, Copy)]
190 enum TupleType {
191     PbmBit,
192     BWBit,
193     GrayU8,
194     GrayU16,
195     RGBU8,
196     RGBU16,
197 }
198 
199 trait Sample {
bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize>200     fn bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize>;
201 
202     /// It is guaranteed that `bytes.len() == bytelen(width, height, samples)`
from_bytes(bytes: &[u8], width: u32, height: u32, samples: u32) -> ImageResult<Vec<u8>>203     fn from_bytes(bytes: &[u8], width: u32, height: u32, samples: u32)
204         -> ImageResult<Vec<u8>>;
205 
from_ascii(reader: &mut dyn Read, width: u32, height: u32, samples: u32) -> ImageResult<Vec<u8>>206     fn from_ascii(reader: &mut dyn Read, width: u32, height: u32, samples: u32)
207         -> ImageResult<Vec<u8>>;
208 }
209 
210 struct U8;
211 struct U16;
212 struct PbmBit;
213 struct BWBit;
214 
215 trait DecodableImageHeader {
tuple_type(&self) -> ImageResult<TupleType>216     fn tuple_type(&self) -> ImageResult<TupleType>;
217 }
218 
219 /// PNM decoder
220 pub struct PnmDecoder<R> {
221     reader: BufReader<R>,
222     header: PNMHeader,
223     tuple: TupleType,
224 }
225 
226 impl<R: Read> PnmDecoder<R> {
227     /// Create a new decoder that decodes from the stream ```read```
new(read: R) -> ImageResult<PnmDecoder<R>>228     pub fn new(read: R) -> ImageResult<PnmDecoder<R>> {
229         let mut buf = BufReader::new(read);
230         let magic = buf.read_magic_constant()?;
231 
232         let subtype = match magic {
233             [b'P', b'1'] => PNMSubtype::Bitmap(SampleEncoding::Ascii),
234             [b'P', b'2'] => PNMSubtype::Graymap(SampleEncoding::Ascii),
235             [b'P', b'3'] => PNMSubtype::Pixmap(SampleEncoding::Ascii),
236             [b'P', b'4'] => PNMSubtype::Bitmap(SampleEncoding::Binary),
237             [b'P', b'5'] => PNMSubtype::Graymap(SampleEncoding::Binary),
238             [b'P', b'6'] => PNMSubtype::Pixmap(SampleEncoding::Binary),
239             [b'P', b'7'] => PNMSubtype::ArbitraryMap,
240             _ => Err(DecoderError::PnmMagicInvalid(magic))?,
241         };
242 
243         match subtype {
244             PNMSubtype::Bitmap(enc) => PnmDecoder::read_bitmap_header(buf, enc),
245             PNMSubtype::Graymap(enc) => PnmDecoder::read_graymap_header(buf, enc),
246             PNMSubtype::Pixmap(enc) => PnmDecoder::read_pixmap_header(buf, enc),
247             PNMSubtype::ArbitraryMap => PnmDecoder::read_arbitrary_header(buf),
248         }
249     }
250 
251     /// Extract the reader and header after an image has been read.
into_inner(self) -> (R, PNMHeader)252     pub fn into_inner(self) -> (R, PNMHeader) {
253         (self.reader.into_inner(), self.header)
254     }
255 
read_bitmap_header( mut reader: BufReader<R>, encoding: SampleEncoding, ) -> ImageResult<PnmDecoder<R>>256     fn read_bitmap_header(
257         mut reader: BufReader<R>,
258         encoding: SampleEncoding,
259     ) -> ImageResult<PnmDecoder<R>> {
260         let header = reader.read_bitmap_header(encoding)?;
261         Ok(PnmDecoder {
262             reader,
263             tuple: TupleType::PbmBit,
264             header: PNMHeader {
265                 decoded: HeaderRecord::Bitmap(header),
266                 encoded: None,
267             },
268         })
269     }
270 
read_graymap_header( mut reader: BufReader<R>, encoding: SampleEncoding, ) -> ImageResult<PnmDecoder<R>>271     fn read_graymap_header(
272         mut reader: BufReader<R>,
273         encoding: SampleEncoding,
274     ) -> ImageResult<PnmDecoder<R>> {
275         let header = reader.read_graymap_header(encoding)?;
276         let tuple_type = header.tuple_type()?;
277         Ok(PnmDecoder {
278             reader,
279             tuple: tuple_type,
280             header: PNMHeader {
281                 decoded: HeaderRecord::Graymap(header),
282                 encoded: None,
283             },
284         })
285     }
286 
read_pixmap_header( mut reader: BufReader<R>, encoding: SampleEncoding, ) -> ImageResult<PnmDecoder<R>>287     fn read_pixmap_header(
288         mut reader: BufReader<R>,
289         encoding: SampleEncoding,
290     ) -> ImageResult<PnmDecoder<R>> {
291         let header = reader.read_pixmap_header(encoding)?;
292         let tuple_type = header.tuple_type()?;
293         Ok(PnmDecoder {
294             reader,
295             tuple: tuple_type,
296             header: PNMHeader {
297                 decoded: HeaderRecord::Pixmap(header),
298                 encoded: None,
299             },
300         })
301     }
302 
read_arbitrary_header(mut reader: BufReader<R>) -> ImageResult<PnmDecoder<R>>303     fn read_arbitrary_header(mut reader: BufReader<R>) -> ImageResult<PnmDecoder<R>> {
304         let header = reader.read_arbitrary_header()?;
305         let tuple_type = header.tuple_type()?;
306         Ok(PnmDecoder {
307             reader,
308             tuple: tuple_type,
309             header: PNMHeader {
310                 decoded: HeaderRecord::Arbitrary(header),
311                 encoded: None,
312             },
313         })
314     }
315 }
316 
317 trait HeaderReader: BufRead {
318     /// Reads the two magic constant bytes
read_magic_constant(&mut self) -> ImageResult<[u8; 2]>319     fn read_magic_constant(&mut self) -> ImageResult<[u8; 2]> {
320         let mut magic: [u8; 2] = [0, 0];
321         self.read_exact(&mut magic)?;
322         Ok(magic)
323     }
324 
325     /// Reads a string as well as a single whitespace after it, ignoring comments
read_next_string(&mut self) -> ImageResult<String>326     fn read_next_string(&mut self) -> ImageResult<String> {
327         let mut bytes = Vec::new();
328 
329         // pair input bytes with a bool mask to remove comments
330         let mark_comments = self.bytes().scan(true, |partof, read| {
331             let byte = match read {
332                 Err(err) => return Some((*partof, Err(err))),
333                 Ok(byte) => byte,
334             };
335             let cur_enabled = *partof && byte != b'#';
336             let next_enabled = cur_enabled || (byte == b'\r' || byte == b'\n');
337             *partof = next_enabled;
338             Some((cur_enabled, Ok(byte)))
339         });
340 
341         for (_, byte) in mark_comments.filter(|ref e| e.0) {
342             match byte {
343                 Ok(b'\t') | Ok(b'\n') | Ok(b'\x0b') | Ok(b'\x0c') | Ok(b'\r') | Ok(b' ') => {
344                     if !bytes.is_empty() {
345                         break; // We're done as we already have some content
346                     }
347                 }
348                 Ok(byte) if !byte.is_ascii() => Err(DecoderError::NonAsciiByteInHeader(byte))?,
349                 Ok(byte) => {
350                     bytes.push(byte);
351                 },
352                 Err(_) => break,
353             }
354         }
355 
356         if bytes.is_empty() {
357             return Err(ImageError::IoError(io::ErrorKind::UnexpectedEof.into()));
358         }
359 
360         if !bytes.as_slice().is_ascii() {
361             // We have only filled the buffer with characters for which `byte.is_ascii()` holds.
362             unreachable!("Non-ASCII character should have returned sooner")
363         }
364 
365         let string = String::from_utf8(bytes)
366             // We checked the precondition ourselves a few lines before, `bytes.as_slice().is_ascii()`.
367             .unwrap_or_else(|_| unreachable!("Only ASCII characters should be decoded"));
368 
369         Ok(string)
370     }
371 
372     /// Read the next line
read_next_line(&mut self) -> ImageResult<String>373     fn read_next_line(&mut self) -> ImageResult<String> {
374         let mut buffer = String::new();
375         self.read_line(&mut buffer)?;
376         Ok(buffer)
377     }
378 
read_next_u32(&mut self) -> ImageResult<u32>379     fn read_next_u32(&mut self) -> ImageResult<u32> {
380         let s = self.read_next_string()?;
381         s.parse::<u32>()
382             .map_err(|err| DecoderError::UnparsableValue(ErrorDataSource::Preamble, s, err).into())
383     }
384 
read_bitmap_header(&mut self, encoding: SampleEncoding) -> ImageResult<BitmapHeader>385     fn read_bitmap_header(&mut self, encoding: SampleEncoding) -> ImageResult<BitmapHeader> {
386         let width = self.read_next_u32()?;
387         let height = self.read_next_u32()?;
388         Ok(BitmapHeader {
389             encoding,
390             width,
391             height,
392         })
393     }
394 
read_graymap_header(&mut self, encoding: SampleEncoding) -> ImageResult<GraymapHeader>395     fn read_graymap_header(&mut self, encoding: SampleEncoding) -> ImageResult<GraymapHeader> {
396         self.read_pixmap_header(encoding).map(
397             |PixmapHeader {
398                  encoding,
399                  width,
400                  height,
401                  maxval,
402              }| GraymapHeader {
403                 encoding,
404                 width,
405                 height,
406                 maxwhite: maxval,
407             },
408         )
409     }
410 
read_pixmap_header(&mut self, encoding: SampleEncoding) -> ImageResult<PixmapHeader>411     fn read_pixmap_header(&mut self, encoding: SampleEncoding) -> ImageResult<PixmapHeader> {
412         let width = self.read_next_u32()?;
413         let height = self.read_next_u32()?;
414         let maxval = self.read_next_u32()?;
415         Ok(PixmapHeader {
416             encoding,
417             width,
418             height,
419             maxval,
420         })
421     }
422 
read_arbitrary_header(&mut self) -> ImageResult<ArbitraryHeader>423     fn read_arbitrary_header(&mut self) -> ImageResult<ArbitraryHeader> {
424         fn parse_single_value_line(line_val: &mut Option<u32>, rest: &str, line: PnmHeaderLine) -> ImageResult<()> {
425             if line_val.is_some() {
426                 return Err(DecoderError::HeaderLineDuplicated(line).into());
427             } else {
428                 let v = rest.trim().parse().map_err(|err| DecoderError::UnparsableValue(ErrorDataSource::Line(line), rest.to_owned(), err))?;
429                 *line_val = Some(v);
430                 Ok(())
431             }
432         }
433 
434         match self.bytes().next() {
435             None => return Err(ImageError::IoError(io::ErrorKind::UnexpectedEof.into())),
436             Some(Err(io)) => return Err(ImageError::IoError(io)),
437             Some(Ok(b'\n')) => (),
438             Some(Ok(c)) => return Err(DecoderError::NotNewlineAfterP7Magic(c).into()),
439         }
440 
441         let mut line = String::new();
442         let mut height: Option<u32> = None;
443         let mut width: Option<u32> = None;
444         let mut depth: Option<u32> = None;
445         let mut maxval: Option<u32> = None;
446         let mut tupltype: Option<String> = None;
447         loop {
448             line.truncate(0);
449             let len = self.read_line(&mut line)?;
450             if len == 0 {
451                 return Err(DecoderError::UnexpectedPnmHeaderEnd.into());
452             }
453             if line.as_bytes()[0] == b'#' {
454                 continue;
455             }
456             if !line.is_ascii() {
457                 return Err(DecoderError::NonAsciiLineInPamHeader.into());
458             }
459             #[allow(deprecated)]
460             let (identifier, rest) = line.trim_left()
461                 .split_at(line.find(char::is_whitespace).unwrap_or_else(|| line.len()));
462             match identifier {
463                 "ENDHDR" => break,
464                 "HEIGHT" => parse_single_value_line(&mut height, rest, PnmHeaderLine::Height)?,
465                 "WIDTH" => parse_single_value_line(&mut width, rest, PnmHeaderLine::Width)?,
466                 "DEPTH" => parse_single_value_line(&mut depth, rest, PnmHeaderLine::Depth)?,
467                 "MAXVAL" => parse_single_value_line(&mut maxval, rest, PnmHeaderLine::Maxval)?,
468                 "TUPLTYPE" => {
469                     let identifier = rest.trim();
470                     if tupltype.is_some() {
471                         let appended = tupltype.take().map(|mut v| {
472                             v.push(' ');
473                             v.push_str(identifier);
474                             v
475                         });
476                         tupltype = appended;
477                     } else {
478                         tupltype = Some(identifier.to_string());
479                     }
480                 }
481                 _ => return Err(DecoderError::HeaderLineUnknown(identifier.to_string()).into()),
482             }
483         }
484 
485         let (h, w, d, m) = match (height, width, depth, maxval) {
486             (Some(h), Some(w), Some(d), Some(m)) => (h, w, d, m),
487             _ => return Err(DecoderError::HeaderLineMissing { height, width, depth, maxval }.into()),
488         };
489 
490         let tupltype = match tupltype {
491             None => None,
492             Some(ref t) if t == "BLACKANDWHITE" => Some(ArbitraryTuplType::BlackAndWhite),
493             Some(ref t) if t == "BLACKANDWHITE_ALPHA" => Some(ArbitraryTuplType::BlackAndWhiteAlpha),
494             Some(ref t) if t == "GRAYSCALE" => Some(ArbitraryTuplType::Grayscale),
495             Some(ref t) if t == "GRAYSCALE_ALPHA" => Some(ArbitraryTuplType::GrayscaleAlpha),
496             Some(ref t) if t == "RGB" => Some(ArbitraryTuplType::RGB),
497             Some(ref t) if t == "RGB_ALPHA" => Some(ArbitraryTuplType::RGBAlpha),
498             Some(other) => Some(ArbitraryTuplType::Custom(other)),
499         };
500 
501         Ok(ArbitraryHeader {
502             height: h,
503             width: w,
504             depth: d,
505             maxval: m,
506             tupltype,
507         })
508     }
509 }
510 
511 impl<R: Read> HeaderReader for BufReader<R> {}
512 
513 /// Wrapper struct around a `Cursor<Vec<u8>>`
514 pub struct PnmReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
515 impl<R> Read for PnmReader<R> {
read(&mut self, buf: &mut [u8]) -> io::Result<usize>516     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
517         self.0.read(buf)
518     }
read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize>519     fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
520         if self.0.position() == 0 && buf.is_empty() {
521             mem::swap(buf, self.0.get_mut());
522             Ok(buf.len())
523         } else {
524             self.0.read_to_end(buf)
525         }
526     }
527 }
528 
529 impl<'a, R: 'a + Read> ImageDecoder<'a> for PnmDecoder<R> {
530     type Reader = PnmReader<R>;
531 
dimensions(&self) -> (u32, u32)532     fn dimensions(&self) -> (u32, u32) {
533         (self.header.width(), self.header.height())
534     }
535 
color_type(&self) -> ColorType536     fn color_type(&self) -> ColorType {
537         match self.tuple {
538             TupleType::PbmBit => ColorType::L8,
539             TupleType::BWBit => ColorType::L8,
540             TupleType::GrayU8 => ColorType::L8,
541             TupleType::GrayU16 => ColorType::L16,
542             TupleType::RGBU8 => ColorType::Rgb8,
543             TupleType::RGBU16 => ColorType::Rgb16,
544         }
545     }
546 
original_color_type(&self) -> ExtendedColorType547     fn original_color_type(&self) -> ExtendedColorType {
548         match self.tuple {
549             TupleType::PbmBit => ExtendedColorType::L1,
550             TupleType::BWBit => ExtendedColorType::L1,
551             TupleType::GrayU8 => ExtendedColorType::L8,
552             TupleType::GrayU16 => ExtendedColorType::L16,
553             TupleType::RGBU8 => ExtendedColorType::Rgb8,
554             TupleType::RGBU16 => ExtendedColorType::Rgb16,
555         }
556     }
557 
into_reader(self) -> ImageResult<Self::Reader>558     fn into_reader(self) -> ImageResult<Self::Reader> {
559         Ok(PnmReader(Cursor::new(image::decoder_to_vec(self)?), PhantomData))
560     }
561 
read_image(mut self, buf: &mut [u8]) -> ImageResult<()>562     fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> {
563         assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));
564         buf.copy_from_slice(&match self.tuple {
565             TupleType::PbmBit => self.read_samples::<PbmBit>(1),
566             TupleType::BWBit => self.read_samples::<BWBit>(1),
567             TupleType::RGBU8 => self.read_samples::<U8>(3),
568             TupleType::RGBU16 => self.read_samples::<U16>(3),
569             TupleType::GrayU8 => self.read_samples::<U8>(1),
570             TupleType::GrayU16 => self.read_samples::<U16>(1),
571         }?);
572         Ok(())
573     }
574 }
575 
576 impl<R: Read> PnmDecoder<R> {
read_samples<S: Sample>(&mut self, components: u32) -> ImageResult<Vec<u8>>577     fn read_samples<S: Sample>(&mut self, components: u32) -> ImageResult<Vec<u8>> {
578         match self.subtype().sample_encoding() {
579             SampleEncoding::Binary => {
580                 let width = self.header.width();
581                 let height = self.header.height();
582                 let bytecount = S::bytelen(width, height, components)?;
583                 let mut bytes = vec![];
584 
585                 self.reader
586                     .by_ref()
587                     // This conversion is potentially lossy but unlikely and in that case we error
588                     // later anyways.
589                     .take(bytecount as u64)
590                     .read_to_end(&mut bytes)?;
591 
592                 if bytes.len() != bytecount {
593                     return Err(DecoderError::InputTooShort.into());
594                 }
595 
596                 let samples = S::from_bytes(&bytes, width, height, components)?;
597                 Ok(samples)
598             }
599             SampleEncoding::Ascii => {
600                 let samples = self.read_ascii::<S>(components)?;
601                 Ok(samples)
602             }
603         }
604     }
605 
read_ascii<Basic: Sample>(&mut self, components: u32) -> ImageResult<Vec<u8>>606     fn read_ascii<Basic: Sample>(&mut self, components: u32) -> ImageResult<Vec<u8>> {
607         Basic::from_ascii(&mut self.reader, self.header.width(), self.header.height(), components)
608     }
609 
610     /// Get the pnm subtype, depending on the magic constant contained in the header
subtype(&self) -> PNMSubtype611     pub fn subtype(&self) -> PNMSubtype {
612         self.header.subtype()
613     }
614 }
615 
read_separated_ascii<T: FromStr<Err = ParseIntError>>(reader: &mut dyn Read) -> ImageResult<T> where T::Err: Display616 fn read_separated_ascii<T: FromStr<Err = ParseIntError>>(reader: &mut dyn Read) -> ImageResult<T>
617     where T::Err: Display
618 {
619     let is_separator = |v: &u8| match *v {
620         b'\t' | b'\n' | b'\x0b' | b'\x0c' | b'\r' | b' ' => true,
621         _ => false,
622     };
623 
624     let token = reader
625         .bytes()
626         .skip_while(|v| v.as_ref().ok().map(&is_separator).unwrap_or(false))
627         .take_while(|v| v.as_ref().ok().map(|c| !is_separator(c)).unwrap_or(false))
628         .collect::<Result<Vec<u8>, _>>()?;
629 
630     if !token.is_ascii() {
631         return Err(DecoderError::NonAsciiSample.into());
632     }
633 
634     let string = str::from_utf8(&token)
635         // We checked the precondition ourselves a few lines before with `token.is_ascii()`.
636         .unwrap_or_else(|_| unreachable!("Only ASCII characters should be decoded"));
637 
638     string.parse()
639           .map_err(|err| DecoderError::UnparsableValue(ErrorDataSource::Sample, string.to_owned(), err).into())
640 }
641 
642 impl Sample for U8 {
bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize>643     fn bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize> {
644         Ok((width * height * samples) as usize)
645     }
646 
from_bytes( bytes: &[u8], width: u32, height: u32, samples: u32, ) -> ImageResult<Vec<u8>>647     fn from_bytes(
648         bytes: &[u8],
649         width: u32,
650         height: u32,
651         samples: u32,
652     ) -> ImageResult<Vec<u8>> {
653         assert_eq!(bytes.len(), Self::bytelen(width, height, samples).unwrap());
654         Ok(bytes.to_vec())
655     }
656 
from_ascii( reader: &mut dyn Read, width: u32, height: u32, samples: u32, ) -> ImageResult<Vec<u8>>657     fn from_ascii(
658         reader: &mut dyn Read,
659         width: u32,
660         height: u32,
661         samples: u32,
662     ) -> ImageResult<Vec<u8>> {
663         (0..width*height*samples)
664             .map(|_| read_separated_ascii(reader))
665             .collect()
666     }
667 }
668 
669 impl Sample for U16 {
bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize>670     fn bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize> {
671         Ok((width * height * samples * 2) as usize)
672     }
673 
from_bytes( bytes: &[u8], width: u32, height: u32, samples: u32, ) -> ImageResult<Vec<u8>>674     fn from_bytes(
675         bytes: &[u8],
676         width: u32,
677         height: u32,
678         samples: u32,
679     ) -> ImageResult<Vec<u8>> {
680         assert_eq!(bytes.len(), Self::bytelen(width, height, samples).unwrap());
681 
682         let mut buffer = bytes.to_vec();
683         for chunk in buffer.chunks_mut(2) {
684             let v = BigEndian::read_u16(chunk);
685             NativeEndian::write_u16(chunk, v);
686         }
687         Ok(buffer)
688     }
689 
from_ascii( reader: &mut dyn Read, width: u32, height: u32, samples: u32, ) -> ImageResult<Vec<u8>>690     fn from_ascii(
691         reader: &mut dyn Read,
692         width: u32,
693         height: u32,
694         samples: u32,
695     ) -> ImageResult<Vec<u8>> {
696         let mut buffer = vec![0; (width * height * samples * 2) as usize];
697         for i in 0..(width*height*samples) as usize {
698             let v = read_separated_ascii::<u16>(reader)?;
699             NativeEndian::write_u16(&mut buffer[2*i..][..2], v);
700         }
701         Ok(buffer)
702     }
703 }
704 
705 // The image is encoded in rows of bits, high order bits first. Any bits beyond the row bits should
706 // be ignored. Also, contrary to rgb, black pixels are encoded as a 1 while white is 0. This will
707 // need to be reversed for the grayscale output.
708 impl Sample for PbmBit {
bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize>709     fn bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize> {
710         let count = width * samples;
711         let linelen = (count / 8) + ((count % 8) != 0) as u32;
712         Ok((linelen * height) as usize)
713     }
714 
from_bytes( bytes: &[u8], width: u32, height: u32, samples: u32, ) -> ImageResult<Vec<u8>>715     fn from_bytes(
716         bytes: &[u8],
717         width: u32,
718         height: u32,
719         samples: u32,
720     ) -> ImageResult<Vec<u8>> {
721         assert_eq!(bytes.len(), Self::bytelen(width, height, samples).unwrap());
722 
723         let mut expanded = utils::expand_bits(1, width * samples, bytes);
724         for b in expanded.iter_mut() {
725             *b = !*b;
726         }
727         Ok(expanded)
728     }
729 
from_ascii( reader: &mut dyn Read, width: u32, height: u32, samples: u32, ) -> ImageResult<Vec<u8>>730     fn from_ascii(
731         reader: &mut dyn Read,
732         width: u32,
733         height: u32,
734         samples: u32,
735     ) -> ImageResult<Vec<u8>> {
736         let count = (width*height*samples) as usize;
737         let raw_samples = reader.bytes()
738             .filter_map(|ascii| match ascii {
739                 Ok(b'0') => Some(Ok(1)),
740                 Ok(b'1') => Some(Ok(0)),
741                 Err(err) => Some(Err(ImageError::IoError(err))),
742                 Ok(b'\t')
743                 | Ok(b'\n')
744                 | Ok(b'\x0b')
745                 | Ok(b'\x0c')
746                 | Ok(b'\r')
747                 | Ok(b' ') => None,
748                 Ok(c) => Some(Err(DecoderError::UnexpectedByteInRaster(c).into())),
749             })
750             .take(count)
751             .collect::<ImageResult<Vec<u8>>>()?;
752 
753         if raw_samples.len() < count {
754             return Err(DecoderError::InputTooShort.into());
755         }
756 
757         Ok(raw_samples)
758     }
759 }
760 
761 // Encoded just like a normal U8 but we check the values.
762 impl Sample for BWBit {
bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize>763     fn bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize> {
764         U8::bytelen(width, height, samples)
765     }
766 
from_bytes( bytes: &[u8], width: u32, height: u32, samples: u32, ) -> ImageResult<Vec<u8>>767     fn from_bytes(
768         bytes: &[u8],
769         width: u32,
770         height: u32,
771         samples: u32,
772     ) -> ImageResult<Vec<u8>> {
773         assert_eq!(bytes.len(), Self::bytelen(width, height, samples).unwrap());
774 
775         let values = U8::from_bytes(bytes, width, height, samples)?;
776         if let Some(val) = values.iter().find(|&val| *val > 1) {
777             return Err(DecoderError::SampleOutOfBounds(*val).into());
778         }
779         Ok(values)
780     }
781 
from_ascii( _reader: &mut dyn Read, _width: u32, _height: u32, _samples: u32, ) -> ImageResult<Vec<u8>>782     fn from_ascii(
783         _reader: &mut dyn Read,
784         _width: u32,
785         _height: u32,
786         _samples: u32,
787     ) -> ImageResult<Vec<u8>> {
788         unreachable!("BW bits from anymaps are never encoded as ASCII")
789     }
790 }
791 
792 impl DecodableImageHeader for BitmapHeader {
tuple_type(&self) -> ImageResult<TupleType>793     fn tuple_type(&self) -> ImageResult<TupleType> {
794         Ok(TupleType::PbmBit)
795     }
796 }
797 
798 impl DecodableImageHeader for GraymapHeader {
tuple_type(&self) -> ImageResult<TupleType>799     fn tuple_type(&self) -> ImageResult<TupleType> {
800         match self.maxwhite {
801             v if v <= 0xFF => Ok(TupleType::GrayU8),
802             v if v <= 0xFFFF => Ok(TupleType::GrayU16),
803             _ => Err(DecoderError::MaxvalTooBig(self.maxwhite).into()),
804         }
805     }
806 }
807 
808 impl DecodableImageHeader for PixmapHeader {
tuple_type(&self) -> ImageResult<TupleType>809     fn tuple_type(&self) -> ImageResult<TupleType> {
810         match self.maxval {
811             v if v <= 0xFF => Ok(TupleType::RGBU8),
812             v if v <= 0xFFFF => Ok(TupleType::RGBU16),
813             _ => Err(DecoderError::MaxvalTooBig(self.maxval).into()),
814         }
815     }
816 }
817 
818 impl DecodableImageHeader for ArbitraryHeader {
tuple_type(&self) -> ImageResult<TupleType>819     fn tuple_type(&self) -> ImageResult<TupleType> {
820         match self.tupltype {
821             None if self.depth == 1 => Ok(TupleType::GrayU8),
822             None if self.depth == 2 => Err(ImageError::Unsupported(UnsupportedError::from_format_and_kind(
823                 ImageFormat::Pnm.into(),
824                 UnsupportedErrorKind::Color(ExtendedColorType::La8),
825             ))),
826             None if self.depth == 3 => Ok(TupleType::RGBU8),
827             None if self.depth == 4 => Err(ImageError::Unsupported(UnsupportedError::from_format_and_kind(
828                 ImageFormat::Pnm.into(),
829                 UnsupportedErrorKind::Color(ExtendedColorType::Rgba8),
830             ))),
831 
832             Some(ArbitraryTuplType::BlackAndWhite) if self.maxval == 1 && self.depth == 1 => {
833                 Ok(TupleType::BWBit)
834             }
835             Some(ArbitraryTuplType::BlackAndWhite) => Err(DecoderError::InvalidDepthOrMaxval {
836                 tuple_type: ArbitraryTuplType::BlackAndWhite,
837                 maxval: self.maxval,
838                 depth: self.depth,
839             }.into()),
840 
841             Some(ArbitraryTuplType::Grayscale) if self.depth == 1 && self.maxval <= 0xFF => {
842                 Ok(TupleType::GrayU8)
843             }
844             Some(ArbitraryTuplType::Grayscale) if self.depth <= 1 && self.maxval <= 0xFFFF => {
845                 Ok(TupleType::GrayU16)
846             }
847             Some(ArbitraryTuplType::Grayscale) => Err(DecoderError::InvalidDepthOrMaxval {
848                 tuple_type: ArbitraryTuplType::Grayscale,
849                 maxval: self.maxval,
850                 depth: self.depth,
851             }.into()),
852 
853             Some(ArbitraryTuplType::RGB) if self.depth == 3 && self.maxval <= 0xFF => {
854                 Ok(TupleType::RGBU8)
855             }
856             Some(ArbitraryTuplType::RGB) if self.depth == 3 && self.maxval <= 0xFFFF => {
857                 Ok(TupleType::RGBU16)
858             }
859             Some(ArbitraryTuplType::RGB) => Err(DecoderError::InvalidDepth {
860                 tuple_type: ArbitraryTuplType::RGB,
861                 depth: self.depth,
862             }.into()),
863 
864             Some(ArbitraryTuplType::BlackAndWhiteAlpha) => {
865                 Err(ImageError::Unsupported(UnsupportedError::from_format_and_kind(
866                     ImageFormat::Pnm.into(),
867                     UnsupportedErrorKind::GenericFeature(
868                         format!("Color type {}", ArbitraryTuplType::BlackAndWhiteAlpha.name())),
869                 )))
870             }
871             Some(ArbitraryTuplType::GrayscaleAlpha) => Err(ImageError::Unsupported(
872                 UnsupportedError::from_format_and_kind(
873                     ImageFormat::Pnm.into(),
874                     UnsupportedErrorKind::Color(ExtendedColorType::La8),
875                 ),
876             )),
877             Some(ArbitraryTuplType::RGBAlpha) => Err(ImageError::Unsupported(
878                 UnsupportedError::from_format_and_kind(
879                     ImageFormat::Pnm.into(),
880                     UnsupportedErrorKind::Color(ExtendedColorType::Rgba8),
881                 ),
882             )),
883             Some(ArbitraryTuplType::Custom(ref custom)) => Err(ImageError::Unsupported(
884                 UnsupportedError::from_format_and_kind(
885                     ImageFormat::Pnm.into(),
886                     UnsupportedErrorKind::GenericFeature(format!(
887                         "Tuple type {:?}",
888                         custom
889                     )),
890                 ),
891             )),
892             None => Err(DecoderError::TupleTypeUnrecognised.into()),
893         }
894     }
895 }
896 
897 #[cfg(test)]
898 mod tests {
899     use super::*;
900     /// Tests reading of a valid blackandwhite pam
901     #[test]
pam_blackandwhite()902     fn pam_blackandwhite() {
903         let pamdata = b"P7
904 WIDTH 4
905 HEIGHT 4
906 DEPTH 1
907 MAXVAL 1
908 TUPLTYPE BLACKANDWHITE
909 # Comment line
910 ENDHDR
911 \x01\x00\x00\x01\x01\x00\x00\x01\x01\x00\x00\x01\x01\x00\x00\x01";
912         let decoder = PnmDecoder::new(&pamdata[..]).unwrap();
913         assert_eq!(decoder.color_type(), ColorType::L8);
914         assert_eq!(decoder.original_color_type(), ExtendedColorType::L1);
915         assert_eq!(decoder.dimensions(), (4, 4));
916         assert_eq!(decoder.subtype(), PNMSubtype::ArbitraryMap);
917 
918         let mut image = vec![0; decoder.total_bytes() as usize];
919         decoder.read_image(&mut image).unwrap();
920         assert_eq!(
921             image,
922             vec![0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00,
923                  0x00, 0x01]
924         );
925         match PnmDecoder::new(&pamdata[..]).unwrap().into_inner() {
926             (
927                 _,
928                 PNMHeader {
929                     decoded:
930                         HeaderRecord::Arbitrary(ArbitraryHeader {
931                             width: 4,
932                             height: 4,
933                             maxval: 1,
934                             depth: 1,
935                             tupltype: Some(ArbitraryTuplType::BlackAndWhite),
936                         }),
937                     encoded: _,
938                 },
939             ) => (),
940             _ => panic!("Decoded header is incorrect"),
941         }
942     }
943 
944     /// Tests reading of a valid grayscale pam
945     #[test]
pam_grayscale()946     fn pam_grayscale() {
947         let pamdata = b"P7
948 WIDTH 4
949 HEIGHT 4
950 DEPTH 1
951 MAXVAL 255
952 TUPLTYPE GRAYSCALE
953 # Comment line
954 ENDHDR
955 \xde\xad\xbe\xef\xde\xad\xbe\xef\xde\xad\xbe\xef\xde\xad\xbe\xef";
956         let decoder = PnmDecoder::new(&pamdata[..]).unwrap();
957         assert_eq!(decoder.color_type(), ColorType::L8);
958         assert_eq!(decoder.dimensions(), (4, 4));
959         assert_eq!(decoder.subtype(), PNMSubtype::ArbitraryMap);
960 
961         let mut image = vec![0; decoder.total_bytes() as usize];
962         decoder.read_image(&mut image).unwrap();
963         assert_eq!(
964             image,
965             vec![0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad,
966                  0xbe, 0xef]
967         );
968         match PnmDecoder::new(&pamdata[..]).unwrap().into_inner() {
969             (
970                 _,
971                 PNMHeader {
972                     decoded:
973                         HeaderRecord::Arbitrary(ArbitraryHeader {
974                             width: 4,
975                             height: 4,
976                             depth: 1,
977                             maxval: 255,
978                             tupltype: Some(ArbitraryTuplType::Grayscale),
979                         }),
980                     encoded: _,
981                 },
982             ) => (),
983             _ => panic!("Decoded header is incorrect"),
984         }
985     }
986 
987     /// Tests reading of a valid rgb pam
988     #[test]
pam_rgb()989     fn pam_rgb() {
990         let pamdata = b"P7
991 # Comment line
992 MAXVAL 255
993 TUPLTYPE RGB
994 DEPTH 3
995 WIDTH 2
996 HEIGHT 2
997 ENDHDR
998 \xde\xad\xbe\xef\xde\xad\xbe\xef\xde\xad\xbe\xef";
999         let decoder = PnmDecoder::new(&pamdata[..]).unwrap();
1000         assert_eq!(decoder.color_type(), ColorType::Rgb8);
1001         assert_eq!(decoder.dimensions(), (2, 2));
1002         assert_eq!(decoder.subtype(), PNMSubtype::ArbitraryMap);
1003 
1004         let mut image = vec![0; decoder.total_bytes() as usize];
1005         decoder.read_image(&mut image).unwrap();
1006         assert_eq!(image,
1007                    vec![0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef]);
1008         match PnmDecoder::new(&pamdata[..]).unwrap().into_inner() {
1009             (
1010                 _,
1011                 PNMHeader {
1012                     decoded:
1013                         HeaderRecord::Arbitrary(ArbitraryHeader {
1014                             maxval: 255,
1015                             tupltype: Some(ArbitraryTuplType::RGB),
1016                             depth: 3,
1017                             width: 2,
1018                             height: 2,
1019                         }),
1020                     encoded: _,
1021                 },
1022             ) => (),
1023             _ => panic!("Decoded header is incorrect"),
1024         }
1025     }
1026 
1027     #[test]
pbm_binary()1028     fn pbm_binary() {
1029         // The data contains two rows of the image (each line is padded to the full byte). For
1030         // comments on its format, see documentation of `impl SampleType for PbmBit`.
1031         let pbmbinary = [&b"P4 6 2\n"[..], &[0b01101100 as u8, 0b10110111]].concat();
1032         let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap();
1033         assert_eq!(decoder.color_type(), ColorType::L8);
1034         assert_eq!(decoder.original_color_type(), ExtendedColorType::L1);
1035         assert_eq!(decoder.dimensions(), (6, 2));
1036         assert_eq!(
1037             decoder.subtype(),
1038             PNMSubtype::Bitmap(SampleEncoding::Binary)
1039         );
1040         let mut image = vec![0; decoder.total_bytes() as usize];
1041         decoder.read_image(&mut image).unwrap();
1042         assert_eq!(image, vec![255, 0, 0, 255, 0, 0, 0, 255, 0, 0, 255, 0]);
1043         match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() {
1044             (
1045                 _,
1046                 PNMHeader {
1047                     decoded:
1048                         HeaderRecord::Bitmap(BitmapHeader {
1049                             encoding: SampleEncoding::Binary,
1050                             width: 6,
1051                             height: 2,
1052                         }),
1053                     encoded: _,
1054                 },
1055             ) => (),
1056             _ => panic!("Decoded header is incorrect"),
1057         }
1058     }
1059 
1060     /// A previous inifite loop.
1061     #[test]
pbm_binary_ascii_termination()1062     fn pbm_binary_ascii_termination() {
1063         use std::io::{Cursor, Error, ErrorKind, Read, Result};
1064         struct FailRead(Cursor<&'static [u8]>);
1065 
1066         impl Read for FailRead {
1067             fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
1068                 match self.0.read(buf) {
1069                     Ok(n) if n > 0 => Ok(n),
1070                     _ => Err(Error::new(
1071                         ErrorKind::BrokenPipe,
1072                         "Simulated broken pipe error"
1073                     )),
1074                 }
1075             }
1076         }
1077 
1078         let pbmbinary = FailRead(Cursor::new(b"P1 1 1\n"));
1079 
1080         let decoder = PnmDecoder::new(pbmbinary).unwrap();
1081         let mut image = vec![0; decoder.total_bytes() as usize];
1082         decoder.read_image(&mut image).expect_err("Image is malformed");
1083     }
1084 
1085     #[test]
pbm_ascii()1086     fn pbm_ascii() {
1087         // The data contains two rows of the image (each line is padded to the full byte). For
1088         // comments on its format, see documentation of `impl SampleType for PbmBit`.  Tests all
1089         // whitespace characters that should be allowed (the 6 characters according to POSIX).
1090         let pbmbinary = b"P1 6 2\n 0 1 1 0 1 1\n1 0 1 1 0\t\n\x0b\x0c\r1";
1091         let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap();
1092         assert_eq!(decoder.color_type(), ColorType::L8);
1093         assert_eq!(decoder.original_color_type(), ExtendedColorType::L1);
1094         assert_eq!(decoder.dimensions(), (6, 2));
1095         assert_eq!(decoder.subtype(), PNMSubtype::Bitmap(SampleEncoding::Ascii));
1096 
1097         let mut image = vec![0; decoder.total_bytes() as usize];
1098         decoder.read_image(&mut image).unwrap();
1099         assert_eq!(image, vec![1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0]);
1100         match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() {
1101             (
1102                 _,
1103                 PNMHeader {
1104                     decoded:
1105                         HeaderRecord::Bitmap(BitmapHeader {
1106                             encoding: SampleEncoding::Ascii,
1107                             width: 6,
1108                             height: 2,
1109                         }),
1110                     encoded: _,
1111                 },
1112             ) => (),
1113             _ => panic!("Decoded header is incorrect"),
1114         }
1115     }
1116 
1117     #[test]
pbm_ascii_nospace()1118     fn pbm_ascii_nospace() {
1119         // The data contains two rows of the image (each line is padded to the full byte). Notably,
1120         // it is completely within specification for the ascii data not to contain separating
1121         // whitespace for the pbm format or any mix.
1122         let pbmbinary = b"P1 6 2\n011011101101";
1123         let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap();
1124         assert_eq!(decoder.color_type(), ColorType::L8);
1125         assert_eq!(decoder.original_color_type(), ExtendedColorType::L1);
1126         assert_eq!(decoder.dimensions(), (6, 2));
1127         assert_eq!(decoder.subtype(), PNMSubtype::Bitmap(SampleEncoding::Ascii));
1128 
1129         let mut image = vec![0; decoder.total_bytes() as usize];
1130         decoder.read_image(&mut image).unwrap();
1131         assert_eq!(image, vec![1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0]);
1132         match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() {
1133             (
1134                 _,
1135                 PNMHeader {
1136                     decoded:
1137                         HeaderRecord::Bitmap(BitmapHeader {
1138                             encoding: SampleEncoding::Ascii,
1139                             width: 6,
1140                             height: 2,
1141                         }),
1142                     encoded: _,
1143                 },
1144             ) => (),
1145             _ => panic!("Decoded header is incorrect"),
1146         }
1147     }
1148 
1149     #[test]
pgm_binary()1150     fn pgm_binary() {
1151         // The data contains two rows of the image (each line is padded to the full byte). For
1152         // comments on its format, see documentation of `impl SampleType for PbmBit`.
1153         let elements = (0..16).collect::<Vec<_>>();
1154         let pbmbinary = [&b"P5 4 4 255\n"[..], &elements].concat();
1155         let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap();
1156         assert_eq!(decoder.color_type(), ColorType::L8);
1157         assert_eq!(decoder.dimensions(), (4, 4));
1158         assert_eq!(
1159             decoder.subtype(),
1160             PNMSubtype::Graymap(SampleEncoding::Binary)
1161         );
1162         let mut image = vec![0; decoder.total_bytes() as usize];
1163         decoder.read_image(&mut image).unwrap();
1164         assert_eq!(image, elements);
1165         match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() {
1166             (
1167                 _,
1168                 PNMHeader {
1169                     decoded:
1170                         HeaderRecord::Graymap(GraymapHeader {
1171                             encoding: SampleEncoding::Binary,
1172                             width: 4,
1173                             height: 4,
1174                             maxwhite: 255,
1175                         }),
1176                     encoded: _,
1177                 },
1178             ) => (),
1179             _ => panic!("Decoded header is incorrect"),
1180         }
1181     }
1182 
1183     #[test]
pgm_ascii()1184     fn pgm_ascii() {
1185         // The data contains two rows of the image (each line is padded to the full byte). For
1186         // comments on its format, see documentation of `impl SampleType for PbmBit`.
1187         let pbmbinary = b"P2 4 4 255\n 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15";
1188         let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap();
1189         assert_eq!(decoder.color_type(), ColorType::L8);
1190         assert_eq!(decoder.dimensions(), (4, 4));
1191         assert_eq!(
1192             decoder.subtype(),
1193             PNMSubtype::Graymap(SampleEncoding::Ascii)
1194         );
1195         let mut image = vec![0; decoder.total_bytes() as usize];
1196         decoder.read_image(&mut image).unwrap();
1197         assert_eq!(image, (0..16).collect::<Vec<_>>());
1198         match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() {
1199             (
1200                 _,
1201                 PNMHeader {
1202                     decoded:
1203                         HeaderRecord::Graymap(GraymapHeader {
1204                             encoding: SampleEncoding::Ascii,
1205                             width: 4,
1206                             height: 4,
1207                             maxwhite: 255,
1208                         }),
1209                     encoded: _,
1210                 },
1211             ) => (),
1212             _ => panic!("Decoded header is incorrect"),
1213         }
1214     }
1215 }
1216