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::io::ReadExt;
15use crate::{utils, ImageDecoder, ImageFormat};
16
17use byteorder_lite::{BigEndian, ByteOrder, NativeEndian};
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 bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize> {
245 Ok((width * height * samples * Self::sample_size()) as usize)
246 }
247 fn from_bytes(bytes: &[u8], row_size: usize, output_buf: &mut [u8]) -> 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 let width = self.header.width();
657 let height = self.header.height();
658 let bytecount = S::bytelen(width, height, components)?;
659
660 let mut bytes = vec![];
661 self.reader.read_exact_vec(&mut bytes, bytecount)?;
662
663 let width: usize = width
664 .try_into()
665 .map_err(|_| DecoderError::Overflow(ErrorDataSource::Sample))?;
666 let components: usize = components
667 .try_into()
668 .map_err(|_| DecoderError::Overflow(ErrorDataSource::Sample))?;
669 let row_size = width
670 .checked_mul(components)
671 .ok_or(DecoderError::Overflow(ErrorDataSource::Sample))?;
672
673 S::from_bytes(&bytes, row_size, buf)?;
674 }
675 SampleEncoding::Ascii => {
676 self.read_ascii::<S>(buf)?;
677 }
678 }
679
680 let current_sample_max = self.header.maximal_sample();
682 let target_sample_max = 256_u32.pow(S::sample_size()) - 1;
683
684 if current_sample_max != target_sample_max {
685 let factor = target_sample_max as f32 / current_sample_max as f32;
686
687 if S::sample_size() == 1 {
688 for v in buf.iter_mut() {
689 *v = (f32::from(*v) * factor).round() as u8;
690 }
691 } else if S::sample_size() == 2 {
692 for chunk in buf.chunks_exact_mut(2) {
693 let v = NativeEndian::read_u16(chunk);
694 NativeEndian::write_u16(chunk, (f32::from(v) * factor).round() as u16);
695 }
696 }
697 }
698
699 Ok(())
700 }
701
702 fn read_ascii<Basic: Sample>(&mut self, output_buf: &mut [u8]) -> ImageResult<()> {
703 Basic::from_ascii(&mut self.reader, output_buf)
704 }
705
706 pub fn subtype(&self) -> PnmSubtype {
708 self.header.subtype()
709 }
710}
711
712fn read_separated_ascii<T: TryFrom<u16>>(reader: &mut dyn Read) -> ImageResult<T> {
713 let is_separator = |v: &u8| matches!(*v, b'\t' | b'\n' | b'\x0b' | b'\x0c' | b'\r' | b' ');
714
715 let mut v: u16 = 0;
716 let mut had_any = false;
717 #[allow(clippy::unbuffered_bytes)]
718 for rc in reader
719 .bytes()
720 .skip_while(|v| v.as_ref().ok().is_some_and(is_separator))
721 .take_while(|v| v.as_ref().ok().is_some_and(|c| !is_separator(c)))
722 {
723 let c = rc?;
724 let digit = match c {
725 b'0'..=b'9' => u16::from(c - b'0'),
726 _ => return Err(DecoderError::InvalidDigit(ErrorDataSource::Sample).into()),
727 };
728 v = v
729 .checked_mul(10)
730 .ok_or(DecoderError::Overflow(ErrorDataSource::Sample))?;
731 v = v
732 .checked_add(digit)
733 .ok_or(DecoderError::Overflow(ErrorDataSource::Sample))?;
734 had_any = true;
735 }
736
737 if !had_any {
738 return Err(DecoderError::InputTooShort.into());
739 }
740
741 Ok(T::try_from(v).or(Err(DecoderError::Overflow(ErrorDataSource::Sample)))?)
742}
743
744impl Sample for U8 {
745 type Representation = u8;
746
747 fn from_bytes(bytes: &[u8], _row_size: usize, output_buf: &mut [u8]) -> ImageResult<()> {
748 output_buf.copy_from_slice(bytes);
749 Ok(())
750 }
751
752 fn from_ascii(reader: &mut dyn Read, output_buf: &mut [u8]) -> ImageResult<()> {
753 for b in output_buf {
754 *b = read_separated_ascii(reader)?;
755 }
756 Ok(())
757 }
758}
759
760impl Sample for U16 {
761 type Representation = u16;
762
763 fn from_bytes(bytes: &[u8], _row_size: usize, output_buf: &mut [u8]) -> ImageResult<()> {
764 output_buf.copy_from_slice(bytes);
765 for chunk in output_buf.chunks_exact_mut(2) {
766 let v = BigEndian::read_u16(chunk);
767 NativeEndian::write_u16(chunk, v);
768 }
769 Ok(())
770 }
771
772 fn from_ascii(reader: &mut dyn Read, output_buf: &mut [u8]) -> ImageResult<()> {
773 for chunk in output_buf.chunks_exact_mut(2) {
774 let v = read_separated_ascii::<u16>(reader)?;
775 NativeEndian::write_u16(chunk, v);
776 }
777 Ok(())
778 }
779}
780
781impl Sample for PbmBit {
785 type Representation = u8;
786
787 fn bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize> {
788 let count = width * samples;
789 let linelen = (count / 8) + u32::from((count % 8) != 0);
790 Ok((linelen * height) as usize)
791 }
792
793 fn from_bytes(bytes: &[u8], row_size: usize, output_buf: &mut [u8]) -> ImageResult<()> {
794 let mut expanded = utils::expand_bits(1, row_size.try_into().unwrap(), bytes);
795 for b in &mut expanded {
796 *b = !*b;
797 }
798 output_buf.copy_from_slice(&expanded);
799 Ok(())
800 }
801
802 fn from_ascii(reader: &mut dyn Read, output_buf: &mut [u8]) -> ImageResult<()> {
803 #[allow(clippy::unbuffered_bytes)]
804 let mut bytes = reader.bytes();
805 for b in output_buf {
806 loop {
807 let byte = bytes
808 .next()
809 .ok_or_else::<ImageError, _>(|| DecoderError::InputTooShort.into())??;
810 match byte {
811 b'\t' | b'\n' | b'\x0b' | b'\x0c' | b'\r' | b' ' => continue,
812 b'0' => *b = 255,
813 b'1' => *b = 0,
814 c => return Err(DecoderError::UnexpectedByteInRaster(c).into()),
815 }
816 break;
817 }
818 }
819
820 Ok(())
821 }
822}
823
824impl Sample for BWBit {
826 type Representation = u8;
827
828 fn from_bytes(bytes: &[u8], row_size: usize, output_buf: &mut [u8]) -> ImageResult<()> {
829 U8::from_bytes(bytes, row_size, output_buf)?;
830 if let Some(val) = output_buf.iter().find(|&val| *val > 1) {
831 return Err(DecoderError::SampleOutOfBounds(*val).into());
832 }
833 Ok(())
834 }
835
836 fn from_ascii(_reader: &mut dyn Read, _output_buf: &mut [u8]) -> ImageResult<()> {
837 unreachable!("BW bits from anymaps are never encoded as ASCII")
838 }
839}
840
841impl DecodableImageHeader for BitmapHeader {
842 fn tuple_type(&self) -> ImageResult<TupleType> {
843 Ok(TupleType::PbmBit)
844 }
845}
846
847impl DecodableImageHeader for GraymapHeader {
848 fn tuple_type(&self) -> ImageResult<TupleType> {
849 match self.maxwhite {
850 0 => Err(DecoderError::MaxvalZero.into()),
851 v if v <= 0xFF => Ok(TupleType::GrayU8),
852 v if v <= 0xFFFF => Ok(TupleType::GrayU16),
853 _ => Err(DecoderError::MaxvalTooBig(self.maxwhite).into()),
854 }
855 }
856}
857
858impl DecodableImageHeader for PixmapHeader {
859 fn tuple_type(&self) -> ImageResult<TupleType> {
860 match self.maxval {
861 0 => Err(DecoderError::MaxvalZero.into()),
862 v if v <= 0xFF => Ok(TupleType::RGBU8),
863 v if v <= 0xFFFF => Ok(TupleType::RGBU16),
864 _ => Err(DecoderError::MaxvalTooBig(self.maxval).into()),
865 }
866 }
867}
868
869impl DecodableImageHeader for ArbitraryHeader {
870 fn tuple_type(&self) -> ImageResult<TupleType> {
871 match self.tupltype {
872 _ if self.maxval == 0 => Err(DecoderError::MaxvalZero.into()),
873 None if self.depth == 1 => Ok(TupleType::GrayU8),
874 None if self.depth == 2 => Ok(TupleType::GrayAlphaU8),
875 None if self.depth == 3 => Ok(TupleType::RGBU8),
876 None if self.depth == 4 => Ok(TupleType::RGBAlphaU8),
877
878 Some(ArbitraryTuplType::BlackAndWhite) if self.maxval == 1 && self.depth == 1 => {
879 Ok(TupleType::BWBit)
880 }
881 Some(ArbitraryTuplType::BlackAndWhite) => Err(DecoderError::InvalidDepthOrMaxval {
882 tuple_type: ArbitraryTuplType::BlackAndWhite,
883 maxval: self.maxval,
884 depth: self.depth,
885 }
886 .into()),
887
888 Some(ArbitraryTuplType::Grayscale) if self.depth == 1 && self.maxval <= 0xFF => {
889 Ok(TupleType::GrayU8)
890 }
891 Some(ArbitraryTuplType::Grayscale) if self.depth <= 1 && self.maxval <= 0xFFFF => {
892 Ok(TupleType::GrayU16)
893 }
894 Some(ArbitraryTuplType::Grayscale) => Err(DecoderError::InvalidDepthOrMaxval {
895 tuple_type: ArbitraryTuplType::Grayscale,
896 maxval: self.maxval,
897 depth: self.depth,
898 }
899 .into()),
900
901 Some(ArbitraryTuplType::RGB) if self.depth == 3 && self.maxval <= 0xFF => {
902 Ok(TupleType::RGBU8)
903 }
904 Some(ArbitraryTuplType::RGB) if self.depth == 3 && self.maxval <= 0xFFFF => {
905 Ok(TupleType::RGBU16)
906 }
907 Some(ArbitraryTuplType::RGB) => Err(DecoderError::InvalidDepth {
908 tuple_type: ArbitraryTuplType::RGB,
909 depth: self.depth,
910 }
911 .into()),
912
913 Some(ArbitraryTuplType::BlackAndWhiteAlpha) if self.depth == 2 && self.maxval == 1 => {
914 Ok(TupleType::BWAlphaBit)
915 }
916 Some(ArbitraryTuplType::BlackAndWhiteAlpha) => {
917 Err(DecoderError::InvalidDepthOrMaxval {
918 tuple_type: ArbitraryTuplType::BlackAndWhiteAlpha,
919 maxval: self.maxval,
920 depth: self.depth,
921 }
922 .into())
923 }
924
925 Some(ArbitraryTuplType::GrayscaleAlpha) if self.depth == 2 && self.maxval <= 0xFF => {
926 Ok(TupleType::GrayAlphaU8)
927 }
928 Some(ArbitraryTuplType::GrayscaleAlpha) if self.depth == 2 && self.maxval <= 0xFFFF => {
929 Ok(TupleType::GrayAlphaU16)
930 }
931 Some(ArbitraryTuplType::GrayscaleAlpha) => Err(DecoderError::InvalidDepth {
932 tuple_type: ArbitraryTuplType::GrayscaleAlpha,
933 depth: self.depth,
934 }
935 .into()),
936
937 Some(ArbitraryTuplType::RGBAlpha) if self.depth == 4 && self.maxval <= 0xFF => {
938 Ok(TupleType::RGBAlphaU8)
939 }
940 Some(ArbitraryTuplType::RGBAlpha) if self.depth == 4 && self.maxval <= 0xFFFF => {
941 Ok(TupleType::RGBAlphaU16)
942 }
943 Some(ArbitraryTuplType::RGBAlpha) => Err(DecoderError::InvalidDepth {
944 tuple_type: ArbitraryTuplType::RGBAlpha,
945 depth: self.depth,
946 }
947 .into()),
948
949 Some(ArbitraryTuplType::Custom(ref custom)) => Err(ImageError::Unsupported(
950 UnsupportedError::from_format_and_kind(
951 ImageFormat::Pnm.into(),
952 UnsupportedErrorKind::GenericFeature(format!("Tuple type {custom:?}")),
953 ),
954 )),
955 None => Err(DecoderError::TupleTypeUnrecognised.into()),
956 }
957 }
958}
959
960#[cfg(test)]
961mod tests {
962 use super::*;
963 #[test]
965 fn pam_blackandwhite() {
966 let pamdata = b"P7
967WIDTH 4
968HEIGHT 4
969DEPTH 1
970MAXVAL 1
971TUPLTYPE BLACKANDWHITE
972# Comment line
973ENDHDR
974\x01\x00\x00\x01\x01\x00\x00\x01\x01\x00\x00\x01\x01\x00\x00\x01";
975 let decoder = PnmDecoder::new(&pamdata[..]).unwrap();
976 assert_eq!(decoder.color_type(), ColorType::L8);
977 assert_eq!(decoder.original_color_type(), ExtendedColorType::L1);
978 assert_eq!(decoder.dimensions(), (4, 4));
979 assert_eq!(decoder.subtype(), PnmSubtype::ArbitraryMap);
980
981 let mut image = vec![0; decoder.total_bytes() as usize];
982 decoder.read_image(&mut image).unwrap();
983 assert_eq!(
984 image,
985 vec![
986 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
987 0x00, 0xFF
988 ]
989 );
990 match PnmDecoder::new(&pamdata[..]).unwrap().into_inner() {
991 (
992 _,
993 PnmHeader {
994 decoded:
995 HeaderRecord::Arbitrary(ArbitraryHeader {
996 width: 4,
997 height: 4,
998 maxval: 1,
999 depth: 1,
1000 tupltype: Some(ArbitraryTuplType::BlackAndWhite),
1001 }),
1002 encoded: _,
1003 },
1004 ) => (),
1005 _ => panic!("Decoded header is incorrect"),
1006 }
1007 }
1008
1009 #[test]
1011 fn pam_blackandwhite_alpha() {
1012 let pamdata = b"P7
1013WIDTH 2
1014HEIGHT 2
1015DEPTH 2
1016MAXVAL 1
1017TUPLTYPE BLACKANDWHITE_ALPHA
1018# Comment line
1019ENDHDR
1020\x01\x00\x00\x01\x01\x00\x00\x01";
1021 let decoder = PnmDecoder::new(&pamdata[..]).unwrap();
1022 assert_eq!(decoder.color_type(), ColorType::La8);
1023 assert_eq!(decoder.original_color_type(), ExtendedColorType::La1);
1024 assert_eq!(decoder.dimensions(), (2, 2));
1025 assert_eq!(decoder.subtype(), PnmSubtype::ArbitraryMap);
1026
1027 let mut image = vec![0; decoder.total_bytes() as usize];
1028 decoder.read_image(&mut image).unwrap();
1029 assert_eq!(image, vec![0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF,]);
1030 match PnmDecoder::new(&pamdata[..]).unwrap().into_inner() {
1031 (
1032 _,
1033 PnmHeader {
1034 decoded:
1035 HeaderRecord::Arbitrary(ArbitraryHeader {
1036 width: 2,
1037 height: 2,
1038 maxval: 1,
1039 depth: 2,
1040 tupltype: Some(ArbitraryTuplType::BlackAndWhiteAlpha),
1041 }),
1042 encoded: _,
1043 },
1044 ) => (),
1045 _ => panic!("Decoded header is incorrect"),
1046 }
1047 }
1048
1049 #[test]
1051 fn pam_grayscale() {
1052 let pamdata = b"P7
1053WIDTH 4
1054HEIGHT 4
1055DEPTH 1
1056MAXVAL 255
1057TUPLTYPE GRAYSCALE
1058# Comment line
1059ENDHDR
1060\xde\xad\xbe\xef\xde\xad\xbe\xef\xde\xad\xbe\xef\xde\xad\xbe\xef";
1061 let decoder = PnmDecoder::new(&pamdata[..]).unwrap();
1062 assert_eq!(decoder.color_type(), ColorType::L8);
1063 assert_eq!(decoder.dimensions(), (4, 4));
1064 assert_eq!(decoder.subtype(), PnmSubtype::ArbitraryMap);
1065
1066 let mut image = vec![0; decoder.total_bytes() as usize];
1067 decoder.read_image(&mut image).unwrap();
1068 assert_eq!(
1069 image,
1070 vec![
1071 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad,
1072 0xbe, 0xef
1073 ]
1074 );
1075 match PnmDecoder::new(&pamdata[..]).unwrap().into_inner() {
1076 (
1077 _,
1078 PnmHeader {
1079 decoded:
1080 HeaderRecord::Arbitrary(ArbitraryHeader {
1081 width: 4,
1082 height: 4,
1083 depth: 1,
1084 maxval: 255,
1085 tupltype: Some(ArbitraryTuplType::Grayscale),
1086 }),
1087 encoded: _,
1088 },
1089 ) => (),
1090 _ => panic!("Decoded header is incorrect"),
1091 }
1092 }
1093
1094 #[test]
1096 fn pam_grayscale_alpha() {
1097 let pamdata = b"P7
1098HEIGHT 1
1099WIDTH 2
1100MAXVAL 65535
1101DEPTH 2
1102TUPLTYPE GRAYSCALE_ALPHA
1103# Comment line
1104ENDHDR
1105\xdc\xba\x32\x10\xdc\xba\x32\x10";
1106 let decoder = PnmDecoder::new(&pamdata[..]).unwrap();
1107 assert_eq!(decoder.color_type(), ColorType::La16);
1108 assert_eq!(decoder.original_color_type(), ExtendedColorType::La16);
1109 assert_eq!(decoder.dimensions(), (2, 1));
1110 assert_eq!(decoder.subtype(), PnmSubtype::ArbitraryMap);
1111
1112 let mut image = vec![0; decoder.total_bytes() as usize];
1113 decoder.read_image(&mut image).unwrap();
1114 assert_eq!(
1115 image,
1116 [
1117 u16::to_ne_bytes(0xdcba),
1118 u16::to_ne_bytes(0x3210),
1119 u16::to_ne_bytes(0xdcba),
1120 u16::to_ne_bytes(0x3210)
1121 ]
1122 .concat()
1123 );
1124 match PnmDecoder::new(&pamdata[..]).unwrap().into_inner() {
1125 (
1126 _,
1127 PnmHeader {
1128 decoded:
1129 HeaderRecord::Arbitrary(ArbitraryHeader {
1130 width: 2,
1131 height: 1,
1132 maxval: 65535,
1133 depth: 2,
1134 tupltype: Some(ArbitraryTuplType::GrayscaleAlpha),
1135 }),
1136 encoded: _,
1137 },
1138 ) => (),
1139 _ => panic!("Decoded header is incorrect"),
1140 }
1141 }
1142
1143 #[test]
1145 fn pam_rgb() {
1146 let pamdata = b"P7
1147# Comment line
1148MAXVAL 255
1149TUPLTYPE RGB
1150DEPTH 3
1151WIDTH 2
1152HEIGHT 2
1153ENDHDR
1154\xde\xad\xbe\xef\xde\xad\xbe\xef\xde\xad\xbe\xef";
1155 let decoder = PnmDecoder::new(&pamdata[..]).unwrap();
1156 assert_eq!(decoder.color_type(), ColorType::Rgb8);
1157 assert_eq!(decoder.dimensions(), (2, 2));
1158 assert_eq!(decoder.subtype(), PnmSubtype::ArbitraryMap);
1159
1160 let mut image = vec![0; decoder.total_bytes() as usize];
1161 decoder.read_image(&mut image).unwrap();
1162 assert_eq!(
1163 image,
1164 vec![0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef]
1165 );
1166 match PnmDecoder::new(&pamdata[..]).unwrap().into_inner() {
1167 (
1168 _,
1169 PnmHeader {
1170 decoded:
1171 HeaderRecord::Arbitrary(ArbitraryHeader {
1172 maxval: 255,
1173 tupltype: Some(ArbitraryTuplType::RGB),
1174 depth: 3,
1175 width: 2,
1176 height: 2,
1177 }),
1178 encoded: _,
1179 },
1180 ) => (),
1181 _ => panic!("Decoded header is incorrect"),
1182 }
1183 }
1184
1185 #[test]
1187 fn pam_rgb_alpha() {
1188 let pamdata = b"P7
1189WIDTH 1
1190HEIGHT 3
1191DEPTH 4
1192MAXVAL 15
1193TUPLTYPE RGB_ALPHA
1194# Comment line
1195ENDHDR
1196\x00\x01\x02\x03\x0a\x0b\x0c\x0d\x05\x06\x07\x08";
1197 let decoder = PnmDecoder::new(&pamdata[..]).unwrap();
1198 assert_eq!(decoder.color_type(), ColorType::Rgba8);
1199 assert_eq!(decoder.original_color_type(), ExtendedColorType::Rgba8);
1200 assert_eq!(decoder.dimensions(), (1, 3));
1201 assert_eq!(decoder.subtype(), PnmSubtype::ArbitraryMap);
1202
1203 let mut image = vec![0; decoder.total_bytes() as usize];
1204 decoder.read_image(&mut image).unwrap();
1205 assert_eq!(image, b"\x00\x11\x22\x33\xaa\xbb\xcc\xdd\x55\x66\x77\x88",);
1206 match PnmDecoder::new(&pamdata[..]).unwrap().into_inner() {
1207 (
1208 _,
1209 PnmHeader {
1210 decoded:
1211 HeaderRecord::Arbitrary(ArbitraryHeader {
1212 width: 1,
1213 height: 3,
1214 maxval: 15,
1215 depth: 4,
1216 tupltype: Some(ArbitraryTuplType::RGBAlpha),
1217 }),
1218 encoded: _,
1219 },
1220 ) => (),
1221 _ => panic!("Decoded header is incorrect"),
1222 }
1223 }
1224
1225 #[test]
1226 fn pbm_binary() {
1227 let pbmbinary = [&b"P4 6 2\n"[..], &[0b0110_1100_u8, 0b1011_0111]].concat();
1230 let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap();
1231 assert_eq!(decoder.color_type(), ColorType::L8);
1232 assert_eq!(decoder.original_color_type(), ExtendedColorType::L1);
1233 assert_eq!(decoder.dimensions(), (6, 2));
1234 assert_eq!(
1235 decoder.subtype(),
1236 PnmSubtype::Bitmap(SampleEncoding::Binary)
1237 );
1238 let mut image = vec![0; decoder.total_bytes() as usize];
1239 decoder.read_image(&mut image).unwrap();
1240 assert_eq!(image, vec![255, 0, 0, 255, 0, 0, 0, 255, 0, 0, 255, 0]);
1241 match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() {
1242 (
1243 _,
1244 PnmHeader {
1245 decoded:
1246 HeaderRecord::Bitmap(BitmapHeader {
1247 encoding: SampleEncoding::Binary,
1248 width: 6,
1249 height: 2,
1250 }),
1251 encoded: _,
1252 },
1253 ) => (),
1254 _ => panic!("Decoded header is incorrect"),
1255 }
1256 }
1257
1258 #[test]
1260 fn pbm_binary_ascii_termination() {
1261 use std::io::{BufReader, Cursor, Error, ErrorKind, Read, Result};
1262 struct FailRead(Cursor<&'static [u8]>);
1263
1264 impl Read for FailRead {
1265 fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
1266 match self.0.read(buf) {
1267 Ok(n) if n > 0 => Ok(n),
1268 _ => Err(Error::new(
1269 ErrorKind::BrokenPipe,
1270 "Simulated broken pipe error",
1271 )),
1272 }
1273 }
1274 }
1275
1276 let pbmbinary = BufReader::new(FailRead(Cursor::new(b"P1 1 1\n")));
1277
1278 let decoder = PnmDecoder::new(pbmbinary).unwrap();
1279 let mut image = vec![0; decoder.total_bytes() as usize];
1280 decoder
1281 .read_image(&mut image)
1282 .expect_err("Image is malformed");
1283 }
1284
1285 #[test]
1286 fn pbm_ascii() {
1287 let pbmbinary = b"P1 6 2\n 0 1 1 0 1 1\n1 0 1 1 0\t\n\x0b\x0c\r1";
1291 let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap();
1292 assert_eq!(decoder.color_type(), ColorType::L8);
1293 assert_eq!(decoder.original_color_type(), ExtendedColorType::L1);
1294 assert_eq!(decoder.dimensions(), (6, 2));
1295 assert_eq!(decoder.subtype(), PnmSubtype::Bitmap(SampleEncoding::Ascii));
1296
1297 let mut image = vec![0; decoder.total_bytes() as usize];
1298 decoder.read_image(&mut image).unwrap();
1299 assert_eq!(image, vec![255, 0, 0, 255, 0, 0, 0, 255, 0, 0, 255, 0]);
1300 match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() {
1301 (
1302 _,
1303 PnmHeader {
1304 decoded:
1305 HeaderRecord::Bitmap(BitmapHeader {
1306 encoding: SampleEncoding::Ascii,
1307 width: 6,
1308 height: 2,
1309 }),
1310 encoded: _,
1311 },
1312 ) => (),
1313 _ => panic!("Decoded header is incorrect"),
1314 }
1315 }
1316
1317 #[test]
1318 fn pbm_ascii_nospace() {
1319 let pbmbinary = b"P1 6 2\n011011101101";
1323 let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap();
1324 assert_eq!(decoder.color_type(), ColorType::L8);
1325 assert_eq!(decoder.original_color_type(), ExtendedColorType::L1);
1326 assert_eq!(decoder.dimensions(), (6, 2));
1327 assert_eq!(decoder.subtype(), PnmSubtype::Bitmap(SampleEncoding::Ascii));
1328
1329 let mut image = vec![0; decoder.total_bytes() as usize];
1330 decoder.read_image(&mut image).unwrap();
1331 assert_eq!(image, vec![255, 0, 0, 255, 0, 0, 0, 255, 0, 0, 255, 0]);
1332 match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() {
1333 (
1334 _,
1335 PnmHeader {
1336 decoded:
1337 HeaderRecord::Bitmap(BitmapHeader {
1338 encoding: SampleEncoding::Ascii,
1339 width: 6,
1340 height: 2,
1341 }),
1342 encoded: _,
1343 },
1344 ) => (),
1345 _ => panic!("Decoded header is incorrect"),
1346 }
1347 }
1348
1349 #[test]
1350 fn pgm_binary() {
1351 let elements = (0..16).collect::<Vec<_>>();
1354 let pbmbinary = [&b"P5 4 4 255\n"[..], &elements].concat();
1355 let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap();
1356 assert_eq!(decoder.color_type(), ColorType::L8);
1357 assert_eq!(decoder.dimensions(), (4, 4));
1358 assert_eq!(
1359 decoder.subtype(),
1360 PnmSubtype::Graymap(SampleEncoding::Binary)
1361 );
1362 let mut image = vec![0; decoder.total_bytes() as usize];
1363 decoder.read_image(&mut image).unwrap();
1364 assert_eq!(image, elements);
1365 match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() {
1366 (
1367 _,
1368 PnmHeader {
1369 decoded:
1370 HeaderRecord::Graymap(GraymapHeader {
1371 encoding: SampleEncoding::Binary,
1372 width: 4,
1373 height: 4,
1374 maxwhite: 255,
1375 }),
1376 encoded: _,
1377 },
1378 ) => (),
1379 _ => panic!("Decoded header is incorrect"),
1380 }
1381 }
1382
1383 #[test]
1384 fn pgm_ascii() {
1385 let pbmbinary = b"P2 4 4 255\n 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15";
1388 let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap();
1389 assert_eq!(decoder.color_type(), ColorType::L8);
1390 assert_eq!(decoder.dimensions(), (4, 4));
1391 assert_eq!(
1392 decoder.subtype(),
1393 PnmSubtype::Graymap(SampleEncoding::Ascii)
1394 );
1395 let mut image = vec![0; decoder.total_bytes() as usize];
1396 decoder.read_image(&mut image).unwrap();
1397 assert_eq!(image, (0..16).collect::<Vec<_>>());
1398 match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() {
1399 (
1400 _,
1401 PnmHeader {
1402 decoded:
1403 HeaderRecord::Graymap(GraymapHeader {
1404 encoding: SampleEncoding::Ascii,
1405 width: 4,
1406 height: 4,
1407 maxwhite: 255,
1408 }),
1409 encoded: _,
1410 },
1411 ) => (),
1412 _ => panic!("Decoded header is incorrect"),
1413 }
1414 }
1415
1416 #[test]
1417 fn ppm_ascii() {
1418 let ascii = b"P3 1 1 2000\n0 1000 2000";
1419 let decoder = PnmDecoder::new(&ascii[..]).unwrap();
1420 let mut image = vec![0; decoder.total_bytes() as usize];
1421 decoder.read_image(&mut image).unwrap();
1422 assert_eq!(
1423 image,
1424 [
1425 0_u16.to_ne_bytes(),
1426 (u16::MAX / 2 + 1).to_ne_bytes(),
1427 u16::MAX.to_ne_bytes()
1428 ]
1429 .into_iter()
1430 .flatten()
1431 .collect::<Vec<_>>()
1432 );
1433 }
1434
1435 #[test]
1436 fn dimension_overflow() {
1437 let pamdata = b"P7
1438# Comment line
1439MAXVAL 255
1440TUPLTYPE RGB
1441DEPTH 3
1442WIDTH 4294967295
1443HEIGHT 4294967295
1444ENDHDR
1445\xde\xad\xbe\xef\xde\xad\xbe\xef\xde\xad\xbe\xef";
1446
1447 assert!(PnmDecoder::new(&pamdata[..]).is_err());
1448 }
1449
1450 #[test]
1451 fn issue_1508() {
1452 let _ = crate::load_from_memory(b"P391919 16999 1 1 9 919 16999 1 9999 999* 99999 N");
1453 }
1454
1455 #[test]
1456 fn issue_1616_overflow() {
1457 let data = [
1458 80, 54, 10, 52, 50, 57, 52, 56, 50, 57, 52, 56, 35, 56, 10, 52, 10, 48, 10, 12, 12, 56,
1459 ];
1460 let decoder = PnmDecoder::new(&data[..]).unwrap();
1463 let mut image = vec![0; decoder.total_bytes() as usize];
1464 let _ = decoder.read_image(&mut image);
1465 }
1466
1467 #[test]
1468 fn data_too_short() {
1469 let data = b"P3 16 16 1\n";
1470 let decoder = PnmDecoder::new(&data[..]).unwrap();
1471 let mut image = vec![0; decoder.total_bytes() as usize];
1472
1473 let _ = decoder.read_image(&mut image).unwrap_err();
1474 }
1475
1476 #[test]
1477 fn no_integers_with_plus() {
1478 let data = b"P3 +1 1 1\n";
1479 assert!(PnmDecoder::new(&data[..]).is_err());
1480 }
1481
1482 #[test]
1483 fn incomplete_pnm_header() {
1484 let data = b"P5 2 3 \n";
1485 assert!(PnmDecoder::new(&data[..]).is_err());
1486 }
1487
1488 #[test]
1489 fn leading_zeros() {
1490 let data = b"P2 03 00000000000002 00100\n011 22 033\n44 055 66\n";
1491 let decoder = PnmDecoder::new(&data[..]).unwrap();
1492 let mut image = vec![0; decoder.total_bytes() as usize];
1493 assert!(decoder.read_image(&mut image).is_ok());
1494 }
1495
1496 #[test]
1497 fn header_overflow() {
1498 let data = b"P1 4294967295 4294967297\n";
1499 assert!(PnmDecoder::new(&data[..]).is_err());
1500 }
1501
1502 #[test]
1503 fn header_large_dimension() {
1504 let data = b"P4 1 01234567890\n";
1505 let decoder = PnmDecoder::new(&data[..]).unwrap();
1506 assert!(decoder.dimensions() == (1, 1234567890));
1507 }
1508}