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