diff options
Diffstat (limited to 'vendor/image/src/codecs/pnm')
-rw-r--r-- | vendor/image/src/codecs/pnm/autobreak.rs | 124 | ||||
-rw-r--r-- | vendor/image/src/codecs/pnm/decoder.rs | 1272 | ||||
-rw-r--r-- | vendor/image/src/codecs/pnm/encoder.rs | 673 | ||||
-rw-r--r-- | vendor/image/src/codecs/pnm/header.rs | 354 | ||||
-rw-r--r-- | vendor/image/src/codecs/pnm/mod.rs | 184 |
5 files changed, 0 insertions, 2607 deletions
diff --git a/vendor/image/src/codecs/pnm/autobreak.rs b/vendor/image/src/codecs/pnm/autobreak.rs deleted file mode 100644 index cea2cd8..0000000 --- a/vendor/image/src/codecs/pnm/autobreak.rs +++ /dev/null @@ -1,124 +0,0 @@ -//! Insert line breaks between written buffers when they would overflow the line length. -use std::io; - -// The pnm standard says to insert line breaks after 70 characters. Assumes that no line breaks -// are actually written. We have to be careful to fully commit buffers or not commit them at all, -// otherwise we might insert a newline in the middle of a token. -pub(crate) struct AutoBreak<W: io::Write> { - wrapped: W, - line_capacity: usize, - line: Vec<u8>, - has_newline: bool, - panicked: bool, // see https://github.com/rust-lang/rust/issues/30888 -} - -impl<W: io::Write> AutoBreak<W> { - pub(crate) fn new(writer: W, line_capacity: usize) -> Self { - AutoBreak { - wrapped: writer, - line_capacity, - line: Vec::with_capacity(line_capacity + 1), - has_newline: false, - panicked: false, - } - } - - fn flush_buf(&mut self) -> io::Result<()> { - // from BufWriter - let mut written = 0; - let len = self.line.len(); - let mut ret = Ok(()); - while written < len { - self.panicked = true; - let r = self.wrapped.write(&self.line[written..]); - self.panicked = false; - match r { - Ok(0) => { - ret = Err(io::Error::new( - io::ErrorKind::WriteZero, - "failed to write the buffered data", - )); - break; - } - Ok(n) => written += n, - Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} - Err(e) => { - ret = Err(e); - break; - } - } - } - if written > 0 { - self.line.drain(..written); - } - ret - } -} - -impl<W: io::Write> io::Write for AutoBreak<W> { - fn write(&mut self, buffer: &[u8]) -> io::Result<usize> { - if self.has_newline { - self.flush()?; - self.has_newline = false; - } - - if !self.line.is_empty() && self.line.len() + buffer.len() > self.line_capacity { - self.line.push(b'\n'); - self.has_newline = true; - self.flush()?; - self.has_newline = false; - } - - self.line.extend_from_slice(buffer); - Ok(buffer.len()) - } - - fn flush(&mut self) -> io::Result<()> { - self.flush_buf()?; - self.wrapped.flush() - } -} - -impl<W: io::Write> Drop for AutoBreak<W> { - fn drop(&mut self) { - if !self.panicked { - let _r = self.flush_buf(); - // internal writer flushed automatically by Drop - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use std::io::Write; - - #[test] - fn test_aligned_writes() { - let mut output = Vec::new(); - - { - let mut writer = AutoBreak::new(&mut output, 10); - writer.write_all(b"0123456789").unwrap(); - writer.write_all(b"0123456789").unwrap(); - } - - assert_eq!(output.as_slice(), b"0123456789\n0123456789"); - } - - #[test] - fn test_greater_writes() { - let mut output = Vec::new(); - - { - let mut writer = AutoBreak::new(&mut output, 10); - writer.write_all(b"012").unwrap(); - writer.write_all(b"345").unwrap(); - writer.write_all(b"0123456789").unwrap(); - writer.write_all(b"012345678910").unwrap(); - writer.write_all(b"_").unwrap(); - } - - assert_eq!(output.as_slice(), b"012345\n0123456789\n012345678910\n_"); - } -} diff --git a/vendor/image/src/codecs/pnm/decoder.rs b/vendor/image/src/codecs/pnm/decoder.rs deleted file mode 100644 index a495871..0000000 --- a/vendor/image/src/codecs/pnm/decoder.rs +++ /dev/null @@ -1,1272 +0,0 @@ -use std::convert::TryFrom; -use std::convert::TryInto; -use std::error; -use std::fmt::{self, Display}; -use std::io::{self, BufRead, Cursor, Read}; -use std::marker::PhantomData; -use std::mem; -use std::num::ParseIntError; -use std::str::{self, FromStr}; - -use super::{ArbitraryHeader, ArbitraryTuplType, BitmapHeader, GraymapHeader, PixmapHeader}; -use super::{HeaderRecord, PnmHeader, PnmSubtype, SampleEncoding}; -use crate::color::{ColorType, ExtendedColorType}; -use crate::error::{ - DecodingError, ImageError, ImageResult, UnsupportedError, UnsupportedErrorKind, -}; -use crate::image::{self, ImageDecoder, ImageFormat}; -use crate::utils; - -use byteorder::{BigEndian, ByteOrder, NativeEndian}; - -/// All errors that can occur when attempting to parse a PNM -#[derive(Debug, Clone)] -enum DecoderError { - /// PNM's "P[123456]" signature wrong or missing - PnmMagicInvalid([u8; 2]), - /// Couldn't parse the specified string as an integer from the specified source - UnparsableValue(ErrorDataSource, String, ParseIntError), - - /// More than the exactly one allowed plane specified by the format - NonAsciiByteInHeader(u8), - /// The PAM header contained a non-ASCII byte - NonAsciiLineInPamHeader, - /// A sample string contained a non-ASCII byte - NonAsciiSample, - - /// The byte after the P7 magic was not 0x0A NEWLINE - NotNewlineAfterP7Magic(u8), - /// The PNM header had too few lines - UnexpectedPnmHeaderEnd, - - /// The specified line was specified twice - HeaderLineDuplicated(PnmHeaderLine), - /// The line with the specified ID was not understood - HeaderLineUnknown(String), - /// At least one of the required lines were missing from the header (are `None` here) - /// - /// Same names as [`PnmHeaderLine`](enum.PnmHeaderLine.html) - #[allow(missing_docs)] - HeaderLineMissing { - height: Option<u32>, - width: Option<u32>, - depth: Option<u32>, - maxval: Option<u32>, - }, - - /// Not enough data was provided to the Decoder to decode the image - InputTooShort, - /// Sample raster contained unexpected byte - UnexpectedByteInRaster(u8), - /// Specified sample was out of bounds (e.g. >1 in B&W) - SampleOutOfBounds(u8), - /// The image's maxval exceeds 0xFFFF - MaxvalTooBig(u32), - - /// The specified tuple type supports restricted depths and maxvals, those restrictions were not met - InvalidDepthOrMaxval { - tuple_type: ArbitraryTuplType, - depth: u32, - maxval: u32, - }, - /// The specified tuple type supports restricted depths, those restrictions were not met - InvalidDepth { - tuple_type: ArbitraryTuplType, - depth: u32, - }, - /// The tuple type was not recognised by the parser - TupleTypeUnrecognised, - - /// Overflowed the specified value when parsing - Overflow, -} - -impl Display for DecoderError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - DecoderError::PnmMagicInvalid(magic) => f.write_fmt(format_args!( - "Expected magic constant for PNM: P1..P7, got [{:#04X?}, {:#04X?}]", - magic[0], magic[1] - )), - DecoderError::UnparsableValue(src, data, err) => { - f.write_fmt(format_args!("Error parsing {:?} as {}: {}", data, src, err)) - } - - DecoderError::NonAsciiByteInHeader(c) => { - f.write_fmt(format_args!("Non-ASCII character {:#04X?} in header", c)) - } - DecoderError::NonAsciiLineInPamHeader => f.write_str("Non-ASCII line in PAM header"), - DecoderError::NonAsciiSample => { - f.write_str("Non-ASCII character where sample value was expected") - } - - DecoderError::NotNewlineAfterP7Magic(c) => f.write_fmt(format_args!( - "Expected newline after P7 magic, got {:#04X?}", - c - )), - DecoderError::UnexpectedPnmHeaderEnd => f.write_str("Unexpected end of PNM header"), - - DecoderError::HeaderLineDuplicated(line) => { - f.write_fmt(format_args!("Duplicate {} line", line)) - } - DecoderError::HeaderLineUnknown(identifier) => f.write_fmt(format_args!( - "Unknown header line with identifier {:?}", - identifier - )), - DecoderError::HeaderLineMissing { - height, - width, - depth, - maxval, - } => f.write_fmt(format_args!( - "Missing header line: have height={:?}, width={:?}, depth={:?}, maxval={:?}", - height, width, depth, maxval - )), - - DecoderError::InputTooShort => { - f.write_str("Not enough data was provided to the Decoder to decode the image") - } - DecoderError::UnexpectedByteInRaster(c) => f.write_fmt(format_args!( - "Unexpected character {:#04X?} within sample raster", - c - )), - DecoderError::SampleOutOfBounds(val) => { - f.write_fmt(format_args!("Sample value {} outside of bounds", val)) - } - DecoderError::MaxvalTooBig(maxval) => { - f.write_fmt(format_args!("Image MAXVAL exceeds {}: {}", 0xFFFF, maxval)) - } - - DecoderError::InvalidDepthOrMaxval { - tuple_type, - depth, - maxval, - } => f.write_fmt(format_args!( - "Invalid depth ({}) or maxval ({}) for tuple type {}", - depth, - maxval, - tuple_type.name() - )), - DecoderError::InvalidDepth { tuple_type, depth } => f.write_fmt(format_args!( - "Invalid depth ({}) for tuple type {}", - depth, - tuple_type.name() - )), - DecoderError::TupleTypeUnrecognised => f.write_str("Tuple type not recognized"), - DecoderError::Overflow => f.write_str("Overflow when parsing value"), - } - } -} - -/// Note: should `pnm` be extracted into a separate crate, -/// this will need to be hidden until that crate hits version `1.0`. -impl From<DecoderError> for ImageError { - fn from(e: DecoderError) -> ImageError { - ImageError::Decoding(DecodingError::new(ImageFormat::Pnm.into(), e)) - } -} - -impl error::Error for DecoderError { - fn source(&self) -> Option<&(dyn error::Error + 'static)> { - match self { - DecoderError::UnparsableValue(_, _, err) => Some(err), - _ => None, - } - } -} - -/// Single-value lines in a PNM header -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] -enum PnmHeaderLine { - /// "HEIGHT" - Height, - /// "WIDTH" - Width, - /// "DEPTH" - Depth, - /// "MAXVAL", a.k.a. `maxwhite` - Maxval, -} - -impl Display for PnmHeaderLine { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(match self { - PnmHeaderLine::Height => "HEIGHT", - PnmHeaderLine::Width => "WIDTH", - PnmHeaderLine::Depth => "DEPTH", - PnmHeaderLine::Maxval => "MAXVAL", - }) - } -} - -/// Single-value lines in a PNM header -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] -enum ErrorDataSource { - /// One of the header lines - Line(PnmHeaderLine), - /// Value in the preamble - Preamble, - /// Sample/pixel data - Sample, -} - -impl Display for ErrorDataSource { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - ErrorDataSource::Line(l) => l.fmt(f), - ErrorDataSource::Preamble => f.write_str("number in preamble"), - ErrorDataSource::Sample => f.write_str("sample"), - } - } -} - -/// Dynamic representation, represents all decodable (sample, depth) combinations. -#[derive(Clone, Copy)] -enum TupleType { - PbmBit, - BWBit, - GrayU8, - GrayU16, - RGBU8, - RGBU16, -} - -trait Sample { - fn bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize>; - fn from_bytes(bytes: &[u8], row_size: usize, output_buf: &mut [u8]) -> ImageResult<()>; - fn from_ascii(reader: &mut dyn Read, output_buf: &mut [u8]) -> ImageResult<()>; -} - -struct U8; -struct U16; -struct PbmBit; -struct BWBit; - -trait DecodableImageHeader { - fn tuple_type(&self) -> ImageResult<TupleType>; -} - -/// PNM decoder -pub struct PnmDecoder<R> { - reader: R, - header: PnmHeader, - tuple: TupleType, -} - -impl<R: BufRead> PnmDecoder<R> { - /// Create a new decoder that decodes from the stream ```read``` - pub fn new(mut buffered_read: R) -> ImageResult<PnmDecoder<R>> { - let magic = buffered_read.read_magic_constant()?; - - let subtype = match magic { - [b'P', b'1'] => PnmSubtype::Bitmap(SampleEncoding::Ascii), - [b'P', b'2'] => PnmSubtype::Graymap(SampleEncoding::Ascii), - [b'P', b'3'] => PnmSubtype::Pixmap(SampleEncoding::Ascii), - [b'P', b'4'] => PnmSubtype::Bitmap(SampleEncoding::Binary), - [b'P', b'5'] => PnmSubtype::Graymap(SampleEncoding::Binary), - [b'P', b'6'] => PnmSubtype::Pixmap(SampleEncoding::Binary), - [b'P', b'7'] => PnmSubtype::ArbitraryMap, - _ => return Err(DecoderError::PnmMagicInvalid(magic).into()), - }; - - let decoder = match subtype { - PnmSubtype::Bitmap(enc) => PnmDecoder::read_bitmap_header(buffered_read, enc), - PnmSubtype::Graymap(enc) => PnmDecoder::read_graymap_header(buffered_read, enc), - PnmSubtype::Pixmap(enc) => PnmDecoder::read_pixmap_header(buffered_read, enc), - PnmSubtype::ArbitraryMap => PnmDecoder::read_arbitrary_header(buffered_read), - }?; - - if utils::check_dimension_overflow( - decoder.dimensions().0, - decoder.dimensions().1, - decoder.color_type().bytes_per_pixel(), - ) { - return Err(ImageError::Unsupported( - UnsupportedError::from_format_and_kind( - ImageFormat::Pnm.into(), - UnsupportedErrorKind::GenericFeature(format!( - "Image dimensions ({}x{}) are too large", - decoder.dimensions().0, - decoder.dimensions().1 - )), - ), - )); - } - - Ok(decoder) - } - - /// Extract the reader and header after an image has been read. - pub fn into_inner(self) -> (R, PnmHeader) { - (self.reader, self.header) - } - - fn read_bitmap_header(mut reader: R, encoding: SampleEncoding) -> ImageResult<PnmDecoder<R>> { - let header = reader.read_bitmap_header(encoding)?; - Ok(PnmDecoder { - reader, - tuple: TupleType::PbmBit, - header: PnmHeader { - decoded: HeaderRecord::Bitmap(header), - encoded: None, - }, - }) - } - - fn read_graymap_header(mut reader: R, encoding: SampleEncoding) -> ImageResult<PnmDecoder<R>> { - let header = reader.read_graymap_header(encoding)?; - let tuple_type = header.tuple_type()?; - Ok(PnmDecoder { - reader, - tuple: tuple_type, - header: PnmHeader { - decoded: HeaderRecord::Graymap(header), - encoded: None, - }, - }) - } - - fn read_pixmap_header(mut reader: R, encoding: SampleEncoding) -> ImageResult<PnmDecoder<R>> { - let header = reader.read_pixmap_header(encoding)?; - let tuple_type = header.tuple_type()?; - Ok(PnmDecoder { - reader, - tuple: tuple_type, - header: PnmHeader { - decoded: HeaderRecord::Pixmap(header), - encoded: None, - }, - }) - } - - fn read_arbitrary_header(mut reader: R) -> ImageResult<PnmDecoder<R>> { - let header = reader.read_arbitrary_header()?; - let tuple_type = header.tuple_type()?; - Ok(PnmDecoder { - reader, - tuple: tuple_type, - header: PnmHeader { - decoded: HeaderRecord::Arbitrary(header), - encoded: None, - }, - }) - } -} - -trait HeaderReader: BufRead { - /// Reads the two magic constant bytes - fn read_magic_constant(&mut self) -> ImageResult<[u8; 2]> { - let mut magic: [u8; 2] = [0, 0]; - self.read_exact(&mut magic)?; - Ok(magic) - } - - /// Reads a string as well as a single whitespace after it, ignoring comments - fn read_next_string(&mut self) -> ImageResult<String> { - let mut bytes = Vec::new(); - - // pair input bytes with a bool mask to remove comments - let mark_comments = self.bytes().scan(true, |partof, read| { - let byte = match read { - Err(err) => return Some((*partof, Err(err))), - Ok(byte) => byte, - }; - let cur_enabled = *partof && byte != b'#'; - let next_enabled = cur_enabled || (byte == b'\r' || byte == b'\n'); - *partof = next_enabled; - Some((cur_enabled, Ok(byte))) - }); - - for (_, byte) in mark_comments.filter(|e| e.0) { - match byte { - Ok(b'\t') | Ok(b'\n') | Ok(b'\x0b') | Ok(b'\x0c') | Ok(b'\r') | Ok(b' ') => { - if !bytes.is_empty() { - break; // We're done as we already have some content - } - } - Ok(byte) if !byte.is_ascii() => { - return Err(DecoderError::NonAsciiByteInHeader(byte).into()) - } - Ok(byte) => { - bytes.push(byte); - } - Err(_) => break, - } - } - - if bytes.is_empty() { - return Err(ImageError::IoError(io::ErrorKind::UnexpectedEof.into())); - } - - if !bytes.as_slice().is_ascii() { - // We have only filled the buffer with characters for which `byte.is_ascii()` holds. - unreachable!("Non-ASCII character should have returned sooner") - } - - let string = String::from_utf8(bytes) - // We checked the precondition ourselves a few lines before, `bytes.as_slice().is_ascii()`. - .unwrap_or_else(|_| unreachable!("Only ASCII characters should be decoded")); - - Ok(string) - } - - /// Read the next line - fn read_next_line(&mut self) -> ImageResult<String> { - let mut buffer = String::new(); - self.read_line(&mut buffer)?; - Ok(buffer) - } - - fn read_next_u32(&mut self) -> ImageResult<u32> { - let s = self.read_next_string()?; - s.parse::<u32>() - .map_err(|err| DecoderError::UnparsableValue(ErrorDataSource::Preamble, s, err).into()) - } - - fn read_bitmap_header(&mut self, encoding: SampleEncoding) -> ImageResult<BitmapHeader> { - let width = self.read_next_u32()?; - let height = self.read_next_u32()?; - Ok(BitmapHeader { - encoding, - width, - height, - }) - } - - fn read_graymap_header(&mut self, encoding: SampleEncoding) -> ImageResult<GraymapHeader> { - self.read_pixmap_header(encoding).map( - |PixmapHeader { - encoding, - width, - height, - maxval, - }| GraymapHeader { - encoding, - width, - height, - maxwhite: maxval, - }, - ) - } - - fn read_pixmap_header(&mut self, encoding: SampleEncoding) -> ImageResult<PixmapHeader> { - let width = self.read_next_u32()?; - let height = self.read_next_u32()?; - let maxval = self.read_next_u32()?; - Ok(PixmapHeader { - encoding, - width, - height, - maxval, - }) - } - - fn read_arbitrary_header(&mut self) -> ImageResult<ArbitraryHeader> { - fn parse_single_value_line( - line_val: &mut Option<u32>, - rest: &str, - line: PnmHeaderLine, - ) -> ImageResult<()> { - if line_val.is_some() { - Err(DecoderError::HeaderLineDuplicated(line).into()) - } else { - let v = rest.trim().parse().map_err(|err| { - DecoderError::UnparsableValue(ErrorDataSource::Line(line), rest.to_owned(), err) - })?; - *line_val = Some(v); - Ok(()) - } - } - - match self.bytes().next() { - None => return Err(ImageError::IoError(io::ErrorKind::UnexpectedEof.into())), - Some(Err(io)) => return Err(ImageError::IoError(io)), - Some(Ok(b'\n')) => (), - Some(Ok(c)) => return Err(DecoderError::NotNewlineAfterP7Magic(c).into()), - } - - let mut line = String::new(); - let mut height: Option<u32> = None; - let mut width: Option<u32> = None; - let mut depth: Option<u32> = None; - let mut maxval: Option<u32> = None; - let mut tupltype: Option<String> = None; - loop { - line.truncate(0); - let len = self.read_line(&mut line)?; - if len == 0 { - return Err(DecoderError::UnexpectedPnmHeaderEnd.into()); - } - if line.as_bytes()[0] == b'#' { - continue; - } - if !line.is_ascii() { - return Err(DecoderError::NonAsciiLineInPamHeader.into()); - } - #[allow(deprecated)] - let (identifier, rest) = line - .trim_left() - .split_at(line.find(char::is_whitespace).unwrap_or(line.len())); - match identifier { - "ENDHDR" => break, - "HEIGHT" => parse_single_value_line(&mut height, rest, PnmHeaderLine::Height)?, - "WIDTH" => parse_single_value_line(&mut width, rest, PnmHeaderLine::Width)?, - "DEPTH" => parse_single_value_line(&mut depth, rest, PnmHeaderLine::Depth)?, - "MAXVAL" => parse_single_value_line(&mut maxval, rest, PnmHeaderLine::Maxval)?, - "TUPLTYPE" => { - let identifier = rest.trim(); - if tupltype.is_some() { - let appended = tupltype.take().map(|mut v| { - v.push(' '); - v.push_str(identifier); - v - }); - tupltype = appended; - } else { - tupltype = Some(identifier.to_string()); - } - } - _ => return Err(DecoderError::HeaderLineUnknown(identifier.to_string()).into()), - } - } - - let (h, w, d, m) = match (height, width, depth, maxval) { - (Some(h), Some(w), Some(d), Some(m)) => (h, w, d, m), - _ => { - return Err(DecoderError::HeaderLineMissing { - height, - width, - depth, - maxval, - } - .into()) - } - }; - - let tupltype = match tupltype { - None => None, - Some(ref t) if t == "BLACKANDWHITE" => Some(ArbitraryTuplType::BlackAndWhite), - Some(ref t) if t == "BLACKANDWHITE_ALPHA" => { - Some(ArbitraryTuplType::BlackAndWhiteAlpha) - } - Some(ref t) if t == "GRAYSCALE" => Some(ArbitraryTuplType::Grayscale), - Some(ref t) if t == "GRAYSCALE_ALPHA" => Some(ArbitraryTuplType::GrayscaleAlpha), - Some(ref t) if t == "RGB" => Some(ArbitraryTuplType::RGB), - Some(ref t) if t == "RGB_ALPHA" => Some(ArbitraryTuplType::RGBAlpha), - Some(other) => Some(ArbitraryTuplType::Custom(other)), - }; - - Ok(ArbitraryHeader { - height: h, - width: w, - depth: d, - maxval: m, - tupltype, - }) - } -} - -impl<R> HeaderReader for R where R: BufRead {} - -/// Wrapper struct around a `Cursor<Vec<u8>>` -pub struct PnmReader<R>(Cursor<Vec<u8>>, PhantomData<R>); -impl<R> Read for PnmReader<R> { - fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { - self.0.read(buf) - } - fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { - if self.0.position() == 0 && buf.is_empty() { - mem::swap(buf, self.0.get_mut()); - Ok(buf.len()) - } else { - self.0.read_to_end(buf) - } - } -} - -impl<'a, R: 'a + Read> ImageDecoder<'a> for PnmDecoder<R> { - type Reader = PnmReader<R>; - - fn dimensions(&self) -> (u32, u32) { - (self.header.width(), self.header.height()) - } - - fn color_type(&self) -> ColorType { - match self.tuple { - TupleType::PbmBit => ColorType::L8, - TupleType::BWBit => ColorType::L8, - TupleType::GrayU8 => ColorType::L8, - TupleType::GrayU16 => ColorType::L16, - TupleType::RGBU8 => ColorType::Rgb8, - TupleType::RGBU16 => ColorType::Rgb16, - } - } - - fn original_color_type(&self) -> ExtendedColorType { - match self.tuple { - TupleType::PbmBit => ExtendedColorType::L1, - TupleType::BWBit => ExtendedColorType::L1, - TupleType::GrayU8 => ExtendedColorType::L8, - TupleType::GrayU16 => ExtendedColorType::L16, - TupleType::RGBU8 => ExtendedColorType::Rgb8, - TupleType::RGBU16 => ExtendedColorType::Rgb16, - } - } - - fn into_reader(self) -> ImageResult<Self::Reader> { - Ok(PnmReader( - Cursor::new(image::decoder_to_vec(self)?), - PhantomData, - )) - } - - fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> { - assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes())); - match self.tuple { - TupleType::PbmBit => self.read_samples::<PbmBit>(1, buf), - TupleType::BWBit => self.read_samples::<BWBit>(1, buf), - TupleType::RGBU8 => self.read_samples::<U8>(3, buf), - TupleType::RGBU16 => self.read_samples::<U16>(3, buf), - TupleType::GrayU8 => self.read_samples::<U8>(1, buf), - TupleType::GrayU16 => self.read_samples::<U16>(1, buf), - } - } -} - -impl<R: Read> PnmDecoder<R> { - fn read_samples<S: Sample>(&mut self, components: u32, buf: &mut [u8]) -> ImageResult<()> { - match self.subtype().sample_encoding() { - SampleEncoding::Binary => { - let width = self.header.width(); - let height = self.header.height(); - let bytecount = S::bytelen(width, height, components)?; - - let mut bytes = vec![]; - self.reader - .by_ref() - // This conversion is potentially lossy but unlikely and in that case we error - // later anyways. - .take(bytecount as u64) - .read_to_end(&mut bytes)?; - if bytes.len() != bytecount { - return Err(DecoderError::InputTooShort.into()); - } - - let width: usize = width.try_into().map_err(|_| DecoderError::Overflow)?; - let components: usize = - components.try_into().map_err(|_| DecoderError::Overflow)?; - let row_size = width - .checked_mul(components) - .ok_or(DecoderError::Overflow)?; - - S::from_bytes(&bytes, row_size, buf) - } - SampleEncoding::Ascii => self.read_ascii::<S>(buf), - } - } - - fn read_ascii<Basic: Sample>(&mut self, output_buf: &mut [u8]) -> ImageResult<()> { - Basic::from_ascii(&mut self.reader, output_buf) - } - - /// Get the pnm subtype, depending on the magic constant contained in the header - pub fn subtype(&self) -> PnmSubtype { - self.header.subtype() - } -} - -fn read_separated_ascii<T: FromStr<Err = ParseIntError>>(reader: &mut dyn Read) -> ImageResult<T> -where - T::Err: Display, -{ - let is_separator = |v: &u8| matches! { *v, b'\t' | b'\n' | b'\x0b' | b'\x0c' | b'\r' | b' ' }; - - let token = reader - .bytes() - .skip_while(|v| v.as_ref().ok().map(is_separator).unwrap_or(false)) - .take_while(|v| v.as_ref().ok().map(|c| !is_separator(c)).unwrap_or(false)) - .collect::<Result<Vec<u8>, _>>()?; - - if !token.is_ascii() { - return Err(DecoderError::NonAsciiSample.into()); - } - - let string = str::from_utf8(&token) - // We checked the precondition ourselves a few lines before with `token.is_ascii()`. - .unwrap_or_else(|_| unreachable!("Only ASCII characters should be decoded")); - - string.parse().map_err(|err| { - DecoderError::UnparsableValue(ErrorDataSource::Sample, string.to_owned(), err).into() - }) -} - -impl Sample for U8 { - fn bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize> { - Ok((width * height * samples) as usize) - } - - fn from_bytes(bytes: &[u8], _row_size: usize, output_buf: &mut [u8]) -> ImageResult<()> { - output_buf.copy_from_slice(bytes); - Ok(()) - } - - fn from_ascii(reader: &mut dyn Read, output_buf: &mut [u8]) -> ImageResult<()> { - for b in output_buf { - *b = read_separated_ascii(reader)?; - } - Ok(()) - } -} - -impl Sample for U16 { - fn bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize> { - Ok((width * height * samples * 2) as usize) - } - - fn from_bytes(bytes: &[u8], _row_size: usize, output_buf: &mut [u8]) -> ImageResult<()> { - output_buf.copy_from_slice(bytes); - for chunk in output_buf.chunks_exact_mut(2) { - let v = BigEndian::read_u16(chunk); - NativeEndian::write_u16(chunk, v); - } - Ok(()) - } - - fn from_ascii(reader: &mut dyn Read, output_buf: &mut [u8]) -> ImageResult<()> { - for chunk in output_buf.chunks_exact_mut(2) { - let v = read_separated_ascii::<u16>(reader)?; - NativeEndian::write_u16(chunk, v); - } - Ok(()) - } -} - -// The image is encoded in rows of bits, high order bits first. Any bits beyond the row bits should -// be ignored. Also, contrary to rgb, black pixels are encoded as a 1 while white is 0. This will -// need to be reversed for the grayscale output. -impl Sample for PbmBit { - fn bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize> { - let count = width * samples; - let linelen = (count / 8) + ((count % 8) != 0) as u32; - Ok((linelen * height) as usize) - } - - fn from_bytes(bytes: &[u8], row_size: usize, output_buf: &mut [u8]) -> ImageResult<()> { - let mut expanded = utils::expand_bits(1, row_size.try_into().unwrap(), bytes); - for b in expanded.iter_mut() { - *b = !*b; - } - output_buf.copy_from_slice(&expanded); - Ok(()) - } - - fn from_ascii(reader: &mut dyn Read, output_buf: &mut [u8]) -> ImageResult<()> { - let mut bytes = reader.bytes(); - for b in output_buf { - loop { - let byte = bytes - .next() - .ok_or_else::<ImageError, _>(|| DecoderError::InputTooShort.into())??; - match byte { - b'\t' | b'\n' | b'\x0b' | b'\x0c' | b'\r' | b' ' => continue, - b'0' => *b = 255, - b'1' => *b = 0, - c => return Err(DecoderError::UnexpectedByteInRaster(c).into()), - } - break; - } - } - - Ok(()) - } -} - -// Encoded just like a normal U8 but we check the values. -impl Sample for BWBit { - fn bytelen(width: u32, height: u32, samples: u32) -> ImageResult<usize> { - U8::bytelen(width, height, samples) - } - - fn from_bytes(bytes: &[u8], row_size: usize, output_buf: &mut [u8]) -> ImageResult<()> { - U8::from_bytes(bytes, row_size, output_buf)?; - if let Some(val) = output_buf.iter().find(|&val| *val > 1) { - return Err(DecoderError::SampleOutOfBounds(*val).into()); - } - Ok(()) - } - - fn from_ascii(_reader: &mut dyn Read, _output_buf: &mut [u8]) -> ImageResult<()> { - unreachable!("BW bits from anymaps are never encoded as ASCII") - } -} - -impl DecodableImageHeader for BitmapHeader { - fn tuple_type(&self) -> ImageResult<TupleType> { - Ok(TupleType::PbmBit) - } -} - -impl DecodableImageHeader for GraymapHeader { - fn tuple_type(&self) -> ImageResult<TupleType> { - match self.maxwhite { - v if v <= 0xFF => Ok(TupleType::GrayU8), - v if v <= 0xFFFF => Ok(TupleType::GrayU16), - _ => Err(DecoderError::MaxvalTooBig(self.maxwhite).into()), - } - } -} - -impl DecodableImageHeader for PixmapHeader { - fn tuple_type(&self) -> ImageResult<TupleType> { - match self.maxval { - v if v <= 0xFF => Ok(TupleType::RGBU8), - v if v <= 0xFFFF => Ok(TupleType::RGBU16), - _ => Err(DecoderError::MaxvalTooBig(self.maxval).into()), - } - } -} - -impl DecodableImageHeader for ArbitraryHeader { - fn tuple_type(&self) -> ImageResult<TupleType> { - match self.tupltype { - None if self.depth == 1 => Ok(TupleType::GrayU8), - None if self.depth == 2 => Err(ImageError::Unsupported( - UnsupportedError::from_format_and_kind( - ImageFormat::Pnm.into(), - UnsupportedErrorKind::Color(ExtendedColorType::La8), - ), - )), - None if self.depth == 3 => Ok(TupleType::RGBU8), - None if self.depth == 4 => Err(ImageError::Unsupported( - UnsupportedError::from_format_and_kind( - ImageFormat::Pnm.into(), - UnsupportedErrorKind::Color(ExtendedColorType::Rgba8), - ), - )), - - Some(ArbitraryTuplType::BlackAndWhite) if self.maxval == 1 && self.depth == 1 => { - Ok(TupleType::BWBit) - } - Some(ArbitraryTuplType::BlackAndWhite) => Err(DecoderError::InvalidDepthOrMaxval { - tuple_type: ArbitraryTuplType::BlackAndWhite, - maxval: self.maxval, - depth: self.depth, - } - .into()), - - Some(ArbitraryTuplType::Grayscale) if self.depth == 1 && self.maxval <= 0xFF => { - Ok(TupleType::GrayU8) - } - Some(ArbitraryTuplType::Grayscale) if self.depth <= 1 && self.maxval <= 0xFFFF => { - Ok(TupleType::GrayU16) - } - Some(ArbitraryTuplType::Grayscale) => Err(DecoderError::InvalidDepthOrMaxval { - tuple_type: ArbitraryTuplType::Grayscale, - maxval: self.maxval, - depth: self.depth, - } - .into()), - - Some(ArbitraryTuplType::RGB) if self.depth == 3 && self.maxval <= 0xFF => { - Ok(TupleType::RGBU8) - } - Some(ArbitraryTuplType::RGB) if self.depth == 3 && self.maxval <= 0xFFFF => { - Ok(TupleType::RGBU16) - } - Some(ArbitraryTuplType::RGB) => Err(DecoderError::InvalidDepth { - tuple_type: ArbitraryTuplType::RGB, - depth: self.depth, - } - .into()), - - Some(ArbitraryTuplType::BlackAndWhiteAlpha) => Err(ImageError::Unsupported( - UnsupportedError::from_format_and_kind( - ImageFormat::Pnm.into(), - UnsupportedErrorKind::GenericFeature(format!( - "Color type {}", - ArbitraryTuplType::BlackAndWhiteAlpha.name() - )), - ), - )), - Some(ArbitraryTuplType::GrayscaleAlpha) => Err(ImageError::Unsupported( - UnsupportedError::from_format_and_kind( - ImageFormat::Pnm.into(), - UnsupportedErrorKind::Color(ExtendedColorType::La8), - ), - )), - Some(ArbitraryTuplType::RGBAlpha) => Err(ImageError::Unsupported( - UnsupportedError::from_format_and_kind( - ImageFormat::Pnm.into(), - UnsupportedErrorKind::Color(ExtendedColorType::Rgba8), - ), - )), - Some(ArbitraryTuplType::Custom(ref custom)) => Err(ImageError::Unsupported( - UnsupportedError::from_format_and_kind( - ImageFormat::Pnm.into(), - UnsupportedErrorKind::GenericFeature(format!("Tuple type {:?}", custom)), - ), - )), - None => Err(DecoderError::TupleTypeUnrecognised.into()), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - /// Tests reading of a valid blackandwhite pam - #[test] - fn pam_blackandwhite() { - let pamdata = b"P7 -WIDTH 4 -HEIGHT 4 -DEPTH 1 -MAXVAL 1 -TUPLTYPE BLACKANDWHITE -# Comment line -ENDHDR -\x01\x00\x00\x01\x01\x00\x00\x01\x01\x00\x00\x01\x01\x00\x00\x01"; - let decoder = PnmDecoder::new(&pamdata[..]).unwrap(); - assert_eq!(decoder.color_type(), ColorType::L8); - assert_eq!(decoder.original_color_type(), ExtendedColorType::L1); - assert_eq!(decoder.dimensions(), (4, 4)); - assert_eq!(decoder.subtype(), PnmSubtype::ArbitraryMap); - - let mut image = vec![0; decoder.total_bytes() as usize]; - decoder.read_image(&mut image).unwrap(); - assert_eq!( - image, - vec![ - 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, - 0x00, 0x01 - ] - ); - match PnmDecoder::new(&pamdata[..]).unwrap().into_inner() { - ( - _, - PnmHeader { - decoded: - HeaderRecord::Arbitrary(ArbitraryHeader { - width: 4, - height: 4, - maxval: 1, - depth: 1, - tupltype: Some(ArbitraryTuplType::BlackAndWhite), - }), - encoded: _, - }, - ) => (), - _ => panic!("Decoded header is incorrect"), - } - } - - /// Tests reading of a valid grayscale pam - #[test] - fn pam_grayscale() { - let pamdata = b"P7 -WIDTH 4 -HEIGHT 4 -DEPTH 1 -MAXVAL 255 -TUPLTYPE GRAYSCALE -# Comment line -ENDHDR -\xde\xad\xbe\xef\xde\xad\xbe\xef\xde\xad\xbe\xef\xde\xad\xbe\xef"; - let decoder = PnmDecoder::new(&pamdata[..]).unwrap(); - assert_eq!(decoder.color_type(), ColorType::L8); - assert_eq!(decoder.dimensions(), (4, 4)); - assert_eq!(decoder.subtype(), PnmSubtype::ArbitraryMap); - - let mut image = vec![0; decoder.total_bytes() as usize]; - decoder.read_image(&mut image).unwrap(); - assert_eq!( - image, - vec![ - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, - 0xbe, 0xef - ] - ); - match PnmDecoder::new(&pamdata[..]).unwrap().into_inner() { - ( - _, - PnmHeader { - decoded: - HeaderRecord::Arbitrary(ArbitraryHeader { - width: 4, - height: 4, - depth: 1, - maxval: 255, - tupltype: Some(ArbitraryTuplType::Grayscale), - }), - encoded: _, - }, - ) => (), - _ => panic!("Decoded header is incorrect"), - } - } - - /// Tests reading of a valid rgb pam - #[test] - fn pam_rgb() { - let pamdata = b"P7 -# Comment line -MAXVAL 255 -TUPLTYPE RGB -DEPTH 3 -WIDTH 2 -HEIGHT 2 -ENDHDR -\xde\xad\xbe\xef\xde\xad\xbe\xef\xde\xad\xbe\xef"; - let decoder = PnmDecoder::new(&pamdata[..]).unwrap(); - assert_eq!(decoder.color_type(), ColorType::Rgb8); - assert_eq!(decoder.dimensions(), (2, 2)); - assert_eq!(decoder.subtype(), PnmSubtype::ArbitraryMap); - - let mut image = vec![0; decoder.total_bytes() as usize]; - decoder.read_image(&mut image).unwrap(); - assert_eq!( - image, - vec![0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef] - ); - match PnmDecoder::new(&pamdata[..]).unwrap().into_inner() { - ( - _, - PnmHeader { - decoded: - HeaderRecord::Arbitrary(ArbitraryHeader { - maxval: 255, - tupltype: Some(ArbitraryTuplType::RGB), - depth: 3, - width: 2, - height: 2, - }), - encoded: _, - }, - ) => (), - _ => panic!("Decoded header is incorrect"), - } - } - - #[test] - fn pbm_binary() { - // The data contains two rows of the image (each line is padded to the full byte). For - // comments on its format, see documentation of `impl SampleType for PbmBit`. - let pbmbinary = [&b"P4 6 2\n"[..], &[0b01101100 as u8, 0b10110111]].concat(); - let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap(); - assert_eq!(decoder.color_type(), ColorType::L8); - assert_eq!(decoder.original_color_type(), ExtendedColorType::L1); - assert_eq!(decoder.dimensions(), (6, 2)); - assert_eq!( - decoder.subtype(), - PnmSubtype::Bitmap(SampleEncoding::Binary) - ); - let mut image = vec![0; decoder.total_bytes() as usize]; - decoder.read_image(&mut image).unwrap(); - assert_eq!(image, vec![255, 0, 0, 255, 0, 0, 0, 255, 0, 0, 255, 0]); - match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() { - ( - _, - PnmHeader { - decoded: - HeaderRecord::Bitmap(BitmapHeader { - encoding: SampleEncoding::Binary, - width: 6, - height: 2, - }), - encoded: _, - }, - ) => (), - _ => panic!("Decoded header is incorrect"), - } - } - - /// A previous infinite loop. - #[test] - fn pbm_binary_ascii_termination() { - use std::io::{BufReader, Cursor, Error, ErrorKind, Read, Result}; - struct FailRead(Cursor<&'static [u8]>); - - impl Read for FailRead { - fn read(&mut self, buf: &mut [u8]) -> Result<usize> { - match self.0.read(buf) { - Ok(n) if n > 0 => Ok(n), - _ => Err(Error::new( - ErrorKind::BrokenPipe, - "Simulated broken pipe error", - )), - } - } - } - - let pbmbinary = BufReader::new(FailRead(Cursor::new(b"P1 1 1\n"))); - - let decoder = PnmDecoder::new(pbmbinary).unwrap(); - let mut image = vec![0; decoder.total_bytes() as usize]; - decoder - .read_image(&mut image) - .expect_err("Image is malformed"); - } - - #[test] - fn pbm_ascii() { - // The data contains two rows of the image (each line is padded to the full byte). For - // comments on its format, see documentation of `impl SampleType for PbmBit`. Tests all - // whitespace characters that should be allowed (the 6 characters according to POSIX). - let pbmbinary = b"P1 6 2\n 0 1 1 0 1 1\n1 0 1 1 0\t\n\x0b\x0c\r1"; - let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap(); - assert_eq!(decoder.color_type(), ColorType::L8); - assert_eq!(decoder.original_color_type(), ExtendedColorType::L1); - assert_eq!(decoder.dimensions(), (6, 2)); - assert_eq!(decoder.subtype(), PnmSubtype::Bitmap(SampleEncoding::Ascii)); - - let mut image = vec![0; decoder.total_bytes() as usize]; - decoder.read_image(&mut image).unwrap(); - assert_eq!(image, vec![255, 0, 0, 255, 0, 0, 0, 255, 0, 0, 255, 0]); - match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() { - ( - _, - PnmHeader { - decoded: - HeaderRecord::Bitmap(BitmapHeader { - encoding: SampleEncoding::Ascii, - width: 6, - height: 2, - }), - encoded: _, - }, - ) => (), - _ => panic!("Decoded header is incorrect"), - } - } - - #[test] - fn pbm_ascii_nospace() { - // The data contains two rows of the image (each line is padded to the full byte). Notably, - // it is completely within specification for the ascii data not to contain separating - // whitespace for the pbm format or any mix. - let pbmbinary = b"P1 6 2\n011011101101"; - let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap(); - assert_eq!(decoder.color_type(), ColorType::L8); - assert_eq!(decoder.original_color_type(), ExtendedColorType::L1); - assert_eq!(decoder.dimensions(), (6, 2)); - assert_eq!(decoder.subtype(), PnmSubtype::Bitmap(SampleEncoding::Ascii)); - - let mut image = vec![0; decoder.total_bytes() as usize]; - decoder.read_image(&mut image).unwrap(); - assert_eq!(image, vec![255, 0, 0, 255, 0, 0, 0, 255, 0, 0, 255, 0]); - match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() { - ( - _, - PnmHeader { - decoded: - HeaderRecord::Bitmap(BitmapHeader { - encoding: SampleEncoding::Ascii, - width: 6, - height: 2, - }), - encoded: _, - }, - ) => (), - _ => panic!("Decoded header is incorrect"), - } - } - - #[test] - fn pgm_binary() { - // The data contains two rows of the image (each line is padded to the full byte). For - // comments on its format, see documentation of `impl SampleType for PbmBit`. - let elements = (0..16).collect::<Vec<_>>(); - let pbmbinary = [&b"P5 4 4 255\n"[..], &elements].concat(); - let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap(); - assert_eq!(decoder.color_type(), ColorType::L8); - assert_eq!(decoder.dimensions(), (4, 4)); - assert_eq!( - decoder.subtype(), - PnmSubtype::Graymap(SampleEncoding::Binary) - ); - let mut image = vec![0; decoder.total_bytes() as usize]; - decoder.read_image(&mut image).unwrap(); - assert_eq!(image, elements); - match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() { - ( - _, - PnmHeader { - decoded: - HeaderRecord::Graymap(GraymapHeader { - encoding: SampleEncoding::Binary, - width: 4, - height: 4, - maxwhite: 255, - }), - encoded: _, - }, - ) => (), - _ => panic!("Decoded header is incorrect"), - } - } - - #[test] - fn pgm_ascii() { - // The data contains two rows of the image (each line is padded to the full byte). For - // comments on its format, see documentation of `impl SampleType for PbmBit`. - let pbmbinary = b"P2 4 4 255\n 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15"; - let decoder = PnmDecoder::new(&pbmbinary[..]).unwrap(); - assert_eq!(decoder.color_type(), ColorType::L8); - assert_eq!(decoder.dimensions(), (4, 4)); - assert_eq!( - decoder.subtype(), - PnmSubtype::Graymap(SampleEncoding::Ascii) - ); - let mut image = vec![0; decoder.total_bytes() as usize]; - decoder.read_image(&mut image).unwrap(); - assert_eq!(image, (0..16).collect::<Vec<_>>()); - match PnmDecoder::new(&pbmbinary[..]).unwrap().into_inner() { - ( - _, - PnmHeader { - decoded: - HeaderRecord::Graymap(GraymapHeader { - encoding: SampleEncoding::Ascii, - width: 4, - height: 4, - maxwhite: 255, - }), - encoded: _, - }, - ) => (), - _ => panic!("Decoded header is incorrect"), - } - } - - #[test] - fn dimension_overflow() { - let pamdata = b"P7 -# Comment line -MAXVAL 255 -TUPLTYPE RGB -DEPTH 3 -WIDTH 4294967295 -HEIGHT 4294967295 -ENDHDR -\xde\xad\xbe\xef\xde\xad\xbe\xef\xde\xad\xbe\xef"; - - assert!(PnmDecoder::new(&pamdata[..]).is_err()); - } - - #[test] - fn issue_1508() { - let _ = crate::load_from_memory(b"P391919 16999 1 1 9 919 16999 1 9999 999* 99999 N"); - } - - #[test] - fn issue_1616_overflow() { - let data = vec![ - 80, 54, 10, 52, 50, 57, 52, 56, 50, 57, 52, 56, 35, 56, 10, 52, 10, 48, 10, 12, 12, 56, - ]; - // Validate: we have a header. Note: we might already calculate that this will fail but - // then we could not return information about the header to the caller. - let decoder = PnmDecoder::new(&data[..]).unwrap(); - let mut image = vec![0; decoder.total_bytes() as usize]; - let _ = decoder.read_image(&mut image); - } -} diff --git a/vendor/image/src/codecs/pnm/encoder.rs b/vendor/image/src/codecs/pnm/encoder.rs deleted file mode 100644 index 9f823d0..0000000 --- a/vendor/image/src/codecs/pnm/encoder.rs +++ /dev/null @@ -1,673 +0,0 @@ -//! Encoding of PNM Images -use std::fmt; -use std::io; - -use std::io::Write; - -use super::AutoBreak; -use super::{ArbitraryHeader, ArbitraryTuplType, BitmapHeader, GraymapHeader, PixmapHeader}; -use super::{HeaderRecord, PnmHeader, PnmSubtype, SampleEncoding}; -use crate::color::{ColorType, ExtendedColorType}; -use crate::error::{ - ImageError, ImageResult, ParameterError, ParameterErrorKind, UnsupportedError, - UnsupportedErrorKind, -}; -use crate::image::{ImageEncoder, ImageFormat}; - -use byteorder::{BigEndian, WriteBytesExt}; - -enum HeaderStrategy { - Dynamic, - Subtype(PnmSubtype), - Chosen(PnmHeader), -} - -#[derive(Clone, Copy)] -pub enum FlatSamples<'a> { - U8(&'a [u8]), - U16(&'a [u16]), -} - -/// Encodes images to any of the `pnm` image formats. -pub struct PnmEncoder<W: Write> { - writer: W, - header: HeaderStrategy, -} - -/// Encapsulate the checking system in the type system. Non of the fields are actually accessed -/// but requiring them forces us to validly construct the struct anyways. -struct CheckedImageBuffer<'a> { - _image: FlatSamples<'a>, - _width: u32, - _height: u32, - _color: ExtendedColorType, -} - -// Check the header against the buffer. Each struct produces the next after a check. -struct UncheckedHeader<'a> { - header: &'a PnmHeader, -} - -struct CheckedDimensions<'a> { - unchecked: UncheckedHeader<'a>, - width: u32, - height: u32, -} - -struct CheckedHeaderColor<'a> { - dimensions: CheckedDimensions<'a>, - color: ExtendedColorType, -} - -struct CheckedHeader<'a> { - color: CheckedHeaderColor<'a>, - encoding: TupleEncoding<'a>, - _image: CheckedImageBuffer<'a>, -} - -enum TupleEncoding<'a> { - PbmBits { - samples: FlatSamples<'a>, - width: u32, - }, - Ascii { - samples: FlatSamples<'a>, - }, - Bytes { - samples: FlatSamples<'a>, - }, -} - -impl<W: Write> PnmEncoder<W> { - /// Create new PnmEncoder from the `writer`. - /// - /// The encoded images will have some `pnm` format. If more control over the image type is - /// required, use either one of `with_subtype` or `with_header`. For more information on the - /// behaviour, see `with_dynamic_header`. - pub fn new(writer: W) -> Self { - PnmEncoder { - writer, - header: HeaderStrategy::Dynamic, - } - } - - /// Encode a specific pnm subtype image. - /// - /// The magic number and encoding type will be chosen as provided while the rest of the header - /// data will be generated dynamically. Trying to encode incompatible images (e.g. encoding an - /// RGB image as Graymap) will result in an error. - /// - /// This will overwrite the effect of earlier calls to `with_header` and `with_dynamic_header`. - pub fn with_subtype(self, subtype: PnmSubtype) -> Self { - PnmEncoder { - writer: self.writer, - header: HeaderStrategy::Subtype(subtype), - } - } - - /// Enforce the use of a chosen header. - /// - /// While this option gives the most control over the actual written data, the encoding process - /// will error in case the header data and image parameters do not agree. It is the users - /// obligation to ensure that the width and height are set accordingly, for example. - /// - /// Choose this option if you want a lossless decoding/encoding round trip. - /// - /// This will overwrite the effect of earlier calls to `with_subtype` and `with_dynamic_header`. - pub fn with_header(self, header: PnmHeader) -> Self { - PnmEncoder { - writer: self.writer, - header: HeaderStrategy::Chosen(header), - } - } - - /// Create the header dynamically for each image. - /// - /// This is the default option upon creation of the encoder. With this, most images should be - /// encodable but the specific format chosen is out of the users control. The pnm subtype is - /// chosen arbitrarily by the library. - /// - /// This will overwrite the effect of earlier calls to `with_subtype` and `with_header`. - pub fn with_dynamic_header(self) -> Self { - PnmEncoder { - writer: self.writer, - header: HeaderStrategy::Dynamic, - } - } - - /// Encode an image whose samples are represented as `u8`. - /// - /// Some `pnm` subtypes are incompatible with some color options, a chosen header most - /// certainly with any deviation from the original decoded image. - pub fn encode<'s, S>( - &mut self, - image: S, - width: u32, - height: u32, - color: ColorType, - ) -> ImageResult<()> - where - S: Into<FlatSamples<'s>>, - { - let image = image.into(); - match self.header { - HeaderStrategy::Dynamic => { - self.write_dynamic_header(image, width, height, color.into()) - } - HeaderStrategy::Subtype(subtype) => { - self.write_subtyped_header(subtype, image, width, height, color.into()) - } - HeaderStrategy::Chosen(ref header) => Self::write_with_header( - &mut self.writer, - header, - image, - width, - height, - color.into(), - ), - } - } - - /// Choose any valid pnm format that the image can be expressed in and write its header. - /// - /// Returns how the body should be written if successful. - fn write_dynamic_header( - &mut self, - image: FlatSamples, - width: u32, - height: u32, - color: ExtendedColorType, - ) -> ImageResult<()> { - let depth = u32::from(color.channel_count()); - let (maxval, tupltype) = match color { - ExtendedColorType::L1 => (1, ArbitraryTuplType::BlackAndWhite), - ExtendedColorType::L8 => (0xff, ArbitraryTuplType::Grayscale), - ExtendedColorType::L16 => (0xffff, ArbitraryTuplType::Grayscale), - ExtendedColorType::La1 => (1, ArbitraryTuplType::BlackAndWhiteAlpha), - ExtendedColorType::La8 => (0xff, ArbitraryTuplType::GrayscaleAlpha), - ExtendedColorType::La16 => (0xffff, ArbitraryTuplType::GrayscaleAlpha), - ExtendedColorType::Rgb8 => (0xff, ArbitraryTuplType::RGB), - ExtendedColorType::Rgb16 => (0xffff, ArbitraryTuplType::RGB), - ExtendedColorType::Rgba8 => (0xff, ArbitraryTuplType::RGBAlpha), - ExtendedColorType::Rgba16 => (0xffff, ArbitraryTuplType::RGBAlpha), - _ => { - return Err(ImageError::Unsupported( - UnsupportedError::from_format_and_kind( - ImageFormat::Pnm.into(), - UnsupportedErrorKind::Color(color), - ), - )) - } - }; - - let header = PnmHeader { - decoded: HeaderRecord::Arbitrary(ArbitraryHeader { - width, - height, - depth, - maxval, - tupltype: Some(tupltype), - }), - encoded: None, - }; - - Self::write_with_header(&mut self.writer, &header, image, width, height, color) - } - - /// Try to encode the image with the chosen format, give its corresponding pixel encoding type. - fn write_subtyped_header( - &mut self, - subtype: PnmSubtype, - image: FlatSamples, - width: u32, - height: u32, - color: ExtendedColorType, - ) -> ImageResult<()> { - let header = match (subtype, color) { - (PnmSubtype::ArbitraryMap, color) => { - return self.write_dynamic_header(image, width, height, color) - } - (PnmSubtype::Pixmap(encoding), ExtendedColorType::Rgb8) => PnmHeader { - decoded: HeaderRecord::Pixmap(PixmapHeader { - encoding, - width, - height, - maxval: 255, - }), - encoded: None, - }, - (PnmSubtype::Graymap(encoding), ExtendedColorType::L8) => PnmHeader { - decoded: HeaderRecord::Graymap(GraymapHeader { - encoding, - width, - height, - maxwhite: 255, - }), - encoded: None, - }, - (PnmSubtype::Bitmap(encoding), ExtendedColorType::L8) - | (PnmSubtype::Bitmap(encoding), ExtendedColorType::L1) => PnmHeader { - decoded: HeaderRecord::Bitmap(BitmapHeader { - encoding, - width, - height, - }), - encoded: None, - }, - (_, _) => { - return Err(ImageError::Parameter(ParameterError::from_kind( - ParameterErrorKind::Generic( - "Color type can not be represented in the chosen format".to_owned(), - ), - ))); - } - }; - - Self::write_with_header(&mut self.writer, &header, image, width, height, color) - } - - /// Try to encode the image with the chosen header, checking if values are correct. - /// - /// Returns how the body should be written if successful. - fn write_with_header( - writer: &mut dyn Write, - header: &PnmHeader, - image: FlatSamples, - width: u32, - height: u32, - color: ExtendedColorType, - ) -> ImageResult<()> { - let unchecked = UncheckedHeader { header }; - - unchecked - .check_header_dimensions(width, height)? - .check_header_color(color)? - .check_sample_values(image)? - .write_header(writer)? - .write_image(writer) - } -} - -impl<W: Write> ImageEncoder for PnmEncoder<W> { - fn write_image( - mut self, - buf: &[u8], - width: u32, - height: u32, - color_type: ColorType, - ) -> ImageResult<()> { - self.encode(buf, width, height, color_type) - } -} - -impl<'a> CheckedImageBuffer<'a> { - fn check( - image: FlatSamples<'a>, - width: u32, - height: u32, - color: ExtendedColorType, - ) -> ImageResult<CheckedImageBuffer<'a>> { - let components = color.channel_count() as usize; - let uwidth = width as usize; - let uheight = height as usize; - let expected_len = components - .checked_mul(uwidth) - .and_then(|v| v.checked_mul(uheight)); - if Some(image.len()) != expected_len { - // Image buffer does not correspond to size and colour. - return Err(ImageError::Parameter(ParameterError::from_kind( - ParameterErrorKind::DimensionMismatch, - ))); - } - Ok(CheckedImageBuffer { - _image: image, - _width: width, - _height: height, - _color: color, - }) - } -} - -impl<'a> UncheckedHeader<'a> { - fn check_header_dimensions( - self, - width: u32, - height: u32, - ) -> ImageResult<CheckedDimensions<'a>> { - if self.header.width() != width || self.header.height() != height { - // Chosen header does not match Image dimensions. - return Err(ImageError::Parameter(ParameterError::from_kind( - ParameterErrorKind::DimensionMismatch, - ))); - } - - Ok(CheckedDimensions { - unchecked: self, - width, - height, - }) - } -} - -impl<'a> CheckedDimensions<'a> { - // Check color compatibility with the header. This will only error when we are certain that - // the combination is bogus (e.g. combining Pixmap and Palette) but allows uncertain - // combinations (basically a ArbitraryTuplType::Custom with any color of fitting depth). - fn check_header_color(self, color: ExtendedColorType) -> ImageResult<CheckedHeaderColor<'a>> { - let components = u32::from(color.channel_count()); - - match *self.unchecked.header { - PnmHeader { - decoded: HeaderRecord::Bitmap(_), - .. - } => match color { - ExtendedColorType::L1 | ExtendedColorType::L8 | ExtendedColorType::L16 => (), - _ => { - return Err(ImageError::Parameter(ParameterError::from_kind( - ParameterErrorKind::Generic( - "PBM format only support luma color types".to_owned(), - ), - ))) - } - }, - PnmHeader { - decoded: HeaderRecord::Graymap(_), - .. - } => match color { - ExtendedColorType::L1 | ExtendedColorType::L8 | ExtendedColorType::L16 => (), - _ => { - return Err(ImageError::Parameter(ParameterError::from_kind( - ParameterErrorKind::Generic( - "PGM format only support luma color types".to_owned(), - ), - ))) - } - }, - PnmHeader { - decoded: HeaderRecord::Pixmap(_), - .. - } => match color { - ExtendedColorType::Rgb8 => (), - _ => { - return Err(ImageError::Parameter(ParameterError::from_kind( - ParameterErrorKind::Generic( - "PPM format only support ExtendedColorType::Rgb8".to_owned(), - ), - ))) - } - }, - PnmHeader { - decoded: - HeaderRecord::Arbitrary(ArbitraryHeader { - depth, - ref tupltype, - .. - }), - .. - } => match (tupltype, color) { - (&Some(ArbitraryTuplType::BlackAndWhite), ExtendedColorType::L1) => (), - (&Some(ArbitraryTuplType::BlackAndWhiteAlpha), ExtendedColorType::La8) => (), - - (&Some(ArbitraryTuplType::Grayscale), ExtendedColorType::L1) => (), - (&Some(ArbitraryTuplType::Grayscale), ExtendedColorType::L8) => (), - (&Some(ArbitraryTuplType::Grayscale), ExtendedColorType::L16) => (), - (&Some(ArbitraryTuplType::GrayscaleAlpha), ExtendedColorType::La8) => (), - - (&Some(ArbitraryTuplType::RGB), ExtendedColorType::Rgb8) => (), - (&Some(ArbitraryTuplType::RGBAlpha), ExtendedColorType::Rgba8) => (), - - (&None, _) if depth == components => (), - (&Some(ArbitraryTuplType::Custom(_)), _) if depth == components => (), - _ if depth != components => { - return Err(ImageError::Parameter(ParameterError::from_kind( - ParameterErrorKind::Generic(format!( - "Depth mismatch: header {} vs. color {}", - depth, components - )), - ))) - } - _ => { - return Err(ImageError::Parameter(ParameterError::from_kind( - ParameterErrorKind::Generic( - "Invalid color type for selected PAM color type".to_owned(), - ), - ))) - } - }, - } - - Ok(CheckedHeaderColor { - dimensions: self, - color, - }) - } -} - -impl<'a> CheckedHeaderColor<'a> { - fn check_sample_values(self, image: FlatSamples<'a>) -> ImageResult<CheckedHeader<'a>> { - let header_maxval = match self.dimensions.unchecked.header.decoded { - HeaderRecord::Bitmap(_) => 1, - HeaderRecord::Graymap(GraymapHeader { maxwhite, .. }) => maxwhite, - HeaderRecord::Pixmap(PixmapHeader { maxval, .. }) => maxval, - HeaderRecord::Arbitrary(ArbitraryHeader { maxval, .. }) => maxval, - }; - - // We trust the image color bit count to be correct at least. - let max_sample = match self.color { - ExtendedColorType::Unknown(n) if n <= 16 => (1 << n) - 1, - ExtendedColorType::L1 => 1, - ExtendedColorType::L8 - | ExtendedColorType::La8 - | ExtendedColorType::Rgb8 - | ExtendedColorType::Rgba8 - | ExtendedColorType::Bgr8 - | ExtendedColorType::Bgra8 => 0xff, - ExtendedColorType::L16 - | ExtendedColorType::La16 - | ExtendedColorType::Rgb16 - | ExtendedColorType::Rgba16 => 0xffff, - _ => { - // Unsupported target color type. - return Err(ImageError::Unsupported( - UnsupportedError::from_format_and_kind( - ImageFormat::Pnm.into(), - UnsupportedErrorKind::Color(self.color), - ), - )); - } - }; - - // Avoid the performance heavy check if possible, e.g. if the header has been chosen by us. - if header_maxval < max_sample && !image.all_smaller(header_maxval) { - // Sample value greater than allowed for chosen header. - return Err(ImageError::Unsupported( - UnsupportedError::from_format_and_kind( - ImageFormat::Pnm.into(), - UnsupportedErrorKind::GenericFeature( - "Sample value greater than allowed for chosen header".to_owned(), - ), - ), - )); - } - - let encoding = image.encoding_for(&self.dimensions.unchecked.header.decoded); - - let image = CheckedImageBuffer::check( - image, - self.dimensions.width, - self.dimensions.height, - self.color, - )?; - - Ok(CheckedHeader { - color: self, - encoding, - _image: image, - }) - } -} - -impl<'a> CheckedHeader<'a> { - fn write_header(self, writer: &mut dyn Write) -> ImageResult<TupleEncoding<'a>> { - self.header().write(writer)?; - Ok(self.encoding) - } - - fn header(&self) -> &PnmHeader { - self.color.dimensions.unchecked.header - } -} - -struct SampleWriter<'a>(&'a mut dyn Write); - -impl<'a> SampleWriter<'a> { - fn write_samples_ascii<V>(self, samples: V) -> io::Result<()> - where - V: Iterator, - V::Item: fmt::Display, - { - let mut auto_break_writer = AutoBreak::new(self.0, 70); - for value in samples { - write!(auto_break_writer, "{} ", value)?; - } - auto_break_writer.flush() - } - - fn write_pbm_bits<V>(self, samples: &[V], width: u32) -> io::Result<()> - /* Default gives 0 for all primitives. TODO: replace this with `Zeroable` once it hits stable */ - where - V: Default + Eq + Copy, - { - // The length of an encoded scanline - let line_width = (width - 1) / 8 + 1; - - // We'll be writing single bytes, so buffer - let mut line_buffer = Vec::with_capacity(line_width as usize); - - for line in samples.chunks(width as usize) { - for byte_bits in line.chunks(8) { - let mut byte = 0u8; - for i in 0..8 { - // Black pixels are encoded as 1s - if let Some(&v) = byte_bits.get(i) { - if v == V::default() { - byte |= 1u8 << (7 - i) - } - } - } - line_buffer.push(byte) - } - self.0.write_all(line_buffer.as_slice())?; - line_buffer.clear(); - } - - self.0.flush() - } -} - -impl<'a> FlatSamples<'a> { - fn len(&self) -> usize { - match *self { - FlatSamples::U8(arr) => arr.len(), - FlatSamples::U16(arr) => arr.len(), - } - } - - fn all_smaller(&self, max_val: u32) -> bool { - match *self { - FlatSamples::U8(arr) => arr.iter().any(|&val| u32::from(val) > max_val), - FlatSamples::U16(arr) => arr.iter().any(|&val| u32::from(val) > max_val), - } - } - - fn encoding_for(&self, header: &HeaderRecord) -> TupleEncoding<'a> { - match *header { - HeaderRecord::Bitmap(BitmapHeader { - encoding: SampleEncoding::Binary, - width, - .. - }) => TupleEncoding::PbmBits { - samples: *self, - width, - }, - - HeaderRecord::Bitmap(BitmapHeader { - encoding: SampleEncoding::Ascii, - .. - }) => TupleEncoding::Ascii { samples: *self }, - - HeaderRecord::Arbitrary(_) => TupleEncoding::Bytes { samples: *self }, - - HeaderRecord::Graymap(GraymapHeader { - encoding: SampleEncoding::Ascii, - .. - }) - | HeaderRecord::Pixmap(PixmapHeader { - encoding: SampleEncoding::Ascii, - .. - }) => TupleEncoding::Ascii { samples: *self }, - - HeaderRecord::Graymap(GraymapHeader { - encoding: SampleEncoding::Binary, - .. - }) - | HeaderRecord::Pixmap(PixmapHeader { - encoding: SampleEncoding::Binary, - .. - }) => TupleEncoding::Bytes { samples: *self }, - } - } -} - -impl<'a> From<&'a [u8]> for FlatSamples<'a> { - fn from(samples: &'a [u8]) -> Self { - FlatSamples::U8(samples) - } -} - -impl<'a> From<&'a [u16]> for FlatSamples<'a> { - fn from(samples: &'a [u16]) -> Self { - FlatSamples::U16(samples) - } -} - -impl<'a> TupleEncoding<'a> { - fn write_image(&self, writer: &mut dyn Write) -> ImageResult<()> { - match *self { - TupleEncoding::PbmBits { - samples: FlatSamples::U8(samples), - width, - } => SampleWriter(writer) - .write_pbm_bits(samples, width) - .map_err(ImageError::IoError), - TupleEncoding::PbmBits { - samples: FlatSamples::U16(samples), - width, - } => SampleWriter(writer) - .write_pbm_bits(samples, width) - .map_err(ImageError::IoError), - - TupleEncoding::Bytes { - samples: FlatSamples::U8(samples), - } => writer.write_all(samples).map_err(ImageError::IoError), - TupleEncoding::Bytes { - samples: FlatSamples::U16(samples), - } => samples.iter().try_for_each(|&sample| { - writer - .write_u16::<BigEndian>(sample) - .map_err(ImageError::IoError) - }), - - TupleEncoding::Ascii { - samples: FlatSamples::U8(samples), - } => SampleWriter(writer) - .write_samples_ascii(samples.iter()) - .map_err(ImageError::IoError), - TupleEncoding::Ascii { - samples: FlatSamples::U16(samples), - } => SampleWriter(writer) - .write_samples_ascii(samples.iter()) - .map_err(ImageError::IoError), - } - } -} diff --git a/vendor/image/src/codecs/pnm/header.rs b/vendor/image/src/codecs/pnm/header.rs deleted file mode 100644 index 443a701..0000000 --- a/vendor/image/src/codecs/pnm/header.rs +++ /dev/null @@ -1,354 +0,0 @@ -use std::{fmt, io}; - -/// The kind of encoding used to store sample values -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub enum SampleEncoding { - /// Samples are unsigned binary integers in big endian - Binary, - - /// Samples are encoded as decimal ascii strings separated by whitespace - Ascii, -} - -/// Denotes the category of the magic number -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub enum PnmSubtype { - /// Magic numbers P1 and P4 - Bitmap(SampleEncoding), - - /// Magic numbers P2 and P5 - Graymap(SampleEncoding), - - /// Magic numbers P3 and P6 - Pixmap(SampleEncoding), - - /// Magic number P7 - ArbitraryMap, -} - -/// Stores the complete header data of a file. -/// -/// Internally, provides mechanisms for lossless reencoding. After reading a file with the decoder -/// it is possible to recover the header and construct an encoder. Using the encoder on the just -/// loaded image should result in a byte copy of the original file (for single image pnms without -/// additional trailing data). -pub struct PnmHeader { - pub(crate) decoded: HeaderRecord, - pub(crate) encoded: Option<Vec<u8>>, -} - -pub(crate) enum HeaderRecord { - Bitmap(BitmapHeader), - Graymap(GraymapHeader), - Pixmap(PixmapHeader), - Arbitrary(ArbitraryHeader), -} - -/// Header produced by a `pbm` file ("Portable Bit Map") -#[derive(Clone, Copy, Debug)] -pub struct BitmapHeader { - /// Binary or Ascii encoded file - pub encoding: SampleEncoding, - - /// Height of the image file - pub height: u32, - - /// Width of the image file - pub width: u32, -} - -/// Header produced by a `pgm` file ("Portable Gray Map") -#[derive(Clone, Copy, Debug)] -pub struct GraymapHeader { - /// Binary or Ascii encoded file - pub encoding: SampleEncoding, - - /// Height of the image file - pub height: u32, - - /// Width of the image file - pub width: u32, - - /// Maximum sample value within the image - pub maxwhite: u32, -} - -/// Header produced by a `ppm` file ("Portable Pixel Map") -#[derive(Clone, Copy, Debug)] -pub struct PixmapHeader { - /// Binary or Ascii encoded file - pub encoding: SampleEncoding, - - /// Height of the image file - pub height: u32, - - /// Width of the image file - pub width: u32, - - /// Maximum sample value within the image - pub maxval: u32, -} - -/// Header produced by a `pam` file ("Portable Arbitrary Map") -#[derive(Clone, Debug)] -pub struct ArbitraryHeader { - /// Height of the image file - pub height: u32, - - /// Width of the image file - pub width: u32, - - /// Number of color channels - pub depth: u32, - - /// Maximum sample value within the image - pub maxval: u32, - - /// Color interpretation of image pixels - pub tupltype: Option<ArbitraryTuplType>, -} - -/// Standardized tuple type specifiers in the header of a `pam`. -#[derive(Clone, Debug)] -pub enum ArbitraryTuplType { - /// Pixels are either black (0) or white (1) - BlackAndWhite, - - /// Pixels are either black (0) or white (1) and a second alpha channel - BlackAndWhiteAlpha, - - /// Pixels represent the amount of white - Grayscale, - - /// Grayscale with an additional alpha channel - GrayscaleAlpha, - - /// Three channels: Red, Green, Blue - RGB, - - /// Four channels: Red, Green, Blue, Alpha - RGBAlpha, - - /// An image format which is not standardized - Custom(String), -} - -impl ArbitraryTuplType { - pub(crate) fn name(&self) -> &str { - match self { - ArbitraryTuplType::BlackAndWhite => "BLACKANDWHITE", - ArbitraryTuplType::BlackAndWhiteAlpha => "BLACKANDWHITE_ALPHA", - ArbitraryTuplType::Grayscale => "GRAYSCALE", - ArbitraryTuplType::GrayscaleAlpha => "GRAYSCALE_ALPHA", - ArbitraryTuplType::RGB => "RGB", - ArbitraryTuplType::RGBAlpha => "RGB_ALPHA", - ArbitraryTuplType::Custom(custom) => custom, - } - } -} - -impl PnmSubtype { - /// Get the two magic constant bytes corresponding to this format subtype. - pub fn magic_constant(self) -> &'static [u8; 2] { - match self { - PnmSubtype::Bitmap(SampleEncoding::Ascii) => b"P1", - PnmSubtype::Graymap(SampleEncoding::Ascii) => b"P2", - PnmSubtype::Pixmap(SampleEncoding::Ascii) => b"P3", - PnmSubtype::Bitmap(SampleEncoding::Binary) => b"P4", - PnmSubtype::Graymap(SampleEncoding::Binary) => b"P5", - PnmSubtype::Pixmap(SampleEncoding::Binary) => b"P6", - PnmSubtype::ArbitraryMap => b"P7", - } - } - - /// Whether samples are stored as binary or as decimal ascii - pub fn sample_encoding(self) -> SampleEncoding { - match self { - PnmSubtype::ArbitraryMap => SampleEncoding::Binary, - PnmSubtype::Bitmap(enc) => enc, - PnmSubtype::Graymap(enc) => enc, - PnmSubtype::Pixmap(enc) => enc, - } - } -} - -impl PnmHeader { - /// Retrieve the format subtype from which the header was created. - pub fn subtype(&self) -> PnmSubtype { - match self.decoded { - HeaderRecord::Bitmap(BitmapHeader { encoding, .. }) => PnmSubtype::Bitmap(encoding), - HeaderRecord::Graymap(GraymapHeader { encoding, .. }) => PnmSubtype::Graymap(encoding), - HeaderRecord::Pixmap(PixmapHeader { encoding, .. }) => PnmSubtype::Pixmap(encoding), - HeaderRecord::Arbitrary(ArbitraryHeader { .. }) => PnmSubtype::ArbitraryMap, - } - } - - /// The width of the image this header is for. - pub fn width(&self) -> u32 { - match self.decoded { - HeaderRecord::Bitmap(BitmapHeader { width, .. }) => width, - HeaderRecord::Graymap(GraymapHeader { width, .. }) => width, - HeaderRecord::Pixmap(PixmapHeader { width, .. }) => width, - HeaderRecord::Arbitrary(ArbitraryHeader { width, .. }) => width, - } - } - - /// The height of the image this header is for. - pub fn height(&self) -> u32 { - match self.decoded { - HeaderRecord::Bitmap(BitmapHeader { height, .. }) => height, - HeaderRecord::Graymap(GraymapHeader { height, .. }) => height, - HeaderRecord::Pixmap(PixmapHeader { height, .. }) => height, - HeaderRecord::Arbitrary(ArbitraryHeader { height, .. }) => height, - } - } - - /// The biggest value a sample can have. In other words, the colour resolution. - pub fn maximal_sample(&self) -> u32 { - match self.decoded { - HeaderRecord::Bitmap(BitmapHeader { .. }) => 1, - HeaderRecord::Graymap(GraymapHeader { maxwhite, .. }) => maxwhite, - HeaderRecord::Pixmap(PixmapHeader { maxval, .. }) => maxval, - HeaderRecord::Arbitrary(ArbitraryHeader { maxval, .. }) => maxval, - } - } - - /// Retrieve the underlying bitmap header if any - pub fn as_bitmap(&self) -> Option<&BitmapHeader> { - match self.decoded { - HeaderRecord::Bitmap(ref bitmap) => Some(bitmap), - _ => None, - } - } - - /// Retrieve the underlying graymap header if any - pub fn as_graymap(&self) -> Option<&GraymapHeader> { - match self.decoded { - HeaderRecord::Graymap(ref graymap) => Some(graymap), - _ => None, - } - } - - /// Retrieve the underlying pixmap header if any - pub fn as_pixmap(&self) -> Option<&PixmapHeader> { - match self.decoded { - HeaderRecord::Pixmap(ref pixmap) => Some(pixmap), - _ => None, - } - } - - /// Retrieve the underlying arbitrary header if any - pub fn as_arbitrary(&self) -> Option<&ArbitraryHeader> { - match self.decoded { - HeaderRecord::Arbitrary(ref arbitrary) => Some(arbitrary), - _ => None, - } - } - - /// Write the header back into a binary stream - pub fn write(&self, writer: &mut dyn io::Write) -> io::Result<()> { - writer.write_all(self.subtype().magic_constant())?; - match *self { - PnmHeader { - encoded: Some(ref content), - .. - } => writer.write_all(content), - PnmHeader { - decoded: - HeaderRecord::Bitmap(BitmapHeader { - encoding: _encoding, - width, - height, - }), - .. - } => writeln!(writer, "\n{} {}", width, height), - PnmHeader { - decoded: - HeaderRecord::Graymap(GraymapHeader { - encoding: _encoding, - width, - height, - maxwhite, - }), - .. - } => writeln!(writer, "\n{} {} {}", width, height, maxwhite), - PnmHeader { - decoded: - HeaderRecord::Pixmap(PixmapHeader { - encoding: _encoding, - width, - height, - maxval, - }), - .. - } => writeln!(writer, "\n{} {} {}", width, height, maxval), - PnmHeader { - decoded: - HeaderRecord::Arbitrary(ArbitraryHeader { - width, - height, - depth, - maxval, - ref tupltype, - }), - .. - } => { - struct TupltypeWriter<'a>(&'a Option<ArbitraryTuplType>); - impl<'a> fmt::Display for TupltypeWriter<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 { - Some(tt) => writeln!(f, "TUPLTYPE {}", tt.name()), - None => Ok(()), - } - } - } - - writeln!( - writer, - "\nWIDTH {}\nHEIGHT {}\nDEPTH {}\nMAXVAL {}\n{}ENDHDR", - width, - height, - depth, - maxval, - TupltypeWriter(tupltype) - ) - } - } - } -} - -impl From<BitmapHeader> for PnmHeader { - fn from(header: BitmapHeader) -> Self { - PnmHeader { - decoded: HeaderRecord::Bitmap(header), - encoded: None, - } - } -} - -impl From<GraymapHeader> for PnmHeader { - fn from(header: GraymapHeader) -> Self { - PnmHeader { - decoded: HeaderRecord::Graymap(header), - encoded: None, - } - } -} - -impl From<PixmapHeader> for PnmHeader { - fn from(header: PixmapHeader) -> Self { - PnmHeader { - decoded: HeaderRecord::Pixmap(header), - encoded: None, - } - } -} - -impl From<ArbitraryHeader> for PnmHeader { - fn from(header: ArbitraryHeader) -> Self { - PnmHeader { - decoded: HeaderRecord::Arbitrary(header), - encoded: None, - } - } -} diff --git a/vendor/image/src/codecs/pnm/mod.rs b/vendor/image/src/codecs/pnm/mod.rs deleted file mode 100644 index de8612d..0000000 --- a/vendor/image/src/codecs/pnm/mod.rs +++ /dev/null @@ -1,184 +0,0 @@ -//! Decoding of netpbm image formats (pbm, pgm, ppm and pam). -//! -//! The formats pbm, pgm and ppm are fully supported. The pam decoder recognizes the tuple types -//! `BLACKANDWHITE`, `GRAYSCALE` and `RGB` and explicitly recognizes but rejects their `_ALPHA` -//! variants for now as alpha color types are unsupported. -use self::autobreak::AutoBreak; -pub use self::decoder::PnmDecoder; -pub use self::encoder::PnmEncoder; -use self::header::HeaderRecord; -pub use self::header::{ - ArbitraryHeader, ArbitraryTuplType, BitmapHeader, GraymapHeader, PixmapHeader, -}; -pub use self::header::{PnmHeader, PnmSubtype, SampleEncoding}; - -mod autobreak; -mod decoder; -mod encoder; -mod header; - -#[cfg(test)] -mod tests { - use super::*; - use crate::color::ColorType; - use crate::image::ImageDecoder; - use byteorder::{ByteOrder, NativeEndian}; - - fn execute_roundtrip_default(buffer: &[u8], width: u32, height: u32, color: ColorType) { - let mut encoded_buffer = Vec::new(); - - { - let mut encoder = PnmEncoder::new(&mut encoded_buffer); - encoder - .encode(buffer, width, height, color) - .expect("Failed to encode the image buffer"); - } - - let (header, loaded_color, loaded_image) = { - let decoder = PnmDecoder::new(&encoded_buffer[..]).unwrap(); - let color_type = decoder.color_type(); - let mut image = vec![0; decoder.total_bytes() as usize]; - decoder - .read_image(&mut image) - .expect("Failed to decode the image"); - let (_, header) = PnmDecoder::new(&encoded_buffer[..]).unwrap().into_inner(); - (header, color_type, image) - }; - - assert_eq!(header.width(), width); - assert_eq!(header.height(), height); - assert_eq!(loaded_color, color); - assert_eq!(loaded_image.as_slice(), buffer); - } - - fn execute_roundtrip_with_subtype( - buffer: &[u8], - width: u32, - height: u32, - color: ColorType, - subtype: PnmSubtype, - ) { - let mut encoded_buffer = Vec::new(); - - { - let mut encoder = PnmEncoder::new(&mut encoded_buffer).with_subtype(subtype); - encoder - .encode(buffer, width, height, color) - .expect("Failed to encode the image buffer"); - } - - let (header, loaded_color, loaded_image) = { - let decoder = PnmDecoder::new(&encoded_buffer[..]).unwrap(); - let color_type = decoder.color_type(); - let mut image = vec![0; decoder.total_bytes() as usize]; - decoder - .read_image(&mut image) - .expect("Failed to decode the image"); - let (_, header) = PnmDecoder::new(&encoded_buffer[..]).unwrap().into_inner(); - (header, color_type, image) - }; - - assert_eq!(header.width(), width); - assert_eq!(header.height(), height); - assert_eq!(header.subtype(), subtype); - assert_eq!(loaded_color, color); - assert_eq!(loaded_image.as_slice(), buffer); - } - - fn execute_roundtrip_u16(buffer: &[u16], width: u32, height: u32, color: ColorType) { - let mut encoded_buffer = Vec::new(); - - { - let mut encoder = PnmEncoder::new(&mut encoded_buffer); - encoder - .encode(buffer, width, height, color) - .expect("Failed to encode the image buffer"); - } - - let (header, loaded_color, loaded_image) = { - let decoder = PnmDecoder::new(&encoded_buffer[..]).unwrap(); - let color_type = decoder.color_type(); - let mut image = vec![0; decoder.total_bytes() as usize]; - decoder - .read_image(&mut image) - .expect("Failed to decode the image"); - let (_, header) = PnmDecoder::new(&encoded_buffer[..]).unwrap().into_inner(); - (header, color_type, image) - }; - - let mut buffer_u8 = vec![0; buffer.len() * 2]; - NativeEndian::write_u16_into(buffer, &mut buffer_u8[..]); - - assert_eq!(header.width(), width); - assert_eq!(header.height(), height); - assert_eq!(loaded_color, color); - assert_eq!(loaded_image, buffer_u8); - } - - #[test] - fn roundtrip_gray() { - #[rustfmt::skip] - let buf: [u8; 16] = [ - 0, 0, 0, 255, - 255, 255, 255, 255, - 255, 0, 255, 0, - 255, 0, 0, 0, - ]; - - execute_roundtrip_default(&buf, 4, 4, ColorType::L8); - execute_roundtrip_with_subtype(&buf, 4, 4, ColorType::L8, PnmSubtype::ArbitraryMap); - execute_roundtrip_with_subtype( - &buf, - 4, - 4, - ColorType::L8, - PnmSubtype::Graymap(SampleEncoding::Ascii), - ); - execute_roundtrip_with_subtype( - &buf, - 4, - 4, - ColorType::L8, - PnmSubtype::Graymap(SampleEncoding::Binary), - ); - } - - #[test] - fn roundtrip_rgb() { - #[rustfmt::skip] - let buf: [u8; 27] = [ - 0, 0, 0, - 0, 0, 255, - 0, 255, 0, - 0, 255, 255, - 255, 0, 0, - 255, 0, 255, - 255, 255, 0, - 255, 255, 255, - 255, 255, 255, - ]; - execute_roundtrip_default(&buf, 3, 3, ColorType::Rgb8); - execute_roundtrip_with_subtype(&buf, 3, 3, ColorType::Rgb8, PnmSubtype::ArbitraryMap); - execute_roundtrip_with_subtype( - &buf, - 3, - 3, - ColorType::Rgb8, - PnmSubtype::Pixmap(SampleEncoding::Binary), - ); - execute_roundtrip_with_subtype( - &buf, - 3, - 3, - ColorType::Rgb8, - PnmSubtype::Pixmap(SampleEncoding::Ascii), - ); - } - - #[test] - fn roundtrip_u16() { - let buf: [u16; 6] = [0, 1, 0xFFFF, 0x1234, 0x3412, 0xBEAF]; - - execute_roundtrip_u16(&buf, 6, 1, ColorType::L16); - } -} |