1 use std::convert::TryFrom;
2 use std::error;
3 use std::io::{self, BufRead, BufReader, Cursor, Read};
4 use std::str::{self, FromStr};
5 use std::fmt::{self, Display};
6 use std::marker::PhantomData;
7 use std::mem;
8 use std::num::ParseIntError;
9
10 use super::{ArbitraryHeader, ArbitraryTuplType, BitmapHeader, GraymapHeader, PixmapHeader};
11 use super::{HeaderRecord, PnmHeader, PNMSubtype, SampleEncoding};
12 use crate::color::{ColorType, ExtendedColorType};
13 use crate::error::{
14 DecodingError, ImageError, ImageResult, UnsupportedError, UnsupportedErrorKind,
15 };
16 use crate::image::{self, ImageDecoder, ImageFormat};
17 use crate::utils;
18
19 use byteorder::{BigEndian, ByteOrder, NativeEndian};
20
21 /// All errors that can occur when attempting to parse a PNM
22 #[derive(Debug, Clone)]
23 enum DecoderError {
24 /// PNM's "P[123456]" signature wrong or missing
25 PnmMagicInvalid([u8; 2]),
26 /// Couldn't parse the specified string as an integer from the specified source
27 UnparsableValue(ErrorDataSource, String, ParseIntError),
28
29 /// More than the exactly one allowed plane specified by the format
30 NonAsciiByteInHeader(u8),
31 /// The PAM header contained a non-ASCII byte
32 NonAsciiLineInPamHeader,
33 /// A sample string contained a non-ASCII byte
34 NonAsciiSample,
35
36 /// The byte after the P7 magic was not 0x0A NEWLINE
37 NotNewlineAfterP7Magic(u8),
38 /// The PNM header had too few lines
39 UnexpectedPnmHeaderEnd,
40
41 /// The specified line was specified twice
42 HeaderLineDuplicated(PnmHeaderLine),
43 /// The line with the specified ID was not understood
44 HeaderLineUnknown(String),
45 /// At least one of the required lines were missing from the header (are `None` here)
46 ///
47 /// Same names as [`PnmHeaderLine`](enum.PnmHeaderLine.html)
48 #[allow(missing_docs)]
49 HeaderLineMissing {
50 height: Option<u32>,
51 width: Option<u32>,
52 depth: Option<u32>,
53 maxval: Option<u32>,
54 },
55
56 /// Not enough data was provided to the Decoder to decode the image
57 InputTooShort,
58 /// Sample raster contained unexpected byte
59 UnexpectedByteInRaster(u8),
60 /// Specified sample was out of bounds (e.g. >1 in B&W)
61 SampleOutOfBounds(u8),
62 /// The image's maxval exceeds 0xFFFF
63 MaxvalTooBig(u32),
64
65 /// The specified tuple type supports restricted depths and maxvals, those restrictions were not met
66 InvalidDepthOrMaxval {
67 tuple_type: ArbitraryTuplType,
68 depth: u32,
69 maxval: u32,
70 },
71 /// The specified tuple type supports restricted depths, those restrictions were not met
72 InvalidDepth {
73 tuple_type: ArbitraryTuplType,
74 depth: u32,
75 },
76 /// The tuple type was not recognised by the parser
77 TupleTypeUnrecognised,
78 }
79
80 impl Display for DecoderError {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result81 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82 match self {
83 DecoderError::PnmMagicInvalid(magic) =>
84 f.write_fmt(format_args!("Expected magic constant for PNM: P1..P7, got [{:#04X?}, {:#04X?}]", magic[0], magic[1])),
85 DecoderError::UnparsableValue(src, data, err) =>
86 f.write_fmt(format_args!("Error parsing {:?} as {}: {}", data, src, err)),
87
88 DecoderError::NonAsciiByteInHeader(c) =>
89 f.write_fmt(format_args!("Non-ASCII character {:#04X?} in header", c)),
90 DecoderError::NonAsciiLineInPamHeader =>
91 f.write_str("Non-ASCII line in PAM header"),
92 DecoderError::NonAsciiSample =>
93 f.write_str("Non-ASCII character where sample value was expected"),
94
95 DecoderError::NotNewlineAfterP7Magic(c) =>
96 f.write_fmt(format_args!("Expected newline after P7 magic, got {:#04X?}", c)),
97 DecoderError::UnexpectedPnmHeaderEnd =>
98 f.write_str("Unexpected end of PNM header"),
99
100 DecoderError::HeaderLineDuplicated(line) =>
101 f.write_fmt(format_args!("Duplicate {} line", line)),
102 DecoderError::HeaderLineUnknown(identifier) =>
103 f.write_fmt(format_args!("Unknown header line with identifier {:?}", identifier)),
104 DecoderError::HeaderLineMissing { height, width, depth, maxval } =>
105 f.write_fmt(format_args!("Missing header line: have height={:?}, width={:?}, depth={:?}, maxval={:?}", height, width, depth, maxval)),
106
107 DecoderError::InputTooShort =>
108 f.write_str("Not enough data was provided to the Decoder to decode the image"),
109 DecoderError::UnexpectedByteInRaster(c) =>
110 f.write_fmt(format_args!("Unexpected character {:#04X?} within sample raster", c)),
111 DecoderError::SampleOutOfBounds(val) =>
112 f.write_fmt(format_args!("Sample value {} outside of bounds", val)),
113 DecoderError::MaxvalTooBig(maxval) =>
114 f.write_fmt(format_args!("Image MAXVAL exceeds {}: {}", 0xFFFF, maxval)),
115
116 DecoderError::InvalidDepthOrMaxval { tuple_type, depth, maxval } =>
117 f.write_fmt(format_args!("Invalid depth ({}) or maxval ({}) for tuple type {}", depth, maxval, tuple_type.name())),
118 DecoderError::InvalidDepth { tuple_type, depth } =>
119 f.write_fmt(format_args!("Invalid depth ({}) for tuple type {}", depth, tuple_type.name())),
120 DecoderError::TupleTypeUnrecognised =>
121 f.write_str("Tuple type not recognized"),
122 }
123 }
124 }
125
126 /// Note: should `pnm` be extracted into a separate crate,
127 /// this will need to be hidden until that crate hits version `1.0`.
128 impl From<DecoderError> for ImageError {
from(e: DecoderError) -> ImageError129 fn from(e: DecoderError) -> ImageError {
130 ImageError::Decoding(DecodingError::new(ImageFormat::Pnm.into(), e))
131 }
132 }
133
134 impl error::Error for DecoderError {
source(&self) -> Option<&(dyn error::Error + 'static)>135 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
136 match self {
137 DecoderError::UnparsableValue(_, _, err) => Some(err),
138 _ => None,
139 }
140 }
141 }
142
143 /// Single-value lines in a PNM header
144 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
145 enum PnmHeaderLine {
146 /// "HEIGHT"
147 Height,
148 /// "WIDTH"
149 Width,
150 /// "DEPTH"
151 Depth,
152 /// "MAXVAL", a.k.a. `maxwhite`
153 Maxval,
154 }
155
156 impl Display for PnmHeaderLine {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result157 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
158 f.write_str(match self {
159 PnmHeaderLine::Height => "HEIGHT",
160 PnmHeaderLine::Width => "WIDTH",
161 PnmHeaderLine::Depth => "DEPTH",
162 PnmHeaderLine::Maxval => "MAXVAL",
163 })
164 }
165 }
166
167 /// Single-value lines in a PNM header
168 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
169 enum ErrorDataSource {
170 /// One of the header lines
171 Line(PnmHeaderLine),
172 /// Value in the preamble
173 Preamble,
174 /// Sample/pixel data
175 Sample,
176 }
177
178 impl Display for ErrorDataSource {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result179 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180 match self {
181 ErrorDataSource::Line(l) => l.fmt(f),
182 ErrorDataSource::Preamble => f.write_str("number in preamble"),
183 ErrorDataSource::Sample => f.write_str("sample"),
184 }
185 }
186 }
187
188 /// Dynamic representation, represents all decodable (sample, depth) combinations.
189 #[derive(Clone, Copy)]
190 enum TupleType {
191 PbmBit,
192 BWBit,
193 GrayU8,
194 GrayU16,
195 RGBU8,
196 RGBU16,
197 }
198
199 trait Sample {
bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize>200 fn bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize>;
201
202 /// It is guaranteed that `bytes.len() == bytelen(width, height, samples)`
from_bytes(bytes: &[u8], width: u32, height: u32, samples: u32) -> ImageResult<Vec<u8>>203 fn from_bytes(bytes: &[u8], width: u32, height: u32, samples: u32)
204 -> ImageResult<Vec<u8>>;
205
from_ascii(reader: &mut dyn Read, width: u32, height: u32, samples: u32) -> ImageResult<Vec<u8>>206 fn from_ascii(reader: &mut dyn Read, width: u32, height: u32, samples: u32)
207 -> ImageResult<Vec<u8>>;
208 }
209
210 struct U8;
211 struct U16;
212 struct PbmBit;
213 struct BWBit;
214
215 trait DecodableImageHeader {
tuple_type(&self) -> ImageResult<TupleType>216 fn tuple_type(&self) -> ImageResult<TupleType>;
217 }
218
219 /// PNM decoder
220 pub struct PnmDecoder<R> {
221 reader: BufReader<R>,
222 header: PnmHeader,
223 tuple: TupleType,
224 }
225
226 impl<R: Read> PnmDecoder<R> {
227 /// Create a new decoder that decodes from the stream ```read```
new(read: R) -> ImageResult<PnmDecoder<R>>228 pub fn new(read: R) -> ImageResult<PnmDecoder<R>> {
229 let mut buf = BufReader::new(read);
230 let magic = buf.read_magic_constant()?;
231
232 let subtype = match magic {
233 [b'P', b'1'] => PNMSubtype::Bitmap(SampleEncoding::Ascii),
234 [b'P', b'2'] => PNMSubtype::Graymap(SampleEncoding::Ascii),
235 [b'P', b'3'] => PNMSubtype::Pixmap(SampleEncoding::Ascii),
236 [b'P', b'4'] => PNMSubtype::Bitmap(SampleEncoding::Binary),
237 [b'P', b'5'] => PNMSubtype::Graymap(SampleEncoding::Binary),
238 [b'P', b'6'] => PNMSubtype::Pixmap(SampleEncoding::Binary),
239 [b'P', b'7'] => PNMSubtype::ArbitraryMap,
240 _ => return Err(DecoderError::PnmMagicInvalid(magic).into()),
241 };
242
243 let decoder = match subtype {
244 PNMSubtype::Bitmap(enc) => PnmDecoder::read_bitmap_header(buf, enc),
245 PNMSubtype::Graymap(enc) => PnmDecoder::read_graymap_header(buf, enc),
246 PNMSubtype::Pixmap(enc) => PnmDecoder::read_pixmap_header(buf, enc),
247 PNMSubtype::ArbitraryMap => PnmDecoder::read_arbitrary_header(buf),
248 }?;
249
250 if utils::check_dimension_overflow(
251 decoder.dimensions().0,
252 decoder.dimensions().1,
253 decoder.color_type().bytes_per_pixel(),
254 ) {
255 return Err(ImageError::Unsupported(
256 UnsupportedError::from_format_and_kind(
257 ImageFormat::Pnm.into(),
258 UnsupportedErrorKind::GenericFeature(format!(
259 "Image dimensions ({}x{}) are too large",
260 decoder.dimensions().0,
261 decoder.dimensions().1
262 )),
263 ),
264 ));
265 }
266
267 Ok(decoder)
268 }
269
270 /// Extract the reader and header after an image has been read.
into_inner(self) -> (R, PnmHeader)271 pub fn into_inner(self) -> (R, PnmHeader) {
272 (self.reader.into_inner(), self.header)
273 }
274
read_bitmap_header( mut reader: BufReader<R>, encoding: SampleEncoding, ) -> ImageResult<PnmDecoder<R>>275 fn read_bitmap_header(
276 mut reader: BufReader<R>,
277 encoding: SampleEncoding,
278 ) -> ImageResult<PnmDecoder<R>> {
279 let header = reader.read_bitmap_header(encoding)?;
280 Ok(PnmDecoder {
281 reader,
282 tuple: TupleType::PbmBit,
283 header: PnmHeader {
284 decoded: HeaderRecord::Bitmap(header),
285 encoded: None,
286 },
287 })
288 }
289
read_graymap_header( mut reader: BufReader<R>, encoding: SampleEncoding, ) -> ImageResult<PnmDecoder<R>>290 fn read_graymap_header(
291 mut reader: BufReader<R>,
292 encoding: SampleEncoding,
293 ) -> ImageResult<PnmDecoder<R>> {
294 let header = reader.read_graymap_header(encoding)?;
295 let tuple_type = header.tuple_type()?;
296 Ok(PnmDecoder {
297 reader,
298 tuple: tuple_type,
299 header: PnmHeader {
300 decoded: HeaderRecord::Graymap(header),
301 encoded: None,
302 },
303 })
304 }
305
read_pixmap_header( mut reader: BufReader<R>, encoding: SampleEncoding, ) -> ImageResult<PnmDecoder<R>>306 fn read_pixmap_header(
307 mut reader: BufReader<R>,
308 encoding: SampleEncoding,
309 ) -> ImageResult<PnmDecoder<R>> {
310 let header = reader.read_pixmap_header(encoding)?;
311 let tuple_type = header.tuple_type()?;
312 Ok(PnmDecoder {
313 reader,
314 tuple: tuple_type,
315 header: PnmHeader {
316 decoded: HeaderRecord::Pixmap(header),
317 encoded: None,
318 },
319 })
320 }
321
read_arbitrary_header(mut reader: BufReader<R>) -> ImageResult<PnmDecoder<R>>322 fn read_arbitrary_header(mut reader: BufReader<R>) -> ImageResult<PnmDecoder<R>> {
323 let header = reader.read_arbitrary_header()?;
324 let tuple_type = header.tuple_type()?;
325 Ok(PnmDecoder {
326 reader,
327 tuple: tuple_type,
328 header: PnmHeader {
329 decoded: HeaderRecord::Arbitrary(header),
330 encoded: None,
331 },
332 })
333 }
334 }
335
336 trait HeaderReader: BufRead {
337 /// Reads the two magic constant bytes
read_magic_constant(&mut self) -> ImageResult<[u8; 2]>338 fn read_magic_constant(&mut self) -> ImageResult<[u8; 2]> {
339 let mut magic: [u8; 2] = [0, 0];
340 self.read_exact(&mut magic)?;
341 Ok(magic)
342 }
343
344 /// Reads a string as well as a single whitespace after it, ignoring comments
read_next_string(&mut self) -> ImageResult<String>345 fn read_next_string(&mut self) -> ImageResult<String> {
346 let mut bytes = Vec::new();
347
348 // pair input bytes with a bool mask to remove comments
349 let mark_comments = self.bytes().scan(true, |partof, read| {
350 let byte = match read {
351 Err(err) => return Some((*partof, Err(err))),
352 Ok(byte) => byte,
353 };
354 let cur_enabled = *partof && byte != b'#';
355 let next_enabled = cur_enabled || (byte == b'\r' || byte == b'\n');
356 *partof = next_enabled;
357 Some((cur_enabled, Ok(byte)))
358 });
359
360 for (_, byte) in mark_comments.filter(|ref e| e.0) {
361 match byte {
362 Ok(b'\t') | Ok(b'\n') | Ok(b'\x0b') | Ok(b'\x0c') | Ok(b'\r') | Ok(b' ') => {
363 if !bytes.is_empty() {
364 break; // We're done as we already have some content
365 }
366 }
367 Ok(byte) if !byte.is_ascii() => return Err(DecoderError::NonAsciiByteInHeader(byte).into()),
368 Ok(byte) => {
369 bytes.push(byte);
370 },
371 Err(_) => break,
372 }
373 }
374
375 if bytes.is_empty() {
376 return Err(ImageError::IoError(io::ErrorKind::UnexpectedEof.into()));
377 }
378
379 if !bytes.as_slice().is_ascii() {
380 // We have only filled the buffer with characters for which `byte.is_ascii()` holds.
381 unreachable!("Non-ASCII character should have returned sooner")
382 }
383
384 let string = String::from_utf8(bytes)
385 // We checked the precondition ourselves a few lines before, `bytes.as_slice().is_ascii()`.
386 .unwrap_or_else(|_| unreachable!("Only ASCII characters should be decoded"));
387
388 Ok(string)
389 }
390
391 /// Read the next line
read_next_line(&mut self) -> ImageResult<String>392 fn read_next_line(&mut self) -> ImageResult<String> {
393 let mut buffer = String::new();
394 self.read_line(&mut buffer)?;
395 Ok(buffer)
396 }
397
read_next_u32(&mut self) -> ImageResult<u32>398 fn read_next_u32(&mut self) -> ImageResult<u32> {
399 let s = self.read_next_string()?;
400 s.parse::<u32>()
401 .map_err(|err| DecoderError::UnparsableValue(ErrorDataSource::Preamble, s, err).into())
402 }
403
read_bitmap_header(&mut self, encoding: SampleEncoding) -> ImageResult<BitmapHeader>404 fn read_bitmap_header(&mut self, encoding: SampleEncoding) -> ImageResult<BitmapHeader> {
405 let width = self.read_next_u32()?;
406 let height = self.read_next_u32()?;
407 Ok(BitmapHeader {
408 encoding,
409 width,
410 height,
411 })
412 }
413
read_graymap_header(&mut self, encoding: SampleEncoding) -> ImageResult<GraymapHeader>414 fn read_graymap_header(&mut self, encoding: SampleEncoding) -> ImageResult<GraymapHeader> {
415 self.read_pixmap_header(encoding).map(
416 |PixmapHeader {
417 encoding,
418 width,
419 height,
420 maxval,
421 }| GraymapHeader {
422 encoding,
423 width,
424 height,
425 maxwhite: maxval,
426 },
427 )
428 }
429
read_pixmap_header(&mut self, encoding: SampleEncoding) -> ImageResult<PixmapHeader>430 fn read_pixmap_header(&mut self, encoding: SampleEncoding) -> ImageResult<PixmapHeader> {
431 let width = self.read_next_u32()?;
432 let height = self.read_next_u32()?;
433 let maxval = self.read_next_u32()?;
434 Ok(PixmapHeader {
435 encoding,
436 width,
437 height,
438 maxval,
439 })
440 }
441
read_arbitrary_header(&mut self) -> ImageResult<ArbitraryHeader>442 fn read_arbitrary_header(&mut self) -> ImageResult<ArbitraryHeader> {
443 fn parse_single_value_line(line_val: &mut Option<u32>, rest: &str, line: PnmHeaderLine) -> ImageResult<()> {
444 if line_val.is_some() {
445 Err(DecoderError::HeaderLineDuplicated(line).into())
446 } else {
447 let v = rest.trim().parse().map_err(|err| DecoderError::UnparsableValue(ErrorDataSource::Line(line), rest.to_owned(), err))?;
448 *line_val = Some(v);
449 Ok(())
450 }
451 }
452
453 match self.bytes().next() {
454 None => return Err(ImageError::IoError(io::ErrorKind::UnexpectedEof.into())),
455 Some(Err(io)) => return Err(ImageError::IoError(io)),
456 Some(Ok(b'\n')) => (),
457 Some(Ok(c)) => return Err(DecoderError::NotNewlineAfterP7Magic(c).into()),
458 }
459
460 let mut line = String::new();
461 let mut height: Option<u32> = None;
462 let mut width: Option<u32> = None;
463 let mut depth: Option<u32> = None;
464 let mut maxval: Option<u32> = None;
465 let mut tupltype: Option<String> = None;
466 loop {
467 line.truncate(0);
468 let len = self.read_line(&mut line)?;
469 if len == 0 {
470 return Err(DecoderError::UnexpectedPnmHeaderEnd.into());
471 }
472 if line.as_bytes()[0] == b'#' {
473 continue;
474 }
475 if !line.is_ascii() {
476 return Err(DecoderError::NonAsciiLineInPamHeader.into());
477 }
478 #[allow(deprecated)]
479 let (identifier, rest) = line.trim_left()
480 .split_at(line.find(char::is_whitespace).unwrap_or_else(|| line.len()));
481 match identifier {
482 "ENDHDR" => break,
483 "HEIGHT" => parse_single_value_line(&mut height, rest, PnmHeaderLine::Height)?,
484 "WIDTH" => parse_single_value_line(&mut width, rest, PnmHeaderLine::Width)?,
485 "DEPTH" => parse_single_value_line(&mut depth, rest, PnmHeaderLine::Depth)?,
486 "MAXVAL" => parse_single_value_line(&mut maxval, rest, PnmHeaderLine::Maxval)?,
487 "TUPLTYPE" => {
488 let identifier = rest.trim();
489 if tupltype.is_some() {
490 let appended = tupltype.take().map(|mut v| {
491 v.push(' ');
492 v.push_str(identifier);
493 v
494 });
495 tupltype = appended;
496 } else {
497 tupltype = Some(identifier.to_string());
498 }
499 }
500 _ => return Err(DecoderError::HeaderLineUnknown(identifier.to_string()).into()),
501 }
502 }
503
504 let (h, w, d, m) = match (height, width, depth, maxval) {
505 (Some(h), Some(w), Some(d), Some(m)) => (h, w, d, m),
506 _ => return Err(DecoderError::HeaderLineMissing { height, width, depth, maxval }.into()),
507 };
508
509 let tupltype = match tupltype {
510 None => None,
511 Some(ref t) if t == "BLACKANDWHITE" => Some(ArbitraryTuplType::BlackAndWhite),
512 Some(ref t) if t == "BLACKANDWHITE_ALPHA" => Some(ArbitraryTuplType::BlackAndWhiteAlpha),
513 Some(ref t) if t == "GRAYSCALE" => Some(ArbitraryTuplType::Grayscale),
514 Some(ref t) if t == "GRAYSCALE_ALPHA" => Some(ArbitraryTuplType::GrayscaleAlpha),
515 Some(ref t) if t == "RGB" => Some(ArbitraryTuplType::RGB),
516 Some(ref t) if t == "RGB_ALPHA" => Some(ArbitraryTuplType::RGBAlpha),
517 Some(other) => Some(ArbitraryTuplType::Custom(other)),
518 };
519
520 Ok(ArbitraryHeader {
521 height: h,
522 width: w,
523 depth: d,
524 maxval: m,
525 tupltype,
526 })
527 }
528 }
529
530 impl<R: Read> HeaderReader for BufReader<R> {}
531
532 /// Wrapper struct around a `Cursor<Vec<u8>>`
533 pub struct PnmReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
534 impl<R> Read for PnmReader<R> {
read(&mut self, buf: &mut [u8]) -> io::Result<usize>535 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
536 self.0.read(buf)
537 }
read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize>538 fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
539 if self.0.position() == 0 && buf.is_empty() {
540 mem::swap(buf, self.0.get_mut());
541 Ok(buf.len())
542 } else {
543 self.0.read_to_end(buf)
544 }
545 }
546 }
547
548 impl<'a, R: 'a + Read> ImageDecoder<'a> for PnmDecoder<R> {
549 type Reader = PnmReader<R>;
550
dimensions(&self) -> (u32, u32)551 fn dimensions(&self) -> (u32, u32) {
552 (self.header.width(), self.header.height())
553 }
554
color_type(&self) -> ColorType555 fn color_type(&self) -> ColorType {
556 match self.tuple {
557 TupleType::PbmBit => ColorType::L8,
558 TupleType::BWBit => ColorType::L8,
559 TupleType::GrayU8 => ColorType::L8,
560 TupleType::GrayU16 => ColorType::L16,
561 TupleType::RGBU8 => ColorType::Rgb8,
562 TupleType::RGBU16 => ColorType::Rgb16,
563 }
564 }
565
original_color_type(&self) -> ExtendedColorType566 fn original_color_type(&self) -> ExtendedColorType {
567 match self.tuple {
568 TupleType::PbmBit => ExtendedColorType::L1,
569 TupleType::BWBit => ExtendedColorType::L1,
570 TupleType::GrayU8 => ExtendedColorType::L8,
571 TupleType::GrayU16 => ExtendedColorType::L16,
572 TupleType::RGBU8 => ExtendedColorType::Rgb8,
573 TupleType::RGBU16 => ExtendedColorType::Rgb16,
574 }
575 }
576
into_reader(self) -> ImageResult<Self::Reader>577 fn into_reader(self) -> ImageResult<Self::Reader> {
578 Ok(PnmReader(Cursor::new(image::decoder_to_vec(self)?), PhantomData))
579 }
580
read_image(mut self, buf: &mut [u8]) -> ImageResult<()>581 fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> {
582 assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));
583 buf.copy_from_slice(&match self.tuple {
584 TupleType::PbmBit => self.read_samples::<PbmBit>(1),
585 TupleType::BWBit => self.read_samples::<BWBit>(1),
586 TupleType::RGBU8 => self.read_samples::<U8>(3),
587 TupleType::RGBU16 => self.read_samples::<U16>(3),
588 TupleType::GrayU8 => self.read_samples::<U8>(1),
589 TupleType::GrayU16 => self.read_samples::<U16>(1),
590 }?);
591 Ok(())
592 }
593 }
594
595 impl<R: Read> PnmDecoder<R> {
read_samples<S: Sample>(&mut self, components: u32) -> ImageResult<Vec<u8>>596 fn read_samples<S: Sample>(&mut self, components: u32) -> ImageResult<Vec<u8>> {
597 match self.subtype().sample_encoding() {
598 SampleEncoding::Binary => {
599 let width = self.header.width();
600 let height = self.header.height();
601 let bytecount = S::bytelen(width, height, components)?;
602 let mut bytes = vec![];
603
604 self.reader
605 .by_ref()
606 // This conversion is potentially lossy but unlikely and in that case we error
607 // later anyways.
608 .take(bytecount as u64)
609 .read_to_end(&mut bytes)?;
610
611 if bytes.len() != bytecount {
612 return Err(DecoderError::InputTooShort.into());
613 }
614
615 let samples = S::from_bytes(&bytes, width, height, components)?;
616 Ok(samples)
617 }
618 SampleEncoding::Ascii => {
619 let samples = self.read_ascii::<S>(components)?;
620 Ok(samples)
621 }
622 }
623 }
624
read_ascii<Basic: Sample>(&mut self, components: u32) -> ImageResult<Vec<u8>>625 fn read_ascii<Basic: Sample>(&mut self, components: u32) -> ImageResult<Vec<u8>> {
626 Basic::from_ascii(&mut self.reader, self.header.width(), self.header.height(), components)
627 }
628
629 /// Get the pnm subtype, depending on the magic constant contained in the header
subtype(&self) -> PNMSubtype630 pub fn subtype(&self) -> PNMSubtype {
631 self.header.subtype()
632 }
633 }
634
read_separated_ascii<T: FromStr<Err = ParseIntError>>(reader: &mut dyn Read) -> ImageResult<T> where T::Err: Display635 fn read_separated_ascii<T: FromStr<Err = ParseIntError>>(reader: &mut dyn Read) -> ImageResult<T>
636 where T::Err: Display
637 {
638 let is_separator = |v: &u8| match *v {
639 b'\t' | b'\n' | b'\x0b' | b'\x0c' | b'\r' | b' ' => true,
640 _ => false,
641 };
642
643 let token = reader
644 .bytes()
645 .skip_while(|v| v.as_ref().ok().map(&is_separator).unwrap_or(false))
646 .take_while(|v| v.as_ref().ok().map(|c| !is_separator(c)).unwrap_or(false))
647 .collect::<Result<Vec<u8>, _>>()?;
648
649 if !token.is_ascii() {
650 return Err(DecoderError::NonAsciiSample.into());
651 }
652
653 let string = str::from_utf8(&token)
654 // We checked the precondition ourselves a few lines before with `token.is_ascii()`.
655 .unwrap_or_else(|_| unreachable!("Only ASCII characters should be decoded"));
656
657 string.parse()
658 .map_err(|err| DecoderError::UnparsableValue(ErrorDataSource::Sample, string.to_owned(), err).into())
659 }
660
661 impl Sample for U8 {
bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize>662 fn bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize> {
663 Ok((width * height * samples) as usize)
664 }
665
from_bytes( bytes: &[u8], width: u32, height: u32, samples: u32, ) -> ImageResult<Vec<u8>>666 fn from_bytes(
667 bytes: &[u8],
668 width: u32,
669 height: u32,
670 samples: u32,
671 ) -> ImageResult<Vec<u8>> {
672 assert_eq!(bytes.len(), Self::bytelen(width, height, samples).unwrap());
673 Ok(bytes.to_vec())
674 }
675
from_ascii( reader: &mut dyn Read, width: u32, height: u32, samples: u32, ) -> ImageResult<Vec<u8>>676 fn from_ascii(
677 reader: &mut dyn Read,
678 width: u32,
679 height: u32,
680 samples: u32,
681 ) -> ImageResult<Vec<u8>> {
682 (0..width*height*samples)
683 .map(|_| read_separated_ascii(reader))
684 .collect()
685 }
686 }
687
688 impl Sample for U16 {
bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize>689 fn bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize> {
690 Ok((width * height * samples * 2) as usize)
691 }
692
from_bytes( bytes: &[u8], width: u32, height: u32, samples: u32, ) -> ImageResult<Vec<u8>>693 fn from_bytes(
694 bytes: &[u8],
695 width: u32,
696 height: u32,
697 samples: u32,
698 ) -> ImageResult<Vec<u8>> {
699 assert_eq!(bytes.len(), Self::bytelen(width, height, samples).unwrap());
700
701 let mut buffer = bytes.to_vec();
702 for chunk in buffer.chunks_mut(2) {
703 let v = BigEndian::read_u16(chunk);
704 NativeEndian::write_u16(chunk, v);
705 }
706 Ok(buffer)
707 }
708
from_ascii( reader: &mut dyn Read, width: u32, height: u32, samples: u32, ) -> ImageResult<Vec<u8>>709 fn from_ascii(
710 reader: &mut dyn Read,
711 width: u32,
712 height: u32,
713 samples: u32,
714 ) -> ImageResult<Vec<u8>> {
715 let mut buffer = vec![0; (width * height * samples * 2) as usize];
716 for i in 0..(width*height*samples) as usize {
717 let v = read_separated_ascii::<u16>(reader)?;
718 NativeEndian::write_u16(&mut buffer[2*i..][..2], v);
719 }
720 Ok(buffer)
721 }
722 }
723
724 // The image is encoded in rows of bits, high order bits first. Any bits beyond the row bits should
725 // be ignored. Also, contrary to rgb, black pixels are encoded as a 1 while white is 0. This will
726 // need to be reversed for the grayscale output.
727 impl Sample for PbmBit {
bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize>728 fn bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize> {
729 let count = width * samples;
730 let linelen = (count / 8) + ((count % 8) != 0) as u32;
731 Ok((linelen * height) as usize)
732 }
733
from_bytes( bytes: &[u8], width: u32, height: u32, samples: u32, ) -> ImageResult<Vec<u8>>734 fn from_bytes(
735 bytes: &[u8],
736 width: u32,
737 height: u32,
738 samples: u32,
739 ) -> ImageResult<Vec<u8>> {
740 assert_eq!(bytes.len(), Self::bytelen(width, height, samples).unwrap());
741
742 let mut expanded = utils::expand_bits(1, width * samples, bytes);
743 for b in expanded.iter_mut() {
744 *b = !*b;
745 }
746 Ok(expanded)
747 }
748
from_ascii( reader: &mut dyn Read, width: u32, height: u32, samples: u32, ) -> ImageResult<Vec<u8>>749 fn from_ascii(
750 reader: &mut dyn Read,
751 width: u32,
752 height: u32,
753 samples: u32,
754 ) -> ImageResult<Vec<u8>> {
755 let count = (width*height*samples) as usize;
756 let raw_samples = reader.bytes()
757 .filter_map(|ascii| match ascii {
758 Ok(b'0') => Some(Ok(255)),
759 Ok(b'1') => Some(Ok(0)),
760 Err(err) => Some(Err(ImageError::IoError(err))),
761 Ok(b'\t')
762 | Ok(b'\n')
763 | Ok(b'\x0b')
764 | Ok(b'\x0c')
765 | Ok(b'\r')
766 | Ok(b' ') => None,
767 Ok(c) => Some(Err(DecoderError::UnexpectedByteInRaster(c).into())),
768 })
769 .take(count)
770 .collect::<ImageResult<Vec<u8>>>()?;
771
772 if raw_samples.len() < count {
773 return Err(DecoderError::InputTooShort.into());
774 }
775
776 Ok(raw_samples)
777 }
778 }
779
780 // Encoded just like a normal U8 but we check the values.
781 impl Sample for BWBit {
bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize>782 fn bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize> {
783 U8::bytelen(width, height, samples)
784 }
785
from_bytes( bytes: &[u8], width: u32, height: u32, samples: u32, ) -> ImageResult<Vec<u8>>786 fn from_bytes(
787 bytes: &[u8],
788 width: u32,
789 height: u32,
790 samples: u32,
791 ) -> ImageResult<Vec<u8>> {
792 assert_eq!(bytes.len(), Self::bytelen(width, height, samples).unwrap());
793
794 let values = U8::from_bytes(bytes, width, height, samples)?;
795 if let Some(val) = values.iter().find(|&val| *val > 1) {
796 return Err(DecoderError::SampleOutOfBounds(*val).into());
797 }
798 Ok(values)
799 }
800
from_ascii( _reader: &mut dyn Read, _width: u32, _height: u32, _samples: u32, ) -> ImageResult<Vec<u8>>801 fn from_ascii(
802 _reader: &mut dyn Read,
803 _width: u32,
804 _height: u32,
805 _samples: u32,
806 ) -> ImageResult<Vec<u8>> {
807 unreachable!("BW bits from anymaps are never encoded as ASCII")
808 }
809 }
810
811 impl DecodableImageHeader for BitmapHeader {
tuple_type(&self) -> ImageResult<TupleType>812 fn tuple_type(&self) -> ImageResult<TupleType> {
813 Ok(TupleType::PbmBit)
814 }
815 }
816
817 impl DecodableImageHeader for GraymapHeader {
tuple_type(&self) -> ImageResult<TupleType>818 fn tuple_type(&self) -> ImageResult<TupleType> {
819 match self.maxwhite {
820 v if v <= 0xFF => Ok(TupleType::GrayU8),
821 v if v <= 0xFFFF => Ok(TupleType::GrayU16),
822 _ => Err(DecoderError::MaxvalTooBig(self.maxwhite).into()),
823 }
824 }
825 }
826
827 impl DecodableImageHeader for PixmapHeader {
tuple_type(&self) -> ImageResult<TupleType>828 fn tuple_type(&self) -> ImageResult<TupleType> {
829 match self.maxval {
830 v if v <= 0xFF => Ok(TupleType::RGBU8),
831 v if v <= 0xFFFF => Ok(TupleType::RGBU16),
832 _ => Err(DecoderError::MaxvalTooBig(self.maxval).into()),
833 }
834 }
835 }
836
837 impl DecodableImageHeader for ArbitraryHeader {
tuple_type(&self) -> ImageResult<TupleType>838 fn tuple_type(&self) -> ImageResult<TupleType> {
839 match self.tupltype {
840 None if self.depth == 1 => Ok(TupleType::GrayU8),
841 None if self.depth == 2 => Err(ImageError::Unsupported(UnsupportedError::from_format_and_kind(
842 ImageFormat::Pnm.into(),
843 UnsupportedErrorKind::Color(ExtendedColorType::La8),
844 ))),
845 None if self.depth == 3 => Ok(TupleType::RGBU8),
846 None if self.depth == 4 => Err(ImageError::Unsupported(UnsupportedError::from_format_and_kind(
847 ImageFormat::Pnm.into(),
848 UnsupportedErrorKind::Color(ExtendedColorType::Rgba8),
849 ))),
850
851 Some(ArbitraryTuplType::BlackAndWhite) if self.maxval == 1 && self.depth == 1 => {
852 Ok(TupleType::BWBit)
853 }
854 Some(ArbitraryTuplType::BlackAndWhite) => Err(DecoderError::InvalidDepthOrMaxval {
855 tuple_type: ArbitraryTuplType::BlackAndWhite,
856 maxval: self.maxval,
857 depth: self.depth,
858 }.into()),
859
860 Some(ArbitraryTuplType::Grayscale) if self.depth == 1 && self.maxval <= 0xFF => {
861 Ok(TupleType::GrayU8)
862 }
863 Some(ArbitraryTuplType::Grayscale) if self.depth <= 1 && self.maxval <= 0xFFFF => {
864 Ok(TupleType::GrayU16)
865 }
866 Some(ArbitraryTuplType::Grayscale) => Err(DecoderError::InvalidDepthOrMaxval {
867 tuple_type: ArbitraryTuplType::Grayscale,
868 maxval: self.maxval,
869 depth: self.depth,
870 }.into()),
871
872 Some(ArbitraryTuplType::RGB) if self.depth == 3 && self.maxval <= 0xFF => {
873 Ok(TupleType::RGBU8)
874 }
875 Some(ArbitraryTuplType::RGB) if self.depth == 3 && self.maxval <= 0xFFFF => {
876 Ok(TupleType::RGBU16)
877 }
878 Some(ArbitraryTuplType::RGB) => Err(DecoderError::InvalidDepth {
879 tuple_type: ArbitraryTuplType::RGB,
880 depth: self.depth,
881 }.into()),
882
883 Some(ArbitraryTuplType::BlackAndWhiteAlpha) => {
884 Err(ImageError::Unsupported(UnsupportedError::from_format_and_kind(
885 ImageFormat::Pnm.into(),
886 UnsupportedErrorKind::GenericFeature(
887 format!("Color type {}", ArbitraryTuplType::BlackAndWhiteAlpha.name())),
888 )))
889 }
890 Some(ArbitraryTuplType::GrayscaleAlpha) => Err(ImageError::Unsupported(
891 UnsupportedError::from_format_and_kind(
892 ImageFormat::Pnm.into(),
893 UnsupportedErrorKind::Color(ExtendedColorType::La8),
894 ),
895 )),
896 Some(ArbitraryTuplType::RGBAlpha) => Err(ImageError::Unsupported(
897 UnsupportedError::from_format_and_kind(
898 ImageFormat::Pnm.into(),
899 UnsupportedErrorKind::Color(ExtendedColorType::Rgba8),
900 ),
901 )),
902 Some(ArbitraryTuplType::Custom(ref custom)) => Err(ImageError::Unsupported(
903 UnsupportedError::from_format_and_kind(
904 ImageFormat::Pnm.into(),
905 UnsupportedErrorKind::GenericFeature(format!(
906 "Tuple type {:?}",
907 custom
908 )),
909 ),
910 )),
911 None => Err(DecoderError::TupleTypeUnrecognised.into()),
912 }
913 }
914 }
915
916 #[cfg(test)]
917 mod tests {
918 use super::*;
919 /// Tests reading of a valid blackandwhite pam
920 #[test]
pam_blackandwhite()921 fn pam_blackandwhite() {
922 let pamdata = b"P7
923 WIDTH 4
924 HEIGHT 4
925 DEPTH 1
926 MAXVAL 1
927 TUPLTYPE BLACKANDWHITE
928 # Comment line
929 ENDHDR
930 \x01\x00\x00\x01\x01\x00\x00\x01\x01\x00\x00\x01\x01\x00\x00\x01";
931 let decoder = PnmDecoder::new(&pamdata[..]).unwrap();
932 assert_eq!(decoder.color_type(), ColorType::L8);
933 assert_eq!(decoder.original_color_type(), ExtendedColorType::L1);
934 assert_eq!(decoder.dimensions(), (4, 4));
935 assert_eq!(decoder.subtype(), PNMSubtype::ArbitraryMap);
936
937 let mut image = vec![0; decoder.total_bytes() as usize];
938 decoder.read_image(&mut image).unwrap();
939 assert_eq!(
940 image,
941 vec![0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00,
942 0x00, 0x01]
943 );
944 match PnmDecoder::new(&pamdata[..]).unwrap().into_inner() {
945 (
946 _,
947 PnmHeader {
948 decoded:
949 HeaderRecord::Arbitrary(ArbitraryHeader {
950 width: 4,
951 height: 4,
952 maxval: 1,
953 depth: 1,
954 tupltype: Some(ArbitraryTuplType::BlackAndWhite),
955 }),
956 encoded: _,
957 },
958 ) => (),
959 _ => panic!("Decoded header is incorrect"),
960 }
961 }
962
963 /// Tests reading of a valid grayscale pam
964 #[test]
pam_grayscale()965 fn pam_grayscale() {
966 let pamdata = b"P7
967 WIDTH 4
968 HEIGHT 4
969 DEPTH 1
970 MAXVAL 255
971 TUPLTYPE GRAYSCALE
972 # Comment line
973 ENDHDR
974 \xde\xad\xbe\xef\xde\xad\xbe\xef\xde\xad\xbe\xef\xde\xad\xbe\xef";
975 let decoder = PnmDecoder::new(&pamdata[..]).unwrap();
976 assert_eq!(decoder.color_type(), ColorType::L8);
977 assert_eq!(decoder.dimensions(), (4, 4));
978 assert_eq!(decoder.subtype(), PNMSubtype::ArbitraryMap);
979
980 let mut image = vec![0; decoder.total_bytes() as usize];
981 decoder.read_image(&mut image).unwrap();
982 assert_eq!(
983 image,
984 vec![0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad,
985 0xbe, 0xef]
986 );
987 match PnmDecoder::new(&pamdata[..]).unwrap().into_inner() {
988 (
989 _,
990 PnmHeader {
991 decoded:
992 HeaderRecord::Arbitrary(ArbitraryHeader {
993 width: 4,
994 height: 4,
995 depth: 1,
996 maxval: 255,
997 tupltype: Some(ArbitraryTuplType::Grayscale),
998 }),
999 encoded: _,
1000 },
1001 ) => (),
1002 _ => panic!("Decoded header is incorrect"),
1003 }
1004 }
1005
1006 /// Tests reading of a valid rgb pam
1007 #[test]
pam_rgb()1008 fn pam_rgb() {
1009 let pamdata = b"P7
1010 # Comment line
1011 MAXVAL 255
1012 TUPLTYPE RGB
1013 DEPTH 3
1014 WIDTH 2
1015 HEIGHT 2
1016 ENDHDR
1017 \xde\xad\xbe\xef\xde\xad\xbe\xef\xde\xad\xbe\xef";
1018 let decoder = PnmDecoder::new(&pamdata[..]).unwrap();
1019 assert_eq!(decoder.color_type(), ColorType::Rgb8);
1020 assert_eq!(decoder.dimensions(), (2, 2));
1021 assert_eq!(decoder.subtype(), PNMSubtype::ArbitraryMap);
1022
1023 let mut image = vec![0; decoder.total_bytes() as usize];
1024 decoder.read_image(&mut image).unwrap();
1025 assert_eq!(image,
1026 vec![0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef]);
1027 match PnmDecoder::new(&pamdata[..]).unwrap().into_inner() {
1028 (
1029 _,
1030 PnmHeader {
1031 decoded:
1032 HeaderRecord::Arbitrary(ArbitraryHeader {
1033 maxval: 255,
1034 tupltype: Some(ArbitraryTuplType::RGB),
1035 depth: 3,
1036 width: 2,
1037 height: 2,
1038 }),
1039 encoded: _,
1040 },
1041 ) => (),
1042 _ => panic!("Decoded header is incorrect"),
1043 }
1044 }
1045
1046 #[test]
pbm_binary()1047 fn pbm_binary() {
1048 // The data contains two rows of the image (each line is padded to the full byte). For
1049 // comments on its format, see documentation of `impl SampleType for PbmBit`.
1050 let pbmbinary = [&b"P4 6 2\n"[..], &[0b01101100 as u8, 0b10110111]].concat();
1051 let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap();
1052 assert_eq!(decoder.color_type(), ColorType::L8);
1053 assert_eq!(decoder.original_color_type(), ExtendedColorType::L1);
1054 assert_eq!(decoder.dimensions(), (6, 2));
1055 assert_eq!(
1056 decoder.subtype(),
1057 PNMSubtype::Bitmap(SampleEncoding::Binary)
1058 );
1059 let mut image = vec![0; decoder.total_bytes() as usize];
1060 decoder.read_image(&mut image).unwrap();
1061 assert_eq!(image, vec![255, 0, 0, 255, 0, 0, 0, 255, 0, 0, 255, 0]);
1062 match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() {
1063 (
1064 _,
1065 PnmHeader {
1066 decoded:
1067 HeaderRecord::Bitmap(BitmapHeader {
1068 encoding: SampleEncoding::Binary,
1069 width: 6,
1070 height: 2,
1071 }),
1072 encoded: _,
1073 },
1074 ) => (),
1075 _ => panic!("Decoded header is incorrect"),
1076 }
1077 }
1078
1079 /// A previous inifite loop.
1080 #[test]
pbm_binary_ascii_termination()1081 fn pbm_binary_ascii_termination() {
1082 use std::io::{Cursor, Error, ErrorKind, Read, Result};
1083 struct FailRead(Cursor<&'static [u8]>);
1084
1085 impl Read for FailRead {
1086 fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
1087 match self.0.read(buf) {
1088 Ok(n) if n > 0 => Ok(n),
1089 _ => Err(Error::new(
1090 ErrorKind::BrokenPipe,
1091 "Simulated broken pipe error"
1092 )),
1093 }
1094 }
1095 }
1096
1097 let pbmbinary = FailRead(Cursor::new(b"P1 1 1\n"));
1098
1099 let decoder = PnmDecoder::new(pbmbinary).unwrap();
1100 let mut image = vec![0; decoder.total_bytes() as usize];
1101 decoder.read_image(&mut image).expect_err("Image is malformed");
1102 }
1103
1104 #[test]
pbm_ascii()1105 fn pbm_ascii() {
1106 // The data contains two rows of the image (each line is padded to the full byte). For
1107 // comments on its format, see documentation of `impl SampleType for PbmBit`. Tests all
1108 // whitespace characters that should be allowed (the 6 characters according to POSIX).
1109 let pbmbinary = b"P1 6 2\n 0 1 1 0 1 1\n1 0 1 1 0\t\n\x0b\x0c\r1";
1110 let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap();
1111 assert_eq!(decoder.color_type(), ColorType::L8);
1112 assert_eq!(decoder.original_color_type(), ExtendedColorType::L1);
1113 assert_eq!(decoder.dimensions(), (6, 2));
1114 assert_eq!(decoder.subtype(), PNMSubtype::Bitmap(SampleEncoding::Ascii));
1115
1116 let mut image = vec![0; decoder.total_bytes() as usize];
1117 decoder.read_image(&mut image).unwrap();
1118 assert_eq!(image, vec![255, 0, 0, 255, 0, 0, 0, 255, 0, 0, 255, 0]);
1119 match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() {
1120 (
1121 _,
1122 PnmHeader {
1123 decoded:
1124 HeaderRecord::Bitmap(BitmapHeader {
1125 encoding: SampleEncoding::Ascii,
1126 width: 6,
1127 height: 2,
1128 }),
1129 encoded: _,
1130 },
1131 ) => (),
1132 _ => panic!("Decoded header is incorrect"),
1133 }
1134 }
1135
1136 #[test]
pbm_ascii_nospace()1137 fn pbm_ascii_nospace() {
1138 // The data contains two rows of the image (each line is padded to the full byte). Notably,
1139 // it is completely within specification for the ascii data not to contain separating
1140 // whitespace for the pbm format or any mix.
1141 let pbmbinary = b"P1 6 2\n011011101101";
1142 let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap();
1143 assert_eq!(decoder.color_type(), ColorType::L8);
1144 assert_eq!(decoder.original_color_type(), ExtendedColorType::L1);
1145 assert_eq!(decoder.dimensions(), (6, 2));
1146 assert_eq!(decoder.subtype(), PNMSubtype::Bitmap(SampleEncoding::Ascii));
1147
1148 let mut image = vec![0; decoder.total_bytes() as usize];
1149 decoder.read_image(&mut image).unwrap();
1150 assert_eq!(image, vec![255, 0, 0, 255, 0, 0, 0, 255, 0, 0, 255, 0]);
1151 match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() {
1152 (
1153 _,
1154 PnmHeader {
1155 decoded:
1156 HeaderRecord::Bitmap(BitmapHeader {
1157 encoding: SampleEncoding::Ascii,
1158 width: 6,
1159 height: 2,
1160 }),
1161 encoded: _,
1162 },
1163 ) => (),
1164 _ => panic!("Decoded header is incorrect"),
1165 }
1166 }
1167
1168 #[test]
pgm_binary()1169 fn pgm_binary() {
1170 // The data contains two rows of the image (each line is padded to the full byte). For
1171 // comments on its format, see documentation of `impl SampleType for PbmBit`.
1172 let elements = (0..16).collect::<Vec<_>>();
1173 let pbmbinary = [&b"P5 4 4 255\n"[..], &elements].concat();
1174 let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap();
1175 assert_eq!(decoder.color_type(), ColorType::L8);
1176 assert_eq!(decoder.dimensions(), (4, 4));
1177 assert_eq!(
1178 decoder.subtype(),
1179 PNMSubtype::Graymap(SampleEncoding::Binary)
1180 );
1181 let mut image = vec![0; decoder.total_bytes() as usize];
1182 decoder.read_image(&mut image).unwrap();
1183 assert_eq!(image, elements);
1184 match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() {
1185 (
1186 _,
1187 PnmHeader {
1188 decoded:
1189 HeaderRecord::Graymap(GraymapHeader {
1190 encoding: SampleEncoding::Binary,
1191 width: 4,
1192 height: 4,
1193 maxwhite: 255,
1194 }),
1195 encoded: _,
1196 },
1197 ) => (),
1198 _ => panic!("Decoded header is incorrect"),
1199 }
1200 }
1201
1202 #[test]
pgm_ascii()1203 fn pgm_ascii() {
1204 // The data contains two rows of the image (each line is padded to the full byte). For
1205 // comments on its format, see documentation of `impl SampleType for PbmBit`.
1206 let pbmbinary = b"P2 4 4 255\n 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15";
1207 let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap();
1208 assert_eq!(decoder.color_type(), ColorType::L8);
1209 assert_eq!(decoder.dimensions(), (4, 4));
1210 assert_eq!(
1211 decoder.subtype(),
1212 PNMSubtype::Graymap(SampleEncoding::Ascii)
1213 );
1214 let mut image = vec![0; decoder.total_bytes() as usize];
1215 decoder.read_image(&mut image).unwrap();
1216 assert_eq!(image, (0..16).collect::<Vec<_>>());
1217 match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() {
1218 (
1219 _,
1220 PnmHeader {
1221 decoded:
1222 HeaderRecord::Graymap(GraymapHeader {
1223 encoding: SampleEncoding::Ascii,
1224 width: 4,
1225 height: 4,
1226 maxwhite: 255,
1227 }),
1228 encoded: _,
1229 },
1230 ) => (),
1231 _ => panic!("Decoded header is incorrect"),
1232 }
1233 }
1234
1235 #[test]
dimension_overflow()1236 fn dimension_overflow() {
1237 let pamdata = b"P7
1238 # Comment line
1239 MAXVAL 255
1240 TUPLTYPE RGB
1241 DEPTH 3
1242 WIDTH 4294967295
1243 HEIGHT 4294967295
1244 ENDHDR
1245 \xde\xad\xbe\xef\xde\xad\xbe\xef\xde\xad\xbe\xef";
1246
1247 assert!(PnmDecoder::new(&pamdata[..]).is_err());
1248 }
1249 }
1250