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(format:ImageFormat::Pnm.into(), err: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: &ParseIntError) => 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(data: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: &PnmHeaderLine) => l.fmt(f),
218 ErrorDataSource::Preamble => f.write_str(data:"number in preamble"),
219 ErrorDataSource::Sample => f.write_str(data:"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(x: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: impl Fn(&u8) -> bool = |v: &u8| matches! { *v, b'\t' | b'\n' | b'\x0b' | b'\x0c' | b'\r' | b' ' };
708
709 let token: Vec = readerimpl Iterator>
710 .bytes()
711 .skip_while(|v: &Result| v.as_ref().ok().map(is_separator).unwrap_or(default:false))
712 .take_while(|v: &Result| v.as_ref().ok().map(|c| !is_separator(c)).unwrap_or(default:false))
713 .collect::<Result<Vec<u8>, _>>()?;
714
715 if !token.is_ascii() {
716 return Err(DecoderError::NonAsciiSample.into());
717 }
718
719 let string: &str = 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: ParseIntError| {
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(src:bytes);
733 Ok(())
734 }
735
736 fn from_ascii(reader: &mut dyn Read, output_buf: &mut [u8]) -> ImageResult<()> {
737 for b: &mut u8 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(src:bytes);
749 for chunk: &mut [u8] in output_buf.chunks_exact_mut(chunk_size:2) {
750 let v: u16 = BigEndian::read_u16(buf:chunk);
751 NativeEndian::write_u16(buf:chunk, n:v);
752 }
753 Ok(())
754 }
755
756 fn from_ascii(reader: &mut dyn Read, output_buf: &mut [u8]) -> ImageResult<()> {
757 for chunk: &mut [u8] in output_buf.chunks_exact_mut(chunk_size:2) {
758 let v: u16 = read_separated_ascii::<u16>(reader)?;
759 NativeEndian::write_u16(buf:chunk, n: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: &u8) = output_buf.iter().find(|&val: &u8| *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: u32 if v <= 0xFF => Ok(TupleType::GrayU8),
835 v: u32 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: u32 if v <= 0xFF => Ok(TupleType::RGBU8),
846 v: u32 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}
1316