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 _ => Err(DecoderError::PnmMagicInvalid(magic))?,
241 };
242
243 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
251 /// Extract the reader and header after an image has been read.
into_inner(self) -> (R, PNMHeader)252 pub fn into_inner(self) -> (R, PNMHeader) {
253 (self.reader.into_inner(), self.header)
254 }
255
read_bitmap_header( mut reader: BufReader<R>, encoding: SampleEncoding, ) -> ImageResult<PnmDecoder<R>>256 fn read_bitmap_header(
257 mut reader: BufReader<R>,
258 encoding: SampleEncoding,
259 ) -> ImageResult<PnmDecoder<R>> {
260 let header = reader.read_bitmap_header(encoding)?;
261 Ok(PnmDecoder {
262 reader,
263 tuple: TupleType::PbmBit,
264 header: PNMHeader {
265 decoded: HeaderRecord::Bitmap(header),
266 encoded: None,
267 },
268 })
269 }
270
read_graymap_header( mut reader: BufReader<R>, encoding: SampleEncoding, ) -> ImageResult<PnmDecoder<R>>271 fn read_graymap_header(
272 mut reader: BufReader<R>,
273 encoding: SampleEncoding,
274 ) -> ImageResult<PnmDecoder<R>> {
275 let header = reader.read_graymap_header(encoding)?;
276 let tuple_type = header.tuple_type()?;
277 Ok(PnmDecoder {
278 reader,
279 tuple: tuple_type,
280 header: PNMHeader {
281 decoded: HeaderRecord::Graymap(header),
282 encoded: None,
283 },
284 })
285 }
286
read_pixmap_header( mut reader: BufReader<R>, encoding: SampleEncoding, ) -> ImageResult<PnmDecoder<R>>287 fn read_pixmap_header(
288 mut reader: BufReader<R>,
289 encoding: SampleEncoding,
290 ) -> ImageResult<PnmDecoder<R>> {
291 let header = reader.read_pixmap_header(encoding)?;
292 let tuple_type = header.tuple_type()?;
293 Ok(PnmDecoder {
294 reader,
295 tuple: tuple_type,
296 header: PNMHeader {
297 decoded: HeaderRecord::Pixmap(header),
298 encoded: None,
299 },
300 })
301 }
302
read_arbitrary_header(mut reader: BufReader<R>) -> ImageResult<PnmDecoder<R>>303 fn read_arbitrary_header(mut reader: BufReader<R>) -> ImageResult<PnmDecoder<R>> {
304 let header = reader.read_arbitrary_header()?;
305 let tuple_type = header.tuple_type()?;
306 Ok(PnmDecoder {
307 reader,
308 tuple: tuple_type,
309 header: PNMHeader {
310 decoded: HeaderRecord::Arbitrary(header),
311 encoded: None,
312 },
313 })
314 }
315 }
316
317 trait HeaderReader: BufRead {
318 /// Reads the two magic constant bytes
read_magic_constant(&mut self) -> ImageResult<[u8; 2]>319 fn read_magic_constant(&mut self) -> ImageResult<[u8; 2]> {
320 let mut magic: [u8; 2] = [0, 0];
321 self.read_exact(&mut magic)?;
322 Ok(magic)
323 }
324
325 /// Reads a string as well as a single whitespace after it, ignoring comments
read_next_string(&mut self) -> ImageResult<String>326 fn read_next_string(&mut self) -> ImageResult<String> {
327 let mut bytes = Vec::new();
328
329 // pair input bytes with a bool mask to remove comments
330 let mark_comments = self.bytes().scan(true, |partof, read| {
331 let byte = match read {
332 Err(err) => return Some((*partof, Err(err))),
333 Ok(byte) => byte,
334 };
335 let cur_enabled = *partof && byte != b'#';
336 let next_enabled = cur_enabled || (byte == b'\r' || byte == b'\n');
337 *partof = next_enabled;
338 Some((cur_enabled, Ok(byte)))
339 });
340
341 for (_, byte) in mark_comments.filter(|ref e| e.0) {
342 match byte {
343 Ok(b'\t') | Ok(b'\n') | Ok(b'\x0b') | Ok(b'\x0c') | Ok(b'\r') | Ok(b' ') => {
344 if !bytes.is_empty() {
345 break; // We're done as we already have some content
346 }
347 }
348 Ok(byte) if !byte.is_ascii() => Err(DecoderError::NonAsciiByteInHeader(byte))?,
349 Ok(byte) => {
350 bytes.push(byte);
351 },
352 Err(_) => break,
353 }
354 }
355
356 if bytes.is_empty() {
357 return Err(ImageError::IoError(io::ErrorKind::UnexpectedEof.into()));
358 }
359
360 if !bytes.as_slice().is_ascii() {
361 // We have only filled the buffer with characters for which `byte.is_ascii()` holds.
362 unreachable!("Non-ASCII character should have returned sooner")
363 }
364
365 let string = String::from_utf8(bytes)
366 // We checked the precondition ourselves a few lines before, `bytes.as_slice().is_ascii()`.
367 .unwrap_or_else(|_| unreachable!("Only ASCII characters should be decoded"));
368
369 Ok(string)
370 }
371
372 /// Read the next line
read_next_line(&mut self) -> ImageResult<String>373 fn read_next_line(&mut self) -> ImageResult<String> {
374 let mut buffer = String::new();
375 self.read_line(&mut buffer)?;
376 Ok(buffer)
377 }
378
read_next_u32(&mut self) -> ImageResult<u32>379 fn read_next_u32(&mut self) -> ImageResult<u32> {
380 let s = self.read_next_string()?;
381 s.parse::<u32>()
382 .map_err(|err| DecoderError::UnparsableValue(ErrorDataSource::Preamble, s, err).into())
383 }
384
read_bitmap_header(&mut self, encoding: SampleEncoding) -> ImageResult<BitmapHeader>385 fn read_bitmap_header(&mut self, encoding: SampleEncoding) -> ImageResult<BitmapHeader> {
386 let width = self.read_next_u32()?;
387 let height = self.read_next_u32()?;
388 Ok(BitmapHeader {
389 encoding,
390 width,
391 height,
392 })
393 }
394
read_graymap_header(&mut self, encoding: SampleEncoding) -> ImageResult<GraymapHeader>395 fn read_graymap_header(&mut self, encoding: SampleEncoding) -> ImageResult<GraymapHeader> {
396 self.read_pixmap_header(encoding).map(
397 |PixmapHeader {
398 encoding,
399 width,
400 height,
401 maxval,
402 }| GraymapHeader {
403 encoding,
404 width,
405 height,
406 maxwhite: maxval,
407 },
408 )
409 }
410
read_pixmap_header(&mut self, encoding: SampleEncoding) -> ImageResult<PixmapHeader>411 fn read_pixmap_header(&mut self, encoding: SampleEncoding) -> ImageResult<PixmapHeader> {
412 let width = self.read_next_u32()?;
413 let height = self.read_next_u32()?;
414 let maxval = self.read_next_u32()?;
415 Ok(PixmapHeader {
416 encoding,
417 width,
418 height,
419 maxval,
420 })
421 }
422
read_arbitrary_header(&mut self) -> ImageResult<ArbitraryHeader>423 fn read_arbitrary_header(&mut self) -> ImageResult<ArbitraryHeader> {
424 fn parse_single_value_line(line_val: &mut Option<u32>, rest: &str, line: PnmHeaderLine) -> ImageResult<()> {
425 if line_val.is_some() {
426 return Err(DecoderError::HeaderLineDuplicated(line).into());
427 } else {
428 let v = rest.trim().parse().map_err(|err| DecoderError::UnparsableValue(ErrorDataSource::Line(line), rest.to_owned(), err))?;
429 *line_val = Some(v);
430 Ok(())
431 }
432 }
433
434 match self.bytes().next() {
435 None => return Err(ImageError::IoError(io::ErrorKind::UnexpectedEof.into())),
436 Some(Err(io)) => return Err(ImageError::IoError(io)),
437 Some(Ok(b'\n')) => (),
438 Some(Ok(c)) => return Err(DecoderError::NotNewlineAfterP7Magic(c).into()),
439 }
440
441 let mut line = String::new();
442 let mut height: Option<u32> = None;
443 let mut width: Option<u32> = None;
444 let mut depth: Option<u32> = None;
445 let mut maxval: Option<u32> = None;
446 let mut tupltype: Option<String> = None;
447 loop {
448 line.truncate(0);
449 let len = self.read_line(&mut line)?;
450 if len == 0 {
451 return Err(DecoderError::UnexpectedPnmHeaderEnd.into());
452 }
453 if line.as_bytes()[0] == b'#' {
454 continue;
455 }
456 if !line.is_ascii() {
457 return Err(DecoderError::NonAsciiLineInPamHeader.into());
458 }
459 #[allow(deprecated)]
460 let (identifier, rest) = line.trim_left()
461 .split_at(line.find(char::is_whitespace).unwrap_or_else(|| line.len()));
462 match identifier {
463 "ENDHDR" => break,
464 "HEIGHT" => parse_single_value_line(&mut height, rest, PnmHeaderLine::Height)?,
465 "WIDTH" => parse_single_value_line(&mut width, rest, PnmHeaderLine::Width)?,
466 "DEPTH" => parse_single_value_line(&mut depth, rest, PnmHeaderLine::Depth)?,
467 "MAXVAL" => parse_single_value_line(&mut maxval, rest, PnmHeaderLine::Maxval)?,
468 "TUPLTYPE" => {
469 let identifier = rest.trim();
470 if tupltype.is_some() {
471 let appended = tupltype.take().map(|mut v| {
472 v.push(' ');
473 v.push_str(identifier);
474 v
475 });
476 tupltype = appended;
477 } else {
478 tupltype = Some(identifier.to_string());
479 }
480 }
481 _ => return Err(DecoderError::HeaderLineUnknown(identifier.to_string()).into()),
482 }
483 }
484
485 let (h, w, d, m) = match (height, width, depth, maxval) {
486 (Some(h), Some(w), Some(d), Some(m)) => (h, w, d, m),
487 _ => return Err(DecoderError::HeaderLineMissing { height, width, depth, maxval }.into()),
488 };
489
490 let tupltype = match tupltype {
491 None => None,
492 Some(ref t) if t == "BLACKANDWHITE" => Some(ArbitraryTuplType::BlackAndWhite),
493 Some(ref t) if t == "BLACKANDWHITE_ALPHA" => Some(ArbitraryTuplType::BlackAndWhiteAlpha),
494 Some(ref t) if t == "GRAYSCALE" => Some(ArbitraryTuplType::Grayscale),
495 Some(ref t) if t == "GRAYSCALE_ALPHA" => Some(ArbitraryTuplType::GrayscaleAlpha),
496 Some(ref t) if t == "RGB" => Some(ArbitraryTuplType::RGB),
497 Some(ref t) if t == "RGB_ALPHA" => Some(ArbitraryTuplType::RGBAlpha),
498 Some(other) => Some(ArbitraryTuplType::Custom(other)),
499 };
500
501 Ok(ArbitraryHeader {
502 height: h,
503 width: w,
504 depth: d,
505 maxval: m,
506 tupltype,
507 })
508 }
509 }
510
511 impl<R: Read> HeaderReader for BufReader<R> {}
512
513 /// Wrapper struct around a `Cursor<Vec<u8>>`
514 pub struct PnmReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
515 impl<R> Read for PnmReader<R> {
read(&mut self, buf: &mut [u8]) -> io::Result<usize>516 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
517 self.0.read(buf)
518 }
read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize>519 fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
520 if self.0.position() == 0 && buf.is_empty() {
521 mem::swap(buf, self.0.get_mut());
522 Ok(buf.len())
523 } else {
524 self.0.read_to_end(buf)
525 }
526 }
527 }
528
529 impl<'a, R: 'a + Read> ImageDecoder<'a> for PnmDecoder<R> {
530 type Reader = PnmReader<R>;
531
dimensions(&self) -> (u32, u32)532 fn dimensions(&self) -> (u32, u32) {
533 (self.header.width(), self.header.height())
534 }
535
color_type(&self) -> ColorType536 fn color_type(&self) -> ColorType {
537 match self.tuple {
538 TupleType::PbmBit => ColorType::L8,
539 TupleType::BWBit => ColorType::L8,
540 TupleType::GrayU8 => ColorType::L8,
541 TupleType::GrayU16 => ColorType::L16,
542 TupleType::RGBU8 => ColorType::Rgb8,
543 TupleType::RGBU16 => ColorType::Rgb16,
544 }
545 }
546
original_color_type(&self) -> ExtendedColorType547 fn original_color_type(&self) -> ExtendedColorType {
548 match self.tuple {
549 TupleType::PbmBit => ExtendedColorType::L1,
550 TupleType::BWBit => ExtendedColorType::L1,
551 TupleType::GrayU8 => ExtendedColorType::L8,
552 TupleType::GrayU16 => ExtendedColorType::L16,
553 TupleType::RGBU8 => ExtendedColorType::Rgb8,
554 TupleType::RGBU16 => ExtendedColorType::Rgb16,
555 }
556 }
557
into_reader(self) -> ImageResult<Self::Reader>558 fn into_reader(self) -> ImageResult<Self::Reader> {
559 Ok(PnmReader(Cursor::new(image::decoder_to_vec(self)?), PhantomData))
560 }
561
read_image(mut self, buf: &mut [u8]) -> ImageResult<()>562 fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> {
563 assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));
564 buf.copy_from_slice(&match self.tuple {
565 TupleType::PbmBit => self.read_samples::<PbmBit>(1),
566 TupleType::BWBit => self.read_samples::<BWBit>(1),
567 TupleType::RGBU8 => self.read_samples::<U8>(3),
568 TupleType::RGBU16 => self.read_samples::<U16>(3),
569 TupleType::GrayU8 => self.read_samples::<U8>(1),
570 TupleType::GrayU16 => self.read_samples::<U16>(1),
571 }?);
572 Ok(())
573 }
574 }
575
576 impl<R: Read> PnmDecoder<R> {
read_samples<S: Sample>(&mut self, components: u32) -> ImageResult<Vec<u8>>577 fn read_samples<S: Sample>(&mut self, components: u32) -> ImageResult<Vec<u8>> {
578 match self.subtype().sample_encoding() {
579 SampleEncoding::Binary => {
580 let width = self.header.width();
581 let height = self.header.height();
582 let bytecount = S::bytelen(width, height, components)?;
583 let mut bytes = vec![];
584
585 self.reader
586 .by_ref()
587 // This conversion is potentially lossy but unlikely and in that case we error
588 // later anyways.
589 .take(bytecount as u64)
590 .read_to_end(&mut bytes)?;
591
592 if bytes.len() != bytecount {
593 return Err(DecoderError::InputTooShort.into());
594 }
595
596 let samples = S::from_bytes(&bytes, width, height, components)?;
597 Ok(samples)
598 }
599 SampleEncoding::Ascii => {
600 let samples = self.read_ascii::<S>(components)?;
601 Ok(samples)
602 }
603 }
604 }
605
read_ascii<Basic: Sample>(&mut self, components: u32) -> ImageResult<Vec<u8>>606 fn read_ascii<Basic: Sample>(&mut self, components: u32) -> ImageResult<Vec<u8>> {
607 Basic::from_ascii(&mut self.reader, self.header.width(), self.header.height(), components)
608 }
609
610 /// Get the pnm subtype, depending on the magic constant contained in the header
subtype(&self) -> PNMSubtype611 pub fn subtype(&self) -> PNMSubtype {
612 self.header.subtype()
613 }
614 }
615
read_separated_ascii<T: FromStr<Err = ParseIntError>>(reader: &mut dyn Read) -> ImageResult<T> where T::Err: Display616 fn read_separated_ascii<T: FromStr<Err = ParseIntError>>(reader: &mut dyn Read) -> ImageResult<T>
617 where T::Err: Display
618 {
619 let is_separator = |v: &u8| match *v {
620 b'\t' | b'\n' | b'\x0b' | b'\x0c' | b'\r' | b' ' => true,
621 _ => false,
622 };
623
624 let token = reader
625 .bytes()
626 .skip_while(|v| v.as_ref().ok().map(&is_separator).unwrap_or(false))
627 .take_while(|v| v.as_ref().ok().map(|c| !is_separator(c)).unwrap_or(false))
628 .collect::<Result<Vec<u8>, _>>()?;
629
630 if !token.is_ascii() {
631 return Err(DecoderError::NonAsciiSample.into());
632 }
633
634 let string = str::from_utf8(&token)
635 // We checked the precondition ourselves a few lines before with `token.is_ascii()`.
636 .unwrap_or_else(|_| unreachable!("Only ASCII characters should be decoded"));
637
638 string.parse()
639 .map_err(|err| DecoderError::UnparsableValue(ErrorDataSource::Sample, string.to_owned(), err).into())
640 }
641
642 impl Sample for U8 {
bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize>643 fn bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize> {
644 Ok((width * height * samples) as usize)
645 }
646
from_bytes( bytes: &[u8], width: u32, height: u32, samples: u32, ) -> ImageResult<Vec<u8>>647 fn from_bytes(
648 bytes: &[u8],
649 width: u32,
650 height: u32,
651 samples: u32,
652 ) -> ImageResult<Vec<u8>> {
653 assert_eq!(bytes.len(), Self::bytelen(width, height, samples).unwrap());
654 Ok(bytes.to_vec())
655 }
656
from_ascii( reader: &mut dyn Read, width: u32, height: u32, samples: u32, ) -> ImageResult<Vec<u8>>657 fn from_ascii(
658 reader: &mut dyn Read,
659 width: u32,
660 height: u32,
661 samples: u32,
662 ) -> ImageResult<Vec<u8>> {
663 (0..width*height*samples)
664 .map(|_| read_separated_ascii(reader))
665 .collect()
666 }
667 }
668
669 impl Sample for U16 {
bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize>670 fn bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize> {
671 Ok((width * height * samples * 2) as usize)
672 }
673
from_bytes( bytes: &[u8], width: u32, height: u32, samples: u32, ) -> ImageResult<Vec<u8>>674 fn from_bytes(
675 bytes: &[u8],
676 width: u32,
677 height: u32,
678 samples: u32,
679 ) -> ImageResult<Vec<u8>> {
680 assert_eq!(bytes.len(), Self::bytelen(width, height, samples).unwrap());
681
682 let mut buffer = bytes.to_vec();
683 for chunk in buffer.chunks_mut(2) {
684 let v = BigEndian::read_u16(chunk);
685 NativeEndian::write_u16(chunk, v);
686 }
687 Ok(buffer)
688 }
689
from_ascii( reader: &mut dyn Read, width: u32, height: u32, samples: u32, ) -> ImageResult<Vec<u8>>690 fn from_ascii(
691 reader: &mut dyn Read,
692 width: u32,
693 height: u32,
694 samples: u32,
695 ) -> ImageResult<Vec<u8>> {
696 let mut buffer = vec![0; (width * height * samples * 2) as usize];
697 for i in 0..(width*height*samples) as usize {
698 let v = read_separated_ascii::<u16>(reader)?;
699 NativeEndian::write_u16(&mut buffer[2*i..][..2], v);
700 }
701 Ok(buffer)
702 }
703 }
704
705 // The image is encoded in rows of bits, high order bits first. Any bits beyond the row bits should
706 // be ignored. Also, contrary to rgb, black pixels are encoded as a 1 while white is 0. This will
707 // need to be reversed for the grayscale output.
708 impl Sample for PbmBit {
bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize>709 fn bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize> {
710 let count = width * samples;
711 let linelen = (count / 8) + ((count % 8) != 0) as u32;
712 Ok((linelen * height) as usize)
713 }
714
from_bytes( bytes: &[u8], width: u32, height: u32, samples: u32, ) -> ImageResult<Vec<u8>>715 fn from_bytes(
716 bytes: &[u8],
717 width: u32,
718 height: u32,
719 samples: u32,
720 ) -> ImageResult<Vec<u8>> {
721 assert_eq!(bytes.len(), Self::bytelen(width, height, samples).unwrap());
722
723 let mut expanded = utils::expand_bits(1, width * samples, bytes);
724 for b in expanded.iter_mut() {
725 *b = !*b;
726 }
727 Ok(expanded)
728 }
729
from_ascii( reader: &mut dyn Read, width: u32, height: u32, samples: u32, ) -> ImageResult<Vec<u8>>730 fn from_ascii(
731 reader: &mut dyn Read,
732 width: u32,
733 height: u32,
734 samples: u32,
735 ) -> ImageResult<Vec<u8>> {
736 let count = (width*height*samples) as usize;
737 let raw_samples = reader.bytes()
738 .filter_map(|ascii| match ascii {
739 Ok(b'0') => Some(Ok(1)),
740 Ok(b'1') => Some(Ok(0)),
741 Err(err) => Some(Err(ImageError::IoError(err))),
742 Ok(b'\t')
743 | Ok(b'\n')
744 | Ok(b'\x0b')
745 | Ok(b'\x0c')
746 | Ok(b'\r')
747 | Ok(b' ') => None,
748 Ok(c) => Some(Err(DecoderError::UnexpectedByteInRaster(c).into())),
749 })
750 .take(count)
751 .collect::<ImageResult<Vec<u8>>>()?;
752
753 if raw_samples.len() < count {
754 return Err(DecoderError::InputTooShort.into());
755 }
756
757 Ok(raw_samples)
758 }
759 }
760
761 // Encoded just like a normal U8 but we check the values.
762 impl Sample for BWBit {
bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize>763 fn bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize> {
764 U8::bytelen(width, height, samples)
765 }
766
from_bytes( bytes: &[u8], width: u32, height: u32, samples: u32, ) -> ImageResult<Vec<u8>>767 fn from_bytes(
768 bytes: &[u8],
769 width: u32,
770 height: u32,
771 samples: u32,
772 ) -> ImageResult<Vec<u8>> {
773 assert_eq!(bytes.len(), Self::bytelen(width, height, samples).unwrap());
774
775 let values = U8::from_bytes(bytes, width, height, samples)?;
776 if let Some(val) = values.iter().find(|&val| *val > 1) {
777 return Err(DecoderError::SampleOutOfBounds(*val).into());
778 }
779 Ok(values)
780 }
781
from_ascii( _reader: &mut dyn Read, _width: u32, _height: u32, _samples: u32, ) -> ImageResult<Vec<u8>>782 fn from_ascii(
783 _reader: &mut dyn Read,
784 _width: u32,
785 _height: u32,
786 _samples: u32,
787 ) -> ImageResult<Vec<u8>> {
788 unreachable!("BW bits from anymaps are never encoded as ASCII")
789 }
790 }
791
792 impl DecodableImageHeader for BitmapHeader {
tuple_type(&self) -> ImageResult<TupleType>793 fn tuple_type(&self) -> ImageResult<TupleType> {
794 Ok(TupleType::PbmBit)
795 }
796 }
797
798 impl DecodableImageHeader for GraymapHeader {
tuple_type(&self) -> ImageResult<TupleType>799 fn tuple_type(&self) -> ImageResult<TupleType> {
800 match self.maxwhite {
801 v if v <= 0xFF => Ok(TupleType::GrayU8),
802 v if v <= 0xFFFF => Ok(TupleType::GrayU16),
803 _ => Err(DecoderError::MaxvalTooBig(self.maxwhite).into()),
804 }
805 }
806 }
807
808 impl DecodableImageHeader for PixmapHeader {
tuple_type(&self) -> ImageResult<TupleType>809 fn tuple_type(&self) -> ImageResult<TupleType> {
810 match self.maxval {
811 v if v <= 0xFF => Ok(TupleType::RGBU8),
812 v if v <= 0xFFFF => Ok(TupleType::RGBU16),
813 _ => Err(DecoderError::MaxvalTooBig(self.maxval).into()),
814 }
815 }
816 }
817
818 impl DecodableImageHeader for ArbitraryHeader {
tuple_type(&self) -> ImageResult<TupleType>819 fn tuple_type(&self) -> ImageResult<TupleType> {
820 match self.tupltype {
821 None if self.depth == 1 => Ok(TupleType::GrayU8),
822 None if self.depth == 2 => Err(ImageError::Unsupported(UnsupportedError::from_format_and_kind(
823 ImageFormat::Pnm.into(),
824 UnsupportedErrorKind::Color(ExtendedColorType::La8),
825 ))),
826 None if self.depth == 3 => Ok(TupleType::RGBU8),
827 None if self.depth == 4 => Err(ImageError::Unsupported(UnsupportedError::from_format_and_kind(
828 ImageFormat::Pnm.into(),
829 UnsupportedErrorKind::Color(ExtendedColorType::Rgba8),
830 ))),
831
832 Some(ArbitraryTuplType::BlackAndWhite) if self.maxval == 1 && self.depth == 1 => {
833 Ok(TupleType::BWBit)
834 }
835 Some(ArbitraryTuplType::BlackAndWhite) => Err(DecoderError::InvalidDepthOrMaxval {
836 tuple_type: ArbitraryTuplType::BlackAndWhite,
837 maxval: self.maxval,
838 depth: self.depth,
839 }.into()),
840
841 Some(ArbitraryTuplType::Grayscale) if self.depth == 1 && self.maxval <= 0xFF => {
842 Ok(TupleType::GrayU8)
843 }
844 Some(ArbitraryTuplType::Grayscale) if self.depth <= 1 && self.maxval <= 0xFFFF => {
845 Ok(TupleType::GrayU16)
846 }
847 Some(ArbitraryTuplType::Grayscale) => Err(DecoderError::InvalidDepthOrMaxval {
848 tuple_type: ArbitraryTuplType::Grayscale,
849 maxval: self.maxval,
850 depth: self.depth,
851 }.into()),
852
853 Some(ArbitraryTuplType::RGB) if self.depth == 3 && self.maxval <= 0xFF => {
854 Ok(TupleType::RGBU8)
855 }
856 Some(ArbitraryTuplType::RGB) if self.depth == 3 && self.maxval <= 0xFFFF => {
857 Ok(TupleType::RGBU16)
858 }
859 Some(ArbitraryTuplType::RGB) => Err(DecoderError::InvalidDepth {
860 tuple_type: ArbitraryTuplType::RGB,
861 depth: self.depth,
862 }.into()),
863
864 Some(ArbitraryTuplType::BlackAndWhiteAlpha) => {
865 Err(ImageError::Unsupported(UnsupportedError::from_format_and_kind(
866 ImageFormat::Pnm.into(),
867 UnsupportedErrorKind::GenericFeature(
868 format!("Color type {}", ArbitraryTuplType::BlackAndWhiteAlpha.name())),
869 )))
870 }
871 Some(ArbitraryTuplType::GrayscaleAlpha) => Err(ImageError::Unsupported(
872 UnsupportedError::from_format_and_kind(
873 ImageFormat::Pnm.into(),
874 UnsupportedErrorKind::Color(ExtendedColorType::La8),
875 ),
876 )),
877 Some(ArbitraryTuplType::RGBAlpha) => Err(ImageError::Unsupported(
878 UnsupportedError::from_format_and_kind(
879 ImageFormat::Pnm.into(),
880 UnsupportedErrorKind::Color(ExtendedColorType::Rgba8),
881 ),
882 )),
883 Some(ArbitraryTuplType::Custom(ref custom)) => Err(ImageError::Unsupported(
884 UnsupportedError::from_format_and_kind(
885 ImageFormat::Pnm.into(),
886 UnsupportedErrorKind::GenericFeature(format!(
887 "Tuple type {:?}",
888 custom
889 )),
890 ),
891 )),
892 None => Err(DecoderError::TupleTypeUnrecognised.into()),
893 }
894 }
895 }
896
897 #[cfg(test)]
898 mod tests {
899 use super::*;
900 /// Tests reading of a valid blackandwhite pam
901 #[test]
pam_blackandwhite()902 fn pam_blackandwhite() {
903 let pamdata = b"P7
904 WIDTH 4
905 HEIGHT 4
906 DEPTH 1
907 MAXVAL 1
908 TUPLTYPE BLACKANDWHITE
909 # Comment line
910 ENDHDR
911 \x01\x00\x00\x01\x01\x00\x00\x01\x01\x00\x00\x01\x01\x00\x00\x01";
912 let decoder = PnmDecoder::new(&pamdata[..]).unwrap();
913 assert_eq!(decoder.color_type(), ColorType::L8);
914 assert_eq!(decoder.original_color_type(), ExtendedColorType::L1);
915 assert_eq!(decoder.dimensions(), (4, 4));
916 assert_eq!(decoder.subtype(), PNMSubtype::ArbitraryMap);
917
918 let mut image = vec![0; decoder.total_bytes() as usize];
919 decoder.read_image(&mut image).unwrap();
920 assert_eq!(
921 image,
922 vec![0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00,
923 0x00, 0x01]
924 );
925 match PnmDecoder::new(&pamdata[..]).unwrap().into_inner() {
926 (
927 _,
928 PNMHeader {
929 decoded:
930 HeaderRecord::Arbitrary(ArbitraryHeader {
931 width: 4,
932 height: 4,
933 maxval: 1,
934 depth: 1,
935 tupltype: Some(ArbitraryTuplType::BlackAndWhite),
936 }),
937 encoded: _,
938 },
939 ) => (),
940 _ => panic!("Decoded header is incorrect"),
941 }
942 }
943
944 /// Tests reading of a valid grayscale pam
945 #[test]
pam_grayscale()946 fn pam_grayscale() {
947 let pamdata = b"P7
948 WIDTH 4
949 HEIGHT 4
950 DEPTH 1
951 MAXVAL 255
952 TUPLTYPE GRAYSCALE
953 # Comment line
954 ENDHDR
955 \xde\xad\xbe\xef\xde\xad\xbe\xef\xde\xad\xbe\xef\xde\xad\xbe\xef";
956 let decoder = PnmDecoder::new(&pamdata[..]).unwrap();
957 assert_eq!(decoder.color_type(), ColorType::L8);
958 assert_eq!(decoder.dimensions(), (4, 4));
959 assert_eq!(decoder.subtype(), PNMSubtype::ArbitraryMap);
960
961 let mut image = vec![0; decoder.total_bytes() as usize];
962 decoder.read_image(&mut image).unwrap();
963 assert_eq!(
964 image,
965 vec![0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad,
966 0xbe, 0xef]
967 );
968 match PnmDecoder::new(&pamdata[..]).unwrap().into_inner() {
969 (
970 _,
971 PNMHeader {
972 decoded:
973 HeaderRecord::Arbitrary(ArbitraryHeader {
974 width: 4,
975 height: 4,
976 depth: 1,
977 maxval: 255,
978 tupltype: Some(ArbitraryTuplType::Grayscale),
979 }),
980 encoded: _,
981 },
982 ) => (),
983 _ => panic!("Decoded header is incorrect"),
984 }
985 }
986
987 /// Tests reading of a valid rgb pam
988 #[test]
pam_rgb()989 fn pam_rgb() {
990 let pamdata = b"P7
991 # Comment line
992 MAXVAL 255
993 TUPLTYPE RGB
994 DEPTH 3
995 WIDTH 2
996 HEIGHT 2
997 ENDHDR
998 \xde\xad\xbe\xef\xde\xad\xbe\xef\xde\xad\xbe\xef";
999 let decoder = PnmDecoder::new(&pamdata[..]).unwrap();
1000 assert_eq!(decoder.color_type(), ColorType::Rgb8);
1001 assert_eq!(decoder.dimensions(), (2, 2));
1002 assert_eq!(decoder.subtype(), PNMSubtype::ArbitraryMap);
1003
1004 let mut image = vec![0; decoder.total_bytes() as usize];
1005 decoder.read_image(&mut image).unwrap();
1006 assert_eq!(image,
1007 vec![0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef]);
1008 match PnmDecoder::new(&pamdata[..]).unwrap().into_inner() {
1009 (
1010 _,
1011 PNMHeader {
1012 decoded:
1013 HeaderRecord::Arbitrary(ArbitraryHeader {
1014 maxval: 255,
1015 tupltype: Some(ArbitraryTuplType::RGB),
1016 depth: 3,
1017 width: 2,
1018 height: 2,
1019 }),
1020 encoded: _,
1021 },
1022 ) => (),
1023 _ => panic!("Decoded header is incorrect"),
1024 }
1025 }
1026
1027 #[test]
pbm_binary()1028 fn pbm_binary() {
1029 // The data contains two rows of the image (each line is padded to the full byte). For
1030 // comments on its format, see documentation of `impl SampleType for PbmBit`.
1031 let pbmbinary = [&b"P4 6 2\n"[..], &[0b01101100 as u8, 0b10110111]].concat();
1032 let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap();
1033 assert_eq!(decoder.color_type(), ColorType::L8);
1034 assert_eq!(decoder.original_color_type(), ExtendedColorType::L1);
1035 assert_eq!(decoder.dimensions(), (6, 2));
1036 assert_eq!(
1037 decoder.subtype(),
1038 PNMSubtype::Bitmap(SampleEncoding::Binary)
1039 );
1040 let mut image = vec![0; decoder.total_bytes() as usize];
1041 decoder.read_image(&mut image).unwrap();
1042 assert_eq!(image, vec![255, 0, 0, 255, 0, 0, 0, 255, 0, 0, 255, 0]);
1043 match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() {
1044 (
1045 _,
1046 PNMHeader {
1047 decoded:
1048 HeaderRecord::Bitmap(BitmapHeader {
1049 encoding: SampleEncoding::Binary,
1050 width: 6,
1051 height: 2,
1052 }),
1053 encoded: _,
1054 },
1055 ) => (),
1056 _ => panic!("Decoded header is incorrect"),
1057 }
1058 }
1059
1060 /// A previous inifite loop.
1061 #[test]
pbm_binary_ascii_termination()1062 fn pbm_binary_ascii_termination() {
1063 use std::io::{Cursor, Error, ErrorKind, Read, Result};
1064 struct FailRead(Cursor<&'static [u8]>);
1065
1066 impl Read for FailRead {
1067 fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
1068 match self.0.read(buf) {
1069 Ok(n) if n > 0 => Ok(n),
1070 _ => Err(Error::new(
1071 ErrorKind::BrokenPipe,
1072 "Simulated broken pipe error"
1073 )),
1074 }
1075 }
1076 }
1077
1078 let pbmbinary = FailRead(Cursor::new(b"P1 1 1\n"));
1079
1080 let decoder = PnmDecoder::new(pbmbinary).unwrap();
1081 let mut image = vec![0; decoder.total_bytes() as usize];
1082 decoder.read_image(&mut image).expect_err("Image is malformed");
1083 }
1084
1085 #[test]
pbm_ascii()1086 fn pbm_ascii() {
1087 // The data contains two rows of the image (each line is padded to the full byte). For
1088 // comments on its format, see documentation of `impl SampleType for PbmBit`. Tests all
1089 // whitespace characters that should be allowed (the 6 characters according to POSIX).
1090 let pbmbinary = b"P1 6 2\n 0 1 1 0 1 1\n1 0 1 1 0\t\n\x0b\x0c\r1";
1091 let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap();
1092 assert_eq!(decoder.color_type(), ColorType::L8);
1093 assert_eq!(decoder.original_color_type(), ExtendedColorType::L1);
1094 assert_eq!(decoder.dimensions(), (6, 2));
1095 assert_eq!(decoder.subtype(), PNMSubtype::Bitmap(SampleEncoding::Ascii));
1096
1097 let mut image = vec![0; decoder.total_bytes() as usize];
1098 decoder.read_image(&mut image).unwrap();
1099 assert_eq!(image, vec![1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0]);
1100 match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() {
1101 (
1102 _,
1103 PNMHeader {
1104 decoded:
1105 HeaderRecord::Bitmap(BitmapHeader {
1106 encoding: SampleEncoding::Ascii,
1107 width: 6,
1108 height: 2,
1109 }),
1110 encoded: _,
1111 },
1112 ) => (),
1113 _ => panic!("Decoded header is incorrect"),
1114 }
1115 }
1116
1117 #[test]
pbm_ascii_nospace()1118 fn pbm_ascii_nospace() {
1119 // The data contains two rows of the image (each line is padded to the full byte). Notably,
1120 // it is completely within specification for the ascii data not to contain separating
1121 // whitespace for the pbm format or any mix.
1122 let pbmbinary = b"P1 6 2\n011011101101";
1123 let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap();
1124 assert_eq!(decoder.color_type(), ColorType::L8);
1125 assert_eq!(decoder.original_color_type(), ExtendedColorType::L1);
1126 assert_eq!(decoder.dimensions(), (6, 2));
1127 assert_eq!(decoder.subtype(), PNMSubtype::Bitmap(SampleEncoding::Ascii));
1128
1129 let mut image = vec![0; decoder.total_bytes() as usize];
1130 decoder.read_image(&mut image).unwrap();
1131 assert_eq!(image, vec![1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0]);
1132 match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() {
1133 (
1134 _,
1135 PNMHeader {
1136 decoded:
1137 HeaderRecord::Bitmap(BitmapHeader {
1138 encoding: SampleEncoding::Ascii,
1139 width: 6,
1140 height: 2,
1141 }),
1142 encoded: _,
1143 },
1144 ) => (),
1145 _ => panic!("Decoded header is incorrect"),
1146 }
1147 }
1148
1149 #[test]
pgm_binary()1150 fn pgm_binary() {
1151 // The data contains two rows of the image (each line is padded to the full byte). For
1152 // comments on its format, see documentation of `impl SampleType for PbmBit`.
1153 let elements = (0..16).collect::<Vec<_>>();
1154 let pbmbinary = [&b"P5 4 4 255\n"[..], &elements].concat();
1155 let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap();
1156 assert_eq!(decoder.color_type(), ColorType::L8);
1157 assert_eq!(decoder.dimensions(), (4, 4));
1158 assert_eq!(
1159 decoder.subtype(),
1160 PNMSubtype::Graymap(SampleEncoding::Binary)
1161 );
1162 let mut image = vec![0; decoder.total_bytes() as usize];
1163 decoder.read_image(&mut image).unwrap();
1164 assert_eq!(image, elements);
1165 match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() {
1166 (
1167 _,
1168 PNMHeader {
1169 decoded:
1170 HeaderRecord::Graymap(GraymapHeader {
1171 encoding: SampleEncoding::Binary,
1172 width: 4,
1173 height: 4,
1174 maxwhite: 255,
1175 }),
1176 encoded: _,
1177 },
1178 ) => (),
1179 _ => panic!("Decoded header is incorrect"),
1180 }
1181 }
1182
1183 #[test]
pgm_ascii()1184 fn pgm_ascii() {
1185 // The data contains two rows of the image (each line is padded to the full byte). For
1186 // comments on its format, see documentation of `impl SampleType for PbmBit`.
1187 let pbmbinary = b"P2 4 4 255\n 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15";
1188 let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap();
1189 assert_eq!(decoder.color_type(), ColorType::L8);
1190 assert_eq!(decoder.dimensions(), (4, 4));
1191 assert_eq!(
1192 decoder.subtype(),
1193 PNMSubtype::Graymap(SampleEncoding::Ascii)
1194 );
1195 let mut image = vec![0; decoder.total_bytes() as usize];
1196 decoder.read_image(&mut image).unwrap();
1197 assert_eq!(image, (0..16).collect::<Vec<_>>());
1198 match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() {
1199 (
1200 _,
1201 PNMHeader {
1202 decoded:
1203 HeaderRecord::Graymap(GraymapHeader {
1204 encoding: SampleEncoding::Ascii,
1205 width: 4,
1206 height: 4,
1207 maxwhite: 255,
1208 }),
1209 encoded: _,
1210 },
1211 ) => (),
1212 _ => panic!("Decoded header is incorrect"),
1213 }
1214 }
1215 }
1216