1use std::error;
2use std::fmt::{self, Display};
3use std::io::{self, Read};
4use std::mem::size_of;
5use std::num::ParseIntError;
6use std::str;
7
8use super::{ArbitraryHeader, ArbitraryTuplType, BitmapHeader, GraymapHeader, PixmapHeader};
9use super::{HeaderRecord, PnmHeader, PnmSubtype, SampleEncoding};
10use crate::color::{ColorType, ExtendedColorType};
11use crate::error::{
12 DecodingError, ImageError, ImageResult, UnsupportedError, UnsupportedErrorKind,
13};
14use crate::{utils, ImageDecoder, ImageFormat};
15
16#[derive(Debug, Clone)]
18enum DecoderError {
19 PnmMagicInvalid([u8; 2]),
21 UnparsableValue(ErrorDataSource, String, ParseIntError),
23
24 NonAsciiByteInHeader(u8),
26 NonAsciiLineInPamHeader,
28 InvalidDigit(ErrorDataSource),
30
31 NotNewlineAfterP7Magic(u8),
33 UnexpectedPnmHeaderEnd,
35
36 HeaderLineDuplicated(PnmHeaderLine),
38 HeaderLineUnknown(String),
40 #[allow(missing_docs)]
44 HeaderLineMissing {
45 height: Option<u32>,
46 width: Option<u32>,
47 depth: Option<u32>,
48 maxval: Option<u32>,
49 },
50
51 InputTooShort,
53 UnexpectedByteInRaster(u8),
55 SampleOutOfBounds(u8),
57 MaxvalZero,
59 MaxvalTooBig(u32),
61
62 InvalidDepthOrMaxval {
64 tuple_type: ArbitraryTuplType,
65 depth: u32,
66 maxval: u32,
67 },
68 InvalidDepth {
70 tuple_type: ArbitraryTuplType,
71 depth: u32,
72 },
73 TupleTypeUnrecognised,
75
76 Overflow(ErrorDataSource),
78}
79
80impl Display for DecoderError {
81 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82 match self {
83 DecoderError::PnmMagicInvalid(magic) => f.write_fmt(format_args!(
84 "Expected magic constant for PNM: P1..P7, got [{:#04X?}, {:#04X?}]",
85 magic[0], magic[1]
86 )),
87 DecoderError::UnparsableValue(src, data, err) => {
88 f.write_fmt(format_args!("Error parsing {data:?} as {src}: {err}"))
89 }
90
91 DecoderError::NonAsciiByteInHeader(c) => {
92 f.write_fmt(format_args!("Non-ASCII character {c:#04X?} in header"))
93 }
94 DecoderError::NonAsciiLineInPamHeader => f.write_str("Non-ASCII line in PAM header"),
95 DecoderError::InvalidDigit(src) => {
96 f.write_fmt(format_args!("Non-ASCII-digit character when parsing number in {src}"))
97 }
98
99 DecoderError::NotNewlineAfterP7Magic(c) => f.write_fmt(format_args!(
100 "Expected newline after P7 magic, got {c:#04X?}"
101 )),
102 DecoderError::UnexpectedPnmHeaderEnd => f.write_str("Unexpected end of PNM header"),
103
104 DecoderError::HeaderLineDuplicated(line) => {
105 f.write_fmt(format_args!("Duplicate {line} line"))
106 }
107 DecoderError::HeaderLineUnknown(identifier) => f.write_fmt(format_args!(
108 "Unknown header line with identifier {identifier:?}"
109 )),
110 DecoderError::HeaderLineMissing {
111 height,
112 width,
113 depth,
114 maxval,
115 } => f.write_fmt(format_args!(
116 "Missing header line: have height={height:?}, width={width:?}, depth={depth:?}, maxval={maxval:?}"
117 )),
118
119 DecoderError::InputTooShort => {
120 f.write_str("Not enough data was provided to the Decoder to decode the image")
121 }
122 DecoderError::UnexpectedByteInRaster(c) => f.write_fmt(format_args!(
123 "Unexpected character {c:#04X?} within sample raster"
124 )),
125 DecoderError::SampleOutOfBounds(val) => {
126 f.write_fmt(format_args!("Sample value {val} outside of bounds"))
127 }
128 DecoderError::MaxvalZero => f.write_str("Image MAXVAL is zero"),
129 DecoderError::MaxvalTooBig(maxval) => {
130 f.write_fmt(format_args!("Image MAXVAL exceeds {}: {}", 0xFFFF, maxval))
131 }
132
133 DecoderError::InvalidDepthOrMaxval {
134 tuple_type,
135 depth,
136 maxval,
137 } => f.write_fmt(format_args!(
138 "Invalid depth ({}) or maxval ({}) for tuple type {}",
139 depth,
140 maxval,
141 tuple_type.name()
142 )),
143 DecoderError::InvalidDepth { tuple_type, depth } => f.write_fmt(format_args!(
144 "Invalid depth ({}) for tuple type {}",
145 depth,
146 tuple_type.name()
147 )),
148 DecoderError::TupleTypeUnrecognised => f.write_str("Tuple type not recognized"),
149 DecoderError::Overflow(src) => f.write_fmt(format_args!(
150 "Overflow when parsing integer in {src}"
151 ))
152 }
153 }
154}
155
156impl From<DecoderError> for ImageError {
159 fn from(e: DecoderError) -> ImageError {
160 ImageError::Decoding(DecodingError::new(ImageFormat::Pnm.into(), e))
161 }
162}
163
164impl error::Error for DecoderError {
165 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
166 match self {
167 DecoderError::UnparsableValue(_, _, err) => Some(err),
168 _ => None,
169 }
170 }
171}
172
173#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
175enum PnmHeaderLine {
176 Height,
178 Width,
180 Depth,
182 Maxval,
184}
185
186impl Display for PnmHeaderLine {
187 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
188 f.write_str(match self {
189 PnmHeaderLine::Height => "HEIGHT",
190 PnmHeaderLine::Width => "WIDTH",
191 PnmHeaderLine::Depth => "DEPTH",
192 PnmHeaderLine::Maxval => "MAXVAL",
193 })
194 }
195}
196
197#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
199enum ErrorDataSource {
200 Line(PnmHeaderLine),
202 Preamble,
204 Sample,
206}
207
208impl Display for ErrorDataSource {
209 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210 match self {
211 ErrorDataSource::Line(l) => l.fmt(f),
212 ErrorDataSource::Preamble => f.write_str("number in preamble"),
213 ErrorDataSource::Sample => f.write_str("sample"),
214 }
215 }
216}
217
218#[derive(Clone, Copy)]
220enum TupleType {
221 PbmBit,
222 BWBit,
223 BWAlphaBit,
224 GrayU8,
225 GrayAlphaU8,
226 GrayU16,
227 GrayAlphaU16,
228 RGBU8,
229 RGBAlphaU8,
230 RGBU16,
231 RGBAlphaU16,
232}
233
234trait Sample {
235 type Representation;
236
237 fn sample_size() -> u32 {
239 size_of::<Self::Representation>() as u32
240 }
241 fn from_bytes(
242 reader: &mut dyn Read,
243 output_buf: &mut [u8],
244 width: u32,
245 height: u32,
246 components: u32,
247 ) -> ImageResult<()>;
248 fn from_ascii(reader: &mut dyn Read, output_buf: &mut [u8]) -> ImageResult<()>;
249}
250
251struct U8;
252struct U16;
253struct PbmBit;
254struct BWBit;
255
256trait DecodableImageHeader {
257 fn tuple_type(&self) -> ImageResult<TupleType>;
258}
259
260pub struct PnmDecoder<R> {
262 reader: R,
263 header: PnmHeader,
264 tuple: TupleType,
265}
266
267impl<R: Read> PnmDecoder<R> {
268 pub fn new(mut buffered_read: R) -> ImageResult<PnmDecoder<R>> {
270 let magic = buffered_read.read_magic_constant()?;
271
272 let subtype = match magic {
273 [b'P', b'1'] => PnmSubtype::Bitmap(SampleEncoding::Ascii),
274 [b'P', b'2'] => PnmSubtype::Graymap(SampleEncoding::Ascii),
275 [b'P', b'3'] => PnmSubtype::Pixmap(SampleEncoding::Ascii),
276 [b'P', b'4'] => PnmSubtype::Bitmap(SampleEncoding::Binary),
277 [b'P', b'5'] => PnmSubtype::Graymap(SampleEncoding::Binary),
278 [b'P', b'6'] => PnmSubtype::Pixmap(SampleEncoding::Binary),
279 [b'P', b'7'] => PnmSubtype::ArbitraryMap,
280 _ => return Err(DecoderError::PnmMagicInvalid(magic).into()),
281 };
282
283 let decoder = match subtype {
284 PnmSubtype::Bitmap(enc) => PnmDecoder::read_bitmap_header(buffered_read, enc),
285 PnmSubtype::Graymap(enc) => PnmDecoder::read_graymap_header(buffered_read, enc),
286 PnmSubtype::Pixmap(enc) => PnmDecoder::read_pixmap_header(buffered_read, enc),
287 PnmSubtype::ArbitraryMap => PnmDecoder::read_arbitrary_header(buffered_read),
288 }?;
289
290 if utils::check_dimension_overflow(
291 decoder.dimensions().0,
292 decoder.dimensions().1,
293 decoder.color_type().bytes_per_pixel(),
294 ) {
295 return Err(ImageError::Unsupported(
296 UnsupportedError::from_format_and_kind(
297 ImageFormat::Pnm.into(),
298 UnsupportedErrorKind::GenericFeature(format!(
299 "Image dimensions ({}x{}) are too large",
300 decoder.dimensions().0,
301 decoder.dimensions().1
302 )),
303 ),
304 ));
305 }
306
307 Ok(decoder)
308 }
309
310 pub fn header(&self) -> &PnmHeader {
312 &self.header
313 }
314
315 pub fn into_inner(self) -> (R, PnmHeader) {
317 (self.reader, self.header)
318 }
319
320 fn read_bitmap_header(mut reader: R, encoding: SampleEncoding) -> ImageResult<PnmDecoder<R>> {
321 let header = reader.read_bitmap_header(encoding)?;
322 Ok(PnmDecoder {
323 reader,
324 tuple: TupleType::PbmBit,
325 header: PnmHeader {
326 decoded: HeaderRecord::Bitmap(header),
327 encoded: None,
328 },
329 })
330 }
331
332 fn read_graymap_header(mut reader: R, encoding: SampleEncoding) -> ImageResult<PnmDecoder<R>> {
333 let header = reader.read_graymap_header(encoding)?;
334 let tuple_type = header.tuple_type()?;
335 Ok(PnmDecoder {
336 reader,
337 tuple: tuple_type,
338 header: PnmHeader {
339 decoded: HeaderRecord::Graymap(header),
340 encoded: None,
341 },
342 })
343 }
344
345 fn read_pixmap_header(mut reader: R, encoding: SampleEncoding) -> ImageResult<PnmDecoder<R>> {
346 let header = reader.read_pixmap_header(encoding)?;
347 let tuple_type = header.tuple_type()?;
348 Ok(PnmDecoder {
349 reader,
350 tuple: tuple_type,
351 header: PnmHeader {
352 decoded: HeaderRecord::Pixmap(header),
353 encoded: None,
354 },
355 })
356 }
357
358 fn read_arbitrary_header(mut reader: R) -> ImageResult<PnmDecoder<R>> {
359 let header = reader.read_arbitrary_header()?;
360 let tuple_type = header.tuple_type()?;
361 Ok(PnmDecoder {
362 reader,
363 tuple: tuple_type,
364 header: PnmHeader {
365 decoded: HeaderRecord::Arbitrary(header),
366 encoded: None,
367 },
368 })
369 }
370}
371
372trait HeaderReader: Read {
373 fn read_magic_constant(&mut self) -> ImageResult<[u8; 2]> {
375 let mut magic: [u8; 2] = [0, 0];
376 self.read_exact(&mut magic)?;
377 Ok(magic)
378 }
379
380 fn read_next_u32(&mut self) -> ImageResult<u32> {
383 #[allow(clippy::unbuffered_bytes)]
385 let mark_comments = self.bytes().scan(true, |partof, read| {
386 let byte = match read {
387 Err(err) => return Some((*partof, Err(err))),
388 Ok(byte) => byte,
389 };
390 let cur_enabled = *partof && byte != b'#';
391 let next_enabled = cur_enabled || (byte == b'\r' || byte == b'\n');
392 *partof = next_enabled;
393 Some((cur_enabled, Ok(byte)))
394 });
395
396 let mut value: u32 = 0;
399 let mut found_digit = false;
400
401 for (_, byte) in mark_comments.filter(|e| e.0) {
402 match byte {
403 Ok(b'\t' | b'\n' | b'\x0b' | b'\x0c' | b'\r' | b' ') => {
404 if found_digit {
405 break; }
407 }
408 Ok(byte) if !byte.is_ascii() => {
409 return Err(DecoderError::NonAsciiByteInHeader(byte).into())
410 }
411 Ok(byte) => {
412 let digit = match byte {
413 b'0'..=b'9' => u32::from(byte - b'0'),
414 _ => {
415 return Err(DecoderError::InvalidDigit(ErrorDataSource::Preamble).into())
416 }
417 };
418 value = value
419 .checked_mul(10)
420 .ok_or(DecoderError::Overflow(ErrorDataSource::Preamble))?;
421 value = value
422 .checked_add(digit)
423 .ok_or(DecoderError::Overflow(ErrorDataSource::Preamble))?;
424 found_digit = true;
425 }
426 Err(_) => break,
427 }
428 }
429
430 if !found_digit {
431 return Err(ImageError::IoError(io::ErrorKind::UnexpectedEof.into()));
432 }
433
434 Ok(value)
435 }
436
437 fn read_next_line(&mut self) -> ImageResult<String> {
438 let mut buffer = Vec::new();
439 loop {
440 let mut byte = [0];
441 if self.read(&mut byte)? == 0 || byte[0] == b'\n' {
442 break;
443 }
444 buffer.push(byte[0]);
445 }
446
447 String::from_utf8(buffer)
448 .map_err(|e| ImageError::Decoding(DecodingError::new(ImageFormat::Pnm.into(), e)))
449 }
450
451 fn read_bitmap_header(&mut self, encoding: SampleEncoding) -> ImageResult<BitmapHeader> {
452 let width = self.read_next_u32()?;
453 let height = self.read_next_u32()?;
454 Ok(BitmapHeader {
455 encoding,
456 height,
457 width,
458 })
459 }
460
461 fn read_graymap_header(&mut self, encoding: SampleEncoding) -> ImageResult<GraymapHeader> {
462 self.read_pixmap_header(encoding).map(
463 |PixmapHeader {
464 encoding,
465 width,
466 height,
467 maxval,
468 }| GraymapHeader {
469 encoding,
470 width,
471 height,
472 maxwhite: maxval,
473 },
474 )
475 }
476
477 fn read_pixmap_header(&mut self, encoding: SampleEncoding) -> ImageResult<PixmapHeader> {
478 let width = self.read_next_u32()?;
479 let height = self.read_next_u32()?;
480 let maxval = self.read_next_u32()?;
481 Ok(PixmapHeader {
482 encoding,
483 height,
484 width,
485 maxval,
486 })
487 }
488
489 fn read_arbitrary_header(&mut self) -> ImageResult<ArbitraryHeader> {
490 fn parse_single_value_line(
491 line_val: &mut Option<u32>,
492 rest: &str,
493 line: PnmHeaderLine,
494 ) -> ImageResult<()> {
495 if line_val.is_some() {
496 Err(DecoderError::HeaderLineDuplicated(line).into())
497 } else {
498 let v = rest.trim().parse().map_err(|err| {
499 DecoderError::UnparsableValue(ErrorDataSource::Line(line), rest.to_owned(), err)
500 })?;
501 *line_val = Some(v);
502 Ok(())
503 }
504 }
505
506 #[allow(clippy::unbuffered_bytes)]
507 match self.bytes().next() {
508 None => return Err(ImageError::IoError(io::ErrorKind::UnexpectedEof.into())),
509 Some(Err(io)) => return Err(ImageError::IoError(io)),
510 Some(Ok(b'\n')) => (),
511 Some(Ok(c)) => return Err(DecoderError::NotNewlineAfterP7Magic(c).into()),
512 }
513
514 let mut line;
515 let mut height: Option<u32> = None;
516 let mut width: Option<u32> = None;
517 let mut depth: Option<u32> = None;
518 let mut maxval: Option<u32> = None;
519 let mut tupltype: Option<String> = None;
520 loop {
521 line = self.read_next_line()?;
522 if line.is_empty() {
523 return Err(DecoderError::UnexpectedPnmHeaderEnd.into());
524 }
525 if line.as_bytes()[0] == b'#' {
526 continue;
527 }
528 if !line.is_ascii() {
529 return Err(DecoderError::NonAsciiLineInPamHeader.into());
530 }
531 #[allow(deprecated)]
532 let (identifier, rest) = line
533 .trim_left()
534 .split_at(line.find(char::is_whitespace).unwrap_or(line.len()));
535 match identifier {
536 "ENDHDR" => break,
537 "HEIGHT" => parse_single_value_line(&mut height, rest, PnmHeaderLine::Height)?,
538 "WIDTH" => parse_single_value_line(&mut width, rest, PnmHeaderLine::Width)?,
539 "DEPTH" => parse_single_value_line(&mut depth, rest, PnmHeaderLine::Depth)?,
540 "MAXVAL" => parse_single_value_line(&mut maxval, rest, PnmHeaderLine::Maxval)?,
541 "TUPLTYPE" => {
542 let identifier = rest.trim();
543 if tupltype.is_some() {
544 let appended = tupltype.take().map(|mut v| {
545 v.push(' ');
546 v.push_str(identifier);
547 v
548 });
549 tupltype = appended;
550 } else {
551 tupltype = Some(identifier.to_string());
552 }
553 }
554 _ => return Err(DecoderError::HeaderLineUnknown(identifier.to_string()).into()),
555 }
556 }
557
558 let (Some(h), Some(w), Some(d), Some(m)) = (height, width, depth, maxval) else {
559 return Err(DecoderError::HeaderLineMissing {
560 height,
561 width,
562 depth,
563 maxval,
564 }
565 .into());
566 };
567
568 let tupltype = match tupltype {
569 None => None,
570 Some(ref t) if t == "BLACKANDWHITE" => Some(ArbitraryTuplType::BlackAndWhite),
571 Some(ref t) if t == "BLACKANDWHITE_ALPHA" => {
572 Some(ArbitraryTuplType::BlackAndWhiteAlpha)
573 }
574 Some(ref t) if t == "GRAYSCALE" => Some(ArbitraryTuplType::Grayscale),
575 Some(ref t) if t == "GRAYSCALE_ALPHA" => Some(ArbitraryTuplType::GrayscaleAlpha),
576 Some(ref t) if t == "RGB" => Some(ArbitraryTuplType::RGB),
577 Some(ref t) if t == "RGB_ALPHA" => Some(ArbitraryTuplType::RGBAlpha),
578 Some(other) => Some(ArbitraryTuplType::Custom(other)),
579 };
580
581 Ok(ArbitraryHeader {
582 height: h,
583 width: w,
584 depth: d,
585 maxval: m,
586 tupltype,
587 })
588 }
589}
590
591impl<R> HeaderReader for R where R: Read {}
592
593impl<R: Read> ImageDecoder for PnmDecoder<R> {
594 fn dimensions(&self) -> (u32, u32) {
595 (self.header.width(), self.header.height())
596 }
597
598 fn color_type(&self) -> ColorType {
599 match self.tuple {
600 TupleType::PbmBit => ColorType::L8,
601 TupleType::BWBit => ColorType::L8,
602 TupleType::BWAlphaBit => ColorType::La8,
603 TupleType::GrayU8 => ColorType::L8,
604 TupleType::GrayAlphaU8 => ColorType::La8,
605 TupleType::GrayU16 => ColorType::L16,
606 TupleType::GrayAlphaU16 => ColorType::La16,
607 TupleType::RGBU8 => ColorType::Rgb8,
608 TupleType::RGBAlphaU8 => ColorType::Rgba8,
609 TupleType::RGBU16 => ColorType::Rgb16,
610 TupleType::RGBAlphaU16 => ColorType::Rgba16,
611 }
612 }
613
614 fn original_color_type(&self) -> ExtendedColorType {
615 match self.tuple {
616 TupleType::PbmBit => ExtendedColorType::L1,
617 TupleType::BWBit => ExtendedColorType::L1,
618 TupleType::BWAlphaBit => ExtendedColorType::La1,
619 TupleType::GrayU8 => ExtendedColorType::L8,
620 TupleType::GrayAlphaU8 => ExtendedColorType::La8,
621 TupleType::GrayU16 => ExtendedColorType::L16,
622 TupleType::GrayAlphaU16 => ExtendedColorType::La16,
623 TupleType::RGBU8 => ExtendedColorType::Rgb8,
624 TupleType::RGBAlphaU8 => ExtendedColorType::Rgba8,
625 TupleType::RGBU16 => ExtendedColorType::Rgb16,
626 TupleType::RGBAlphaU16 => ExtendedColorType::Rgba16,
627 }
628 }
629
630 fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> {
631 assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));
632 match self.tuple {
633 TupleType::PbmBit => self.read_samples::<PbmBit>(1, buf),
634 TupleType::BWBit => self.read_samples::<BWBit>(1, buf),
635 TupleType::BWAlphaBit => self.read_samples::<BWBit>(2, buf),
636 TupleType::RGBU8 => self.read_samples::<U8>(3, buf),
637 TupleType::RGBAlphaU8 => self.read_samples::<U8>(4, buf),
638 TupleType::RGBU16 => self.read_samples::<U16>(3, buf),
639 TupleType::RGBAlphaU16 => self.read_samples::<U16>(4, buf),
640 TupleType::GrayU8 => self.read_samples::<U8>(1, buf),
641 TupleType::GrayAlphaU8 => self.read_samples::<U8>(2, buf),
642 TupleType::GrayU16 => self.read_samples::<U16>(1, buf),
643 TupleType::GrayAlphaU16 => self.read_samples::<U16>(2, buf),
644 }
645 }
646
647 fn read_image_boxed(self: Box<Self>, buf: &mut [u8]) -> ImageResult<()> {
648 (*self).read_image(buf)
649 }
650}
651
652impl<R: Read> PnmDecoder<R> {
653 fn read_samples<S: Sample>(&mut self, components: u32, buf: &mut [u8]) -> ImageResult<()> {
654 match self.subtype().sample_encoding() {
655 SampleEncoding::Binary => {
656 S::from_bytes(
657 &mut self.reader,
658 buf,
659 self.header.width(),
660 self.header.height(),
661 components,
662 )?;
663 }
664 SampleEncoding::Ascii => {
665 S::from_ascii(&mut self.reader, buf)?;
666 }
667 }
668
669 let current_sample_max = self.header.maximal_sample();
671 let target_sample_max = 256_u32.pow(S::sample_size()) - 1;
672
673 if current_sample_max != target_sample_max {
674 let factor = target_sample_max as f32 / current_sample_max as f32;
675
676 if S::sample_size() == 1 {
677 for v in buf.iter_mut() {
678 *v = (f32::from(*v) * factor).round() as u8;
679 }
680 } else if S::sample_size() == 2 {
681 for chunk in buf.as_chunks_mut::<2>().0.iter_mut() {
682 let v = (f32::from(u16::from_ne_bytes(*chunk)) * factor).round() as u16;
683 chunk.copy_from_slice(&v.to_ne_bytes());
684 }
685 }
686 }
687
688 Ok(())
689 }
690
691 pub fn subtype(&self) -> PnmSubtype {
693 self.header.subtype()
694 }
695}
696
697fn read_separated_ascii<T: TryFrom<u16>>(reader: &mut dyn Read) -> ImageResult<T> {
698 let is_separator = |v: &u8| matches!(*v, b'\t' | b'\n' | b'\x0b' | b'\x0c' | b'\r' | b' ');
699
700 let mut v: u16 = 0;
701 let mut had_any = false;
702 #[allow(clippy::unbuffered_bytes)]
703 for rc in reader
704 .bytes()
705 .skip_while(|v| v.as_ref().ok().is_some_and(is_separator))
706 .take_while(|v| v.as_ref().ok().is_some_and(|c| !is_separator(c)))
707 {
708 let c = rc?;
709 let digit = match c {
710 b'0'..=b'9' => u16::from(c - b'0'),
711 _ => return Err(DecoderError::InvalidDigit(ErrorDataSource::Sample).into()),
712 };
713 v = v
714 .checked_mul(10)
715 .ok_or(DecoderError::Overflow(ErrorDataSource::Sample))?;
716 v = v
717 .checked_add(digit)
718 .ok_or(DecoderError::Overflow(ErrorDataSource::Sample))?;
719 had_any = true;
720 }
721
722 if !had_any {
723 return Err(DecoderError::InputTooShort.into());
724 }
725
726 Ok(T::try_from(v).or(Err(DecoderError::Overflow(ErrorDataSource::Sample)))?)
727}
728
729impl Sample for U8 {
730 type Representation = u8;
731 fn from_bytes(
732 reader: &mut dyn Read,
733 output_buf: &mut [u8],
734 _width: u32,
735 _height: u32,
736 _components: u32,
737 ) -> ImageResult<()> {
738 reader.read_exact(output_buf)?;
739 Ok(())
740 }
741
742 fn from_ascii(reader: &mut dyn Read, output_buf: &mut [u8]) -> ImageResult<()> {
743 for b in output_buf {
744 *b = read_separated_ascii(reader)?;
745 }
746 Ok(())
747 }
748}
749
750impl Sample for U16 {
751 type Representation = u16;
752
753 fn from_bytes(
754 reader: &mut dyn Read,
755 output_buf: &mut [u8],
756 _width: u32,
757 _height: u32,
758 _components: u32,
759 ) -> ImageResult<()> {
760 reader.read_exact(output_buf)?;
761 for chunk in output_buf.as_chunks_mut::<2>().0.iter_mut() {
762 let v = u16::from_be_bytes(*chunk);
763 chunk.copy_from_slice(&v.to_ne_bytes());
764 }
765 Ok(())
766 }
767
768 fn from_ascii(reader: &mut dyn Read, output_buf: &mut [u8]) -> ImageResult<()> {
769 for chunk in output_buf.as_chunks_mut::<2>().0.iter_mut() {
770 let v = read_separated_ascii::<u16>(reader)?;
771 chunk.copy_from_slice(&v.to_ne_bytes());
772 }
773 Ok(())
774 }
775}
776
777impl Sample for PbmBit {
781 type Representation = u8;
782
783 fn from_bytes(
784 reader: &mut dyn Read,
785 output_buf: &mut [u8],
786 width: u32,
787 height: u32,
788 components: u32,
789 ) -> ImageResult<()> {
790 assert!(components == 1);
791
792 let width: usize = width
793 .try_into()
794 .map_err(|_| DecoderError::Overflow(ErrorDataSource::Sample))?;
795 let height: usize = height
796 .try_into()
797 .map_err(|_| DecoderError::Overflow(ErrorDataSource::Sample))?;
798 assert!(width.checked_mul(height) == Some(output_buf.len()));
799
800 let linelen = width.div_ceil(8);
801 let bytecount = height
802 .checked_mul(linelen)
803 .filter(|l| *l <= output_buf.len())
804 .expect("PBM packed data is never longer than unpacked");
805
806 reader.read_exact(&mut output_buf[..bytecount])?;
807
808 for y in (0..height).rev() {
813 for x in (0..width).rev() {
814 let shift = 7 - (x % 8);
815 let v = (output_buf[y * linelen + x / 8] >> shift) & 0x1;
816 output_buf[y * width + x] = 1 - v;
817 }
818 }
819 Ok(())
820 }
821
822 fn from_ascii(reader: &mut dyn Read, output_buf: &mut [u8]) -> ImageResult<()> {
823 #[allow(clippy::unbuffered_bytes)]
824 let mut bytes = reader.bytes();
825 for b in output_buf {
826 loop {
827 let byte = bytes
828 .next()
829 .ok_or_else::<ImageError, _>(|| DecoderError::InputTooShort.into())??;
830 match byte {
831 b'\t' | b'\n' | b'\x0b' | b'\x0c' | b'\r' | b' ' => continue,
832 b'0' => *b = 255,
833 b'1' => *b = 0,
834 c => return Err(DecoderError::UnexpectedByteInRaster(c).into()),
835 }
836 break;
837 }
838 }
839
840 Ok(())
841 }
842}
843
844impl Sample for BWBit {
846 type Representation = u8;
847
848 fn from_bytes(
849 reader: &mut dyn Read,
850 output_buf: &mut [u8],
851 width: u32,
852 height: u32,
853 components: u32,
854 ) -> ImageResult<()> {
855 U8::from_bytes(reader, output_buf, width, height, components)?;
856 if let Some(val) = output_buf.iter().find(|&val| *val > 1) {
857 return Err(DecoderError::SampleOutOfBounds(*val).into());
858 }
859 Ok(())
860 }
861
862 fn from_ascii(_reader: &mut dyn Read, _output_buf: &mut [u8]) -> ImageResult<()> {
863 unreachable!("BW bits from anymaps are never encoded as ASCII")
864 }
865}
866
867impl DecodableImageHeader for BitmapHeader {
868 fn tuple_type(&self) -> ImageResult<TupleType> {
869 Ok(TupleType::PbmBit)
870 }
871}
872
873impl DecodableImageHeader for GraymapHeader {
874 fn tuple_type(&self) -> ImageResult<TupleType> {
875 match self.maxwhite {
876 0 => Err(DecoderError::MaxvalZero.into()),
877 v if v <= 0xFF => Ok(TupleType::GrayU8),
878 v if v <= 0xFFFF => Ok(TupleType::GrayU16),
879 _ => Err(DecoderError::MaxvalTooBig(self.maxwhite).into()),
880 }
881 }
882}
883
884impl DecodableImageHeader for PixmapHeader {
885 fn tuple_type(&self) -> ImageResult<TupleType> {
886 match self.maxval {
887 0 => Err(DecoderError::MaxvalZero.into()),
888 v if v <= 0xFF => Ok(TupleType::RGBU8),
889 v if v <= 0xFFFF => Ok(TupleType::RGBU16),
890 _ => Err(DecoderError::MaxvalTooBig(self.maxval).into()),
891 }
892 }
893}
894
895impl DecodableImageHeader for ArbitraryHeader {
896 fn tuple_type(&self) -> ImageResult<TupleType> {
897 match self.tupltype {
898 _ if self.maxval == 0 => Err(DecoderError::MaxvalZero.into()),
899 None if self.depth == 1 => Ok(TupleType::GrayU8),
900 None if self.depth == 2 => Ok(TupleType::GrayAlphaU8),
901 None if self.depth == 3 => Ok(TupleType::RGBU8),
902 None if self.depth == 4 => Ok(TupleType::RGBAlphaU8),
903
904 Some(ArbitraryTuplType::BlackAndWhite) if self.maxval == 1 && self.depth == 1 => {
905 Ok(TupleType::BWBit)
906 }
907 Some(ArbitraryTuplType::BlackAndWhite) => Err(DecoderError::InvalidDepthOrMaxval {
908 tuple_type: ArbitraryTuplType::BlackAndWhite,
909 maxval: self.maxval,
910 depth: self.depth,
911 }
912 .into()),
913
914 Some(ArbitraryTuplType::Grayscale) if self.depth == 1 && self.maxval <= 0xFF => {
915 Ok(TupleType::GrayU8)
916 }
917 Some(ArbitraryTuplType::Grayscale) if self.depth <= 1 && self.maxval <= 0xFFFF => {
918 Ok(TupleType::GrayU16)
919 }
920 Some(ArbitraryTuplType::Grayscale) => Err(DecoderError::InvalidDepthOrMaxval {
921 tuple_type: ArbitraryTuplType::Grayscale,
922 maxval: self.maxval,
923 depth: self.depth,
924 }
925 .into()),
926
927 Some(ArbitraryTuplType::RGB) if self.depth == 3 && self.maxval <= 0xFF => {
928 Ok(TupleType::RGBU8)
929 }
930 Some(ArbitraryTuplType::RGB) if self.depth == 3 && self.maxval <= 0xFFFF => {
931 Ok(TupleType::RGBU16)
932 }
933 Some(ArbitraryTuplType::RGB) => Err(DecoderError::InvalidDepth {
934 tuple_type: ArbitraryTuplType::RGB,
935 depth: self.depth,
936 }
937 .into()),
938
939 Some(ArbitraryTuplType::BlackAndWhiteAlpha) if self.depth == 2 && self.maxval == 1 => {
940 Ok(TupleType::BWAlphaBit)
941 }
942 Some(ArbitraryTuplType::BlackAndWhiteAlpha) => {
943 Err(DecoderError::InvalidDepthOrMaxval {
944 tuple_type: ArbitraryTuplType::BlackAndWhiteAlpha,
945 maxval: self.maxval,
946 depth: self.depth,
947 }
948 .into())
949 }
950
951 Some(ArbitraryTuplType::GrayscaleAlpha) if self.depth == 2 && self.maxval <= 0xFF => {
952 Ok(TupleType::GrayAlphaU8)
953 }
954 Some(ArbitraryTuplType::GrayscaleAlpha) if self.depth == 2 && self.maxval <= 0xFFFF => {
955 Ok(TupleType::GrayAlphaU16)
956 }
957 Some(ArbitraryTuplType::GrayscaleAlpha) => Err(DecoderError::InvalidDepth {
958 tuple_type: ArbitraryTuplType::GrayscaleAlpha,
959 depth: self.depth,
960 }
961 .into()),
962
963 Some(ArbitraryTuplType::RGBAlpha) if self.depth == 4 && self.maxval <= 0xFF => {
964 Ok(TupleType::RGBAlphaU8)
965 }
966 Some(ArbitraryTuplType::RGBAlpha) if self.depth == 4 && self.maxval <= 0xFFFF => {
967 Ok(TupleType::RGBAlphaU16)
968 }
969 Some(ArbitraryTuplType::RGBAlpha) => Err(DecoderError::InvalidDepth {
970 tuple_type: ArbitraryTuplType::RGBAlpha,
971 depth: self.depth,
972 }
973 .into()),
974
975 Some(ArbitraryTuplType::Custom(ref custom)) => Err(ImageError::Unsupported(
976 UnsupportedError::from_format_and_kind(
977 ImageFormat::Pnm.into(),
978 UnsupportedErrorKind::GenericFeature(format!("Tuple type {custom:?}")),
979 ),
980 )),
981 None => Err(DecoderError::TupleTypeUnrecognised.into()),
982 }
983 }
984}
985
986#[cfg(test)]
987mod tests {
988 use super::*;
989 #[test]
991 fn pam_blackandwhite() {
992 let pamdata = b"P7
993WIDTH 4
994HEIGHT 4
995DEPTH 1
996MAXVAL 1
997TUPLTYPE BLACKANDWHITE
998# Comment line
999ENDHDR
1000\x01\x00\x00\x01\x01\x00\x00\x01\x01\x00\x00\x01\x01\x00\x00\x01";
1001 let decoder = PnmDecoder::new(&pamdata[..]).unwrap();
1002 assert_eq!(decoder.color_type(), ColorType::L8);
1003 assert_eq!(decoder.original_color_type(), ExtendedColorType::L1);
1004 assert_eq!(decoder.dimensions(), (4, 4));
1005 assert_eq!(decoder.subtype(), PnmSubtype::ArbitraryMap);
1006
1007 let mut image = vec![0; decoder.total_bytes() as usize];
1008 decoder.read_image(&mut image).unwrap();
1009 assert_eq!(
1010 image,
1011 vec![
1012 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
1013 0x00, 0xFF
1014 ]
1015 );
1016 match PnmDecoder::new(&pamdata[..]).unwrap().into_inner() {
1017 (
1018 _,
1019 PnmHeader {
1020 decoded:
1021 HeaderRecord::Arbitrary(ArbitraryHeader {
1022 width: 4,
1023 height: 4,
1024 maxval: 1,
1025 depth: 1,
1026 tupltype: Some(ArbitraryTuplType::BlackAndWhite),
1027 }),
1028 encoded: _,
1029 },
1030 ) => (),
1031 _ => panic!("Decoded header is incorrect"),
1032 }
1033 }
1034
1035 #[test]
1037 fn pam_blackandwhite_alpha() {
1038 let pamdata = b"P7
1039WIDTH 2
1040HEIGHT 2
1041DEPTH 2
1042MAXVAL 1
1043TUPLTYPE BLACKANDWHITE_ALPHA
1044# Comment line
1045ENDHDR
1046\x01\x00\x00\x01\x01\x00\x00\x01";
1047 let decoder = PnmDecoder::new(&pamdata[..]).unwrap();
1048 assert_eq!(decoder.color_type(), ColorType::La8);
1049 assert_eq!(decoder.original_color_type(), ExtendedColorType::La1);
1050 assert_eq!(decoder.dimensions(), (2, 2));
1051 assert_eq!(decoder.subtype(), PnmSubtype::ArbitraryMap);
1052
1053 let mut image = vec![0; decoder.total_bytes() as usize];
1054 decoder.read_image(&mut image).unwrap();
1055 assert_eq!(image, vec![0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF,]);
1056 match PnmDecoder::new(&pamdata[..]).unwrap().into_inner() {
1057 (
1058 _,
1059 PnmHeader {
1060 decoded:
1061 HeaderRecord::Arbitrary(ArbitraryHeader {
1062 width: 2,
1063 height: 2,
1064 maxval: 1,
1065 depth: 2,
1066 tupltype: Some(ArbitraryTuplType::BlackAndWhiteAlpha),
1067 }),
1068 encoded: _,
1069 },
1070 ) => (),
1071 _ => panic!("Decoded header is incorrect"),
1072 }
1073 }
1074
1075 #[test]
1077 fn pam_grayscale() {
1078 let pamdata = b"P7
1079WIDTH 4
1080HEIGHT 4
1081DEPTH 1
1082MAXVAL 255
1083TUPLTYPE GRAYSCALE
1084# Comment line
1085ENDHDR
1086\xde\xad\xbe\xef\xde\xad\xbe\xef\xde\xad\xbe\xef\xde\xad\xbe\xef";
1087 let decoder = PnmDecoder::new(&pamdata[..]).unwrap();
1088 assert_eq!(decoder.color_type(), ColorType::L8);
1089 assert_eq!(decoder.dimensions(), (4, 4));
1090 assert_eq!(decoder.subtype(), PnmSubtype::ArbitraryMap);
1091
1092 let mut image = vec![0; decoder.total_bytes() as usize];
1093 decoder.read_image(&mut image).unwrap();
1094 assert_eq!(
1095 image,
1096 vec![
1097 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad,
1098 0xbe, 0xef
1099 ]
1100 );
1101 match PnmDecoder::new(&pamdata[..]).unwrap().into_inner() {
1102 (
1103 _,
1104 PnmHeader {
1105 decoded:
1106 HeaderRecord::Arbitrary(ArbitraryHeader {
1107 width: 4,
1108 height: 4,
1109 depth: 1,
1110 maxval: 255,
1111 tupltype: Some(ArbitraryTuplType::Grayscale),
1112 }),
1113 encoded: _,
1114 },
1115 ) => (),
1116 _ => panic!("Decoded header is incorrect"),
1117 }
1118 }
1119
1120 #[test]
1122 fn pam_grayscale_alpha() {
1123 let pamdata = b"P7
1124HEIGHT 1
1125WIDTH 2
1126MAXVAL 65535
1127DEPTH 2
1128TUPLTYPE GRAYSCALE_ALPHA
1129# Comment line
1130ENDHDR
1131\xdc\xba\x32\x10\xdc\xba\x32\x10";
1132 let decoder = PnmDecoder::new(&pamdata[..]).unwrap();
1133 assert_eq!(decoder.color_type(), ColorType::La16);
1134 assert_eq!(decoder.original_color_type(), ExtendedColorType::La16);
1135 assert_eq!(decoder.dimensions(), (2, 1));
1136 assert_eq!(decoder.subtype(), PnmSubtype::ArbitraryMap);
1137
1138 let mut image = vec![0; decoder.total_bytes() as usize];
1139 decoder.read_image(&mut image).unwrap();
1140 assert_eq!(
1141 image,
1142 [
1143 u16::to_ne_bytes(0xdcba),
1144 u16::to_ne_bytes(0x3210),
1145 u16::to_ne_bytes(0xdcba),
1146 u16::to_ne_bytes(0x3210)
1147 ]
1148 .concat()
1149 );
1150 match PnmDecoder::new(&pamdata[..]).unwrap().into_inner() {
1151 (
1152 _,
1153 PnmHeader {
1154 decoded:
1155 HeaderRecord::Arbitrary(ArbitraryHeader {
1156 width: 2,
1157 height: 1,
1158 maxval: 65535,
1159 depth: 2,
1160 tupltype: Some(ArbitraryTuplType::GrayscaleAlpha),
1161 }),
1162 encoded: _,
1163 },
1164 ) => (),
1165 _ => panic!("Decoded header is incorrect"),
1166 }
1167 }
1168
1169 #[test]
1171 fn pam_rgb() {
1172 let pamdata = b"P7
1173# Comment line
1174MAXVAL 255
1175TUPLTYPE RGB
1176DEPTH 3
1177WIDTH 2
1178HEIGHT 2
1179ENDHDR
1180\xde\xad\xbe\xef\xde\xad\xbe\xef\xde\xad\xbe\xef";
1181 let decoder = PnmDecoder::new(&pamdata[..]).unwrap();
1182 assert_eq!(decoder.color_type(), ColorType::Rgb8);
1183 assert_eq!(decoder.dimensions(), (2, 2));
1184 assert_eq!(decoder.subtype(), PnmSubtype::ArbitraryMap);
1185
1186 let mut image = vec![0; decoder.total_bytes() as usize];
1187 decoder.read_image(&mut image).unwrap();
1188 assert_eq!(
1189 image,
1190 vec![0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef]
1191 );
1192 match PnmDecoder::new(&pamdata[..]).unwrap().into_inner() {
1193 (
1194 _,
1195 PnmHeader {
1196 decoded:
1197 HeaderRecord::Arbitrary(ArbitraryHeader {
1198 maxval: 255,
1199 tupltype: Some(ArbitraryTuplType::RGB),
1200 depth: 3,
1201 width: 2,
1202 height: 2,
1203 }),
1204 encoded: _,
1205 },
1206 ) => (),
1207 _ => panic!("Decoded header is incorrect"),
1208 }
1209 }
1210
1211 #[test]
1213 fn pam_rgb_alpha() {
1214 let pamdata = b"P7
1215WIDTH 1
1216HEIGHT 3
1217DEPTH 4
1218MAXVAL 15
1219TUPLTYPE RGB_ALPHA
1220# Comment line
1221ENDHDR
1222\x00\x01\x02\x03\x0a\x0b\x0c\x0d\x05\x06\x07\x08";
1223 let decoder = PnmDecoder::new(&pamdata[..]).unwrap();
1224 assert_eq!(decoder.color_type(), ColorType::Rgba8);
1225 assert_eq!(decoder.original_color_type(), ExtendedColorType::Rgba8);
1226 assert_eq!(decoder.dimensions(), (1, 3));
1227 assert_eq!(decoder.subtype(), PnmSubtype::ArbitraryMap);
1228
1229 let mut image = vec![0; decoder.total_bytes() as usize];
1230 decoder.read_image(&mut image).unwrap();
1231 assert_eq!(image, b"\x00\x11\x22\x33\xaa\xbb\xcc\xdd\x55\x66\x77\x88",);
1232 match PnmDecoder::new(&pamdata[..]).unwrap().into_inner() {
1233 (
1234 _,
1235 PnmHeader {
1236 decoded:
1237 HeaderRecord::Arbitrary(ArbitraryHeader {
1238 width: 1,
1239 height: 3,
1240 maxval: 15,
1241 depth: 4,
1242 tupltype: Some(ArbitraryTuplType::RGBAlpha),
1243 }),
1244 encoded: _,
1245 },
1246 ) => (),
1247 _ => panic!("Decoded header is incorrect"),
1248 }
1249 }
1250
1251 #[test]
1252 fn pbm_binary() {
1253 let pbmbinary = [&b"P4 6 2\n"[..], &[0b0110_1100_u8, 0b1011_0111]].concat();
1256 let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap();
1257 assert_eq!(decoder.color_type(), ColorType::L8);
1258 assert_eq!(decoder.original_color_type(), ExtendedColorType::L1);
1259 assert_eq!(decoder.dimensions(), (6, 2));
1260 assert_eq!(
1261 decoder.subtype(),
1262 PnmSubtype::Bitmap(SampleEncoding::Binary)
1263 );
1264 let mut image = vec![0; decoder.total_bytes() as usize];
1265 decoder.read_image(&mut image).unwrap();
1266 assert_eq!(image, vec![255, 0, 0, 255, 0, 0, 0, 255, 0, 0, 255, 0]);
1267 match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() {
1268 (
1269 _,
1270 PnmHeader {
1271 decoded:
1272 HeaderRecord::Bitmap(BitmapHeader {
1273 encoding: SampleEncoding::Binary,
1274 width: 6,
1275 height: 2,
1276 }),
1277 encoded: _,
1278 },
1279 ) => (),
1280 _ => panic!("Decoded header is incorrect"),
1281 }
1282 }
1283
1284 #[test]
1286 fn pbm_binary_ascii_termination() {
1287 use std::io::{BufReader, Cursor, Error, ErrorKind, Read, Result};
1288 struct FailRead(Cursor<&'static [u8]>);
1289
1290 impl Read for FailRead {
1291 fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
1292 match self.0.read(buf) {
1293 Ok(n) if n > 0 => Ok(n),
1294 _ => Err(Error::new(
1295 ErrorKind::BrokenPipe,
1296 "Simulated broken pipe error",
1297 )),
1298 }
1299 }
1300 }
1301
1302 let pbmbinary = BufReader::new(FailRead(Cursor::new(b"P1 1 1\n")));
1303
1304 let decoder = PnmDecoder::new(pbmbinary).unwrap();
1305 let mut image = vec![0; decoder.total_bytes() as usize];
1306 decoder
1307 .read_image(&mut image)
1308 .expect_err("Image is malformed");
1309 }
1310
1311 #[test]
1312 fn pbm_ascii() {
1313 let pbmbinary = b"P1 6 2\n 0 1 1 0 1 1\n1 0 1 1 0\t\n\x0b\x0c\r1";
1317 let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap();
1318 assert_eq!(decoder.color_type(), ColorType::L8);
1319 assert_eq!(decoder.original_color_type(), ExtendedColorType::L1);
1320 assert_eq!(decoder.dimensions(), (6, 2));
1321 assert_eq!(decoder.subtype(), PnmSubtype::Bitmap(SampleEncoding::Ascii));
1322
1323 let mut image = vec![0; decoder.total_bytes() as usize];
1324 decoder.read_image(&mut image).unwrap();
1325 assert_eq!(image, vec![255, 0, 0, 255, 0, 0, 0, 255, 0, 0, 255, 0]);
1326 match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() {
1327 (
1328 _,
1329 PnmHeader {
1330 decoded:
1331 HeaderRecord::Bitmap(BitmapHeader {
1332 encoding: SampleEncoding::Ascii,
1333 width: 6,
1334 height: 2,
1335 }),
1336 encoded: _,
1337 },
1338 ) => (),
1339 _ => panic!("Decoded header is incorrect"),
1340 }
1341 }
1342
1343 #[test]
1344 fn pbm_ascii_nospace() {
1345 let pbmbinary = b"P1 6 2\n011011101101";
1349 let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap();
1350 assert_eq!(decoder.color_type(), ColorType::L8);
1351 assert_eq!(decoder.original_color_type(), ExtendedColorType::L1);
1352 assert_eq!(decoder.dimensions(), (6, 2));
1353 assert_eq!(decoder.subtype(), PnmSubtype::Bitmap(SampleEncoding::Ascii));
1354
1355 let mut image = vec![0; decoder.total_bytes() as usize];
1356 decoder.read_image(&mut image).unwrap();
1357 assert_eq!(image, vec![255, 0, 0, 255, 0, 0, 0, 255, 0, 0, 255, 0]);
1358 match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() {
1359 (
1360 _,
1361 PnmHeader {
1362 decoded:
1363 HeaderRecord::Bitmap(BitmapHeader {
1364 encoding: SampleEncoding::Ascii,
1365 width: 6,
1366 height: 2,
1367 }),
1368 encoded: _,
1369 },
1370 ) => (),
1371 _ => panic!("Decoded header is incorrect"),
1372 }
1373 }
1374
1375 #[test]
1376 fn pgm_binary() {
1377 let elements = (0..16).collect::<Vec<_>>();
1380 let pbmbinary = [&b"P5 4 4 255\n"[..], &elements].concat();
1381 let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap();
1382 assert_eq!(decoder.color_type(), ColorType::L8);
1383 assert_eq!(decoder.dimensions(), (4, 4));
1384 assert_eq!(
1385 decoder.subtype(),
1386 PnmSubtype::Graymap(SampleEncoding::Binary)
1387 );
1388 let mut image = vec![0; decoder.total_bytes() as usize];
1389 decoder.read_image(&mut image).unwrap();
1390 assert_eq!(image, elements);
1391 match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() {
1392 (
1393 _,
1394 PnmHeader {
1395 decoded:
1396 HeaderRecord::Graymap(GraymapHeader {
1397 encoding: SampleEncoding::Binary,
1398 width: 4,
1399 height: 4,
1400 maxwhite: 255,
1401 }),
1402 encoded: _,
1403 },
1404 ) => (),
1405 _ => panic!("Decoded header is incorrect"),
1406 }
1407 }
1408
1409 #[test]
1410 fn pgm_ascii() {
1411 let pbmbinary = b"P2 4 4 255\n 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15";
1414 let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap();
1415 assert_eq!(decoder.color_type(), ColorType::L8);
1416 assert_eq!(decoder.dimensions(), (4, 4));
1417 assert_eq!(
1418 decoder.subtype(),
1419 PnmSubtype::Graymap(SampleEncoding::Ascii)
1420 );
1421 let mut image = vec![0; decoder.total_bytes() as usize];
1422 decoder.read_image(&mut image).unwrap();
1423 assert_eq!(image, (0..16).collect::<Vec<_>>());
1424 match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() {
1425 (
1426 _,
1427 PnmHeader {
1428 decoded:
1429 HeaderRecord::Graymap(GraymapHeader {
1430 encoding: SampleEncoding::Ascii,
1431 width: 4,
1432 height: 4,
1433 maxwhite: 255,
1434 }),
1435 encoded: _,
1436 },
1437 ) => (),
1438 _ => panic!("Decoded header is incorrect"),
1439 }
1440 }
1441
1442 #[test]
1443 fn ppm_ascii() {
1444 let ascii = b"P3 1 1 2000\n0 1000 2000";
1445 let decoder = PnmDecoder::new(&ascii[..]).unwrap();
1446 let mut image = vec![0; decoder.total_bytes() as usize];
1447 decoder.read_image(&mut image).unwrap();
1448 assert_eq!(
1449 image,
1450 [
1451 0_u16.to_ne_bytes(),
1452 (u16::MAX / 2 + 1).to_ne_bytes(),
1453 u16::MAX.to_ne_bytes()
1454 ]
1455 .into_iter()
1456 .flatten()
1457 .collect::<Vec<_>>()
1458 );
1459 }
1460
1461 #[test]
1462 fn dimension_overflow() {
1463 let pamdata = b"P7
1464# Comment line
1465MAXVAL 255
1466TUPLTYPE RGB
1467DEPTH 3
1468WIDTH 4294967295
1469HEIGHT 4294967295
1470ENDHDR
1471\xde\xad\xbe\xef\xde\xad\xbe\xef\xde\xad\xbe\xef";
1472
1473 assert!(PnmDecoder::new(&pamdata[..]).is_err());
1474 }
1475
1476 #[test]
1477 fn issue_1508() {
1478 let _ = crate::load_from_memory(b"P391919 16999 1 1 9 919 16999 1 9999 999* 99999 N");
1479 }
1480
1481 #[test]
1482 fn issue_1616_overflow() {
1483 let data = [
1484 80, 54, 10, 52, 50, 57, 52, 56, 50, 57, 52, 56, 35, 56, 10, 52, 10, 48, 10, 12, 12, 56,
1485 ];
1486 let decoder = PnmDecoder::new(&data[..]).unwrap();
1489 let mut image = vec![0; decoder.total_bytes() as usize];
1490 let _ = decoder.read_image(&mut image);
1491 }
1492
1493 #[test]
1494 fn data_too_short() {
1495 let data = b"P3 16 16 1\n";
1496 let decoder = PnmDecoder::new(&data[..]).unwrap();
1497 let mut image = vec![0; decoder.total_bytes() as usize];
1498
1499 let _ = decoder.read_image(&mut image).unwrap_err();
1500 }
1501
1502 #[test]
1503 fn no_integers_with_plus() {
1504 let data = b"P3 +1 1 1\n";
1505 assert!(PnmDecoder::new(&data[..]).is_err());
1506 }
1507
1508 #[test]
1509 fn incomplete_pnm_header() {
1510 let data = b"P5 2 3 \n";
1511 assert!(PnmDecoder::new(&data[..]).is_err());
1512 }
1513
1514 #[test]
1515 fn leading_zeros() {
1516 let data = b"P2 03 00000000000002 00100\n011 22 033\n44 055 66\n";
1517 let decoder = PnmDecoder::new(&data[..]).unwrap();
1518 let mut image = vec![0; decoder.total_bytes() as usize];
1519 assert!(decoder.read_image(&mut image).is_ok());
1520 }
1521
1522 #[test]
1523 fn header_overflow() {
1524 let data = b"P1 4294967295 4294967297\n";
1525 assert!(PnmDecoder::new(&data[..]).is_err());
1526 }
1527
1528 #[test]
1529 fn header_large_dimension() {
1530 let data = b"P4 1 01234567890\n";
1531 let decoder = PnmDecoder::new(&data[..]).unwrap();
1532 assert!(decoder.dimensions() == (1, 1234567890));
1533 }
1534}