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