image/codecs/pnm/
decoder.rs

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