diff options
Diffstat (limited to 'vendor/image/src/io')
-rw-r--r-- | vendor/image/src/io/free_functions.rs | 312 | ||||
-rw-r--r-- | vendor/image/src/io/mod.rs | 166 | ||||
-rw-r--r-- | vendor/image/src/io/reader.rs | 239 |
3 files changed, 0 insertions, 717 deletions
diff --git a/vendor/image/src/io/free_functions.rs b/vendor/image/src/io/free_functions.rs deleted file mode 100644 index d6047d7..0000000 --- a/vendor/image/src/io/free_functions.rs +++ /dev/null @@ -1,312 +0,0 @@ -use std::fs::File; -use std::io::{BufRead, BufReader, BufWriter, Seek}; -use std::path::Path; -use std::u32; - -use crate::codecs::*; - -use crate::dynimage::DynamicImage; -use crate::error::{ImageError, ImageFormatHint, ImageResult}; -use crate::image; -use crate::image::ImageFormat; -#[allow(unused_imports)] // When no features are supported -use crate::image::{ImageDecoder, ImageEncoder}; -use crate::{ - color, - error::{UnsupportedError, UnsupportedErrorKind}, - ImageOutputFormat, -}; - -pub(crate) fn open_impl(path: &Path) -> ImageResult<DynamicImage> { - let buffered_read = BufReader::new(File::open(path).map_err(ImageError::IoError)?); - - load(buffered_read, ImageFormat::from_path(path)?) -} - -/// Create a new image from a Reader. -/// -/// Assumes the reader is already buffered. For optimal performance, -/// consider wrapping the reader with a `BufReader::new()`. -/// -/// Try [`io::Reader`] for more advanced uses. -/// -/// [`io::Reader`]: io/struct.Reader.html -#[allow(unused_variables)] -// r is unused if no features are supported. -pub fn load<R: BufRead + Seek>(r: R, format: ImageFormat) -> ImageResult<DynamicImage> { - load_inner(r, super::Limits::default(), format) -} - -pub(crate) trait DecoderVisitor { - type Result; - fn visit_decoder<'a, D: ImageDecoder<'a>>(self, decoder: D) -> ImageResult<Self::Result>; -} - -pub(crate) fn load_decoder<R: BufRead + Seek, V: DecoderVisitor>( - r: R, - format: ImageFormat, - limits: super::Limits, - visitor: V, -) -> ImageResult<V::Result> { - #[allow(unreachable_patterns)] - // Default is unreachable if all features are supported. - match format { - #[cfg(feature = "avif-decoder")] - image::ImageFormat::Avif => visitor.visit_decoder(avif::AvifDecoder::new(r)?), - #[cfg(feature = "png")] - image::ImageFormat::Png => visitor.visit_decoder(png::PngDecoder::with_limits(r, limits)?), - #[cfg(feature = "gif")] - image::ImageFormat::Gif => visitor.visit_decoder(gif::GifDecoder::new(r)?), - #[cfg(feature = "jpeg")] - image::ImageFormat::Jpeg => visitor.visit_decoder(jpeg::JpegDecoder::new(r)?), - #[cfg(feature = "webp")] - image::ImageFormat::WebP => visitor.visit_decoder(webp::WebPDecoder::new(r)?), - #[cfg(feature = "tiff")] - image::ImageFormat::Tiff => visitor.visit_decoder(tiff::TiffDecoder::new(r)?), - #[cfg(feature = "tga")] - image::ImageFormat::Tga => visitor.visit_decoder(tga::TgaDecoder::new(r)?), - #[cfg(feature = "dds")] - image::ImageFormat::Dds => visitor.visit_decoder(dds::DdsDecoder::new(r)?), - #[cfg(feature = "bmp")] - image::ImageFormat::Bmp => visitor.visit_decoder(bmp::BmpDecoder::new(r)?), - #[cfg(feature = "ico")] - image::ImageFormat::Ico => visitor.visit_decoder(ico::IcoDecoder::new(r)?), - #[cfg(feature = "hdr")] - image::ImageFormat::Hdr => visitor.visit_decoder(hdr::HdrAdapter::new(BufReader::new(r))?), - #[cfg(feature = "exr")] - image::ImageFormat::OpenExr => visitor.visit_decoder(openexr::OpenExrDecoder::new(r)?), - #[cfg(feature = "pnm")] - image::ImageFormat::Pnm => visitor.visit_decoder(pnm::PnmDecoder::new(r)?), - #[cfg(feature = "farbfeld")] - image::ImageFormat::Farbfeld => visitor.visit_decoder(farbfeld::FarbfeldDecoder::new(r)?), - #[cfg(feature = "qoi")] - image::ImageFormat::Qoi => visitor.visit_decoder(qoi::QoiDecoder::new(r)?), - _ => Err(ImageError::Unsupported( - ImageFormatHint::Exact(format).into(), - )), - } -} - -pub(crate) fn load_inner<R: BufRead + Seek>( - r: R, - limits: super::Limits, - format: ImageFormat, -) -> ImageResult<DynamicImage> { - struct LoadVisitor(super::Limits); - - impl DecoderVisitor for LoadVisitor { - type Result = DynamicImage; - - fn visit_decoder<'a, D: ImageDecoder<'a>>( - self, - mut decoder: D, - ) -> ImageResult<Self::Result> { - let mut limits = self.0; - // Check that we do not allocate a bigger buffer than we are allowed to - // FIXME: should this rather go in `DynamicImage::from_decoder` somehow? - limits.reserve(decoder.total_bytes())?; - decoder.set_limits(limits)?; - DynamicImage::from_decoder(decoder) - } - } - - load_decoder(r, format, limits.clone(), LoadVisitor(limits)) -} - -pub(crate) fn image_dimensions_impl(path: &Path) -> ImageResult<(u32, u32)> { - let format = image::ImageFormat::from_path(path)?; - let reader = BufReader::new(File::open(path)?); - image_dimensions_with_format_impl(reader, format) -} - -#[allow(unused_variables)] -// fin is unused if no features are supported. -pub(crate) fn image_dimensions_with_format_impl<R: BufRead + Seek>( - buffered_read: R, - format: ImageFormat, -) -> ImageResult<(u32, u32)> { - struct DimVisitor; - - impl DecoderVisitor for DimVisitor { - type Result = (u32, u32); - fn visit_decoder<'a, D: ImageDecoder<'a>>(self, decoder: D) -> ImageResult<Self::Result> { - Ok(decoder.dimensions()) - } - } - - load_decoder(buffered_read, format, super::Limits::default(), DimVisitor) -} - -#[allow(unused_variables)] -// Most variables when no features are supported -pub(crate) fn save_buffer_impl( - path: &Path, - buf: &[u8], - width: u32, - height: u32, - color: color::ColorType, -) -> ImageResult<()> { - let format = ImageFormat::from_path(path)?; - save_buffer_with_format_impl(path, buf, width, height, color, format) -} - -#[allow(unused_variables)] -// Most variables when no features are supported -pub(crate) fn save_buffer_with_format_impl( - path: &Path, - buf: &[u8], - width: u32, - height: u32, - color: color::ColorType, - format: ImageFormat, -) -> ImageResult<()> { - let buffered_file_write = &mut BufWriter::new(File::create(path)?); // always seekable - - let format = match format { - #[cfg(feature = "pnm")] - image::ImageFormat::Pnm => { - let ext = path - .extension() - .and_then(|s| s.to_str()) - .map_or("".to_string(), |s| s.to_ascii_lowercase()); - ImageOutputFormat::Pnm(match &*ext { - "pbm" => pnm::PnmSubtype::Bitmap(pnm::SampleEncoding::Binary), - "pgm" => pnm::PnmSubtype::Graymap(pnm::SampleEncoding::Binary), - "ppm" => pnm::PnmSubtype::Pixmap(pnm::SampleEncoding::Binary), - "pam" => pnm::PnmSubtype::ArbitraryMap, - _ => { - return Err(ImageError::Unsupported( - ImageFormatHint::Exact(format).into(), - )) - } // Unsupported Pnm subtype. - }) - } - // #[cfg(feature = "hdr")] - // image::ImageFormat::Hdr => hdr::HdrEncoder::new(fout).encode(&[Rgb<f32>], width, height), // usize - format => format.into(), - }; - - write_buffer_impl(buffered_file_write, buf, width, height, color, format) -} - -#[allow(unused_variables)] -// Most variables when no features are supported -pub(crate) fn write_buffer_impl<W: std::io::Write + Seek>( - buffered_write: &mut W, - buf: &[u8], - width: u32, - height: u32, - color: color::ColorType, - format: ImageOutputFormat, -) -> ImageResult<()> { - match format { - #[cfg(feature = "png")] - ImageOutputFormat::Png => { - png::PngEncoder::new(buffered_write).write_image(buf, width, height, color) - } - #[cfg(feature = "jpeg")] - ImageOutputFormat::Jpeg(quality) => { - jpeg::JpegEncoder::new_with_quality(buffered_write, quality) - .write_image(buf, width, height, color) - } - #[cfg(feature = "pnm")] - ImageOutputFormat::Pnm(subtype) => pnm::PnmEncoder::new(buffered_write) - .with_subtype(subtype) - .write_image(buf, width, height, color), - #[cfg(feature = "gif")] - ImageOutputFormat::Gif => { - gif::GifEncoder::new(buffered_write).encode(buf, width, height, color) - } - #[cfg(feature = "ico")] - ImageOutputFormat::Ico => { - ico::IcoEncoder::new(buffered_write).write_image(buf, width, height, color) - } - #[cfg(feature = "bmp")] - ImageOutputFormat::Bmp => { - bmp::BmpEncoder::new(buffered_write).write_image(buf, width, height, color) - } - #[cfg(feature = "farbfeld")] - ImageOutputFormat::Farbfeld => { - farbfeld::FarbfeldEncoder::new(buffered_write).write_image(buf, width, height, color) - } - #[cfg(feature = "tga")] - ImageOutputFormat::Tga => { - tga::TgaEncoder::new(buffered_write).write_image(buf, width, height, color) - } - #[cfg(feature = "exr")] - ImageOutputFormat::OpenExr => { - openexr::OpenExrEncoder::new(buffered_write).write_image(buf, width, height, color) - } - #[cfg(feature = "tiff")] - ImageOutputFormat::Tiff => { - tiff::TiffEncoder::new(buffered_write).write_image(buf, width, height, color) - } - #[cfg(feature = "avif-encoder")] - ImageOutputFormat::Avif => { - avif::AvifEncoder::new(buffered_write).write_image(buf, width, height, color) - } - #[cfg(feature = "qoi")] - ImageOutputFormat::Qoi => { - qoi::QoiEncoder::new(buffered_write).write_image(buf, width, height, color) - } - #[cfg(feature = "webp-encoder")] - ImageOutputFormat::WebP => { - webp::WebPEncoder::new(buffered_write).write_image(buf, width, height, color) - } - - image::ImageOutputFormat::Unsupported(msg) => Err(ImageError::Unsupported( - UnsupportedError::from_format_and_kind( - ImageFormatHint::Unknown, - UnsupportedErrorKind::Format(ImageFormatHint::Name(msg)), - ), - )), - } -} - -static MAGIC_BYTES: [(&[u8], ImageFormat); 23] = [ - (b"\x89PNG\r\n\x1a\n", ImageFormat::Png), - (&[0xff, 0xd8, 0xff], ImageFormat::Jpeg), - (b"GIF89a", ImageFormat::Gif), - (b"GIF87a", ImageFormat::Gif), - (b"RIFF", ImageFormat::WebP), // TODO: better magic byte detection, see https://github.com/image-rs/image/issues/660 - (b"MM\x00*", ImageFormat::Tiff), - (b"II*\x00", ImageFormat::Tiff), - (b"DDS ", ImageFormat::Dds), - (b"BM", ImageFormat::Bmp), - (&[0, 0, 1, 0], ImageFormat::Ico), - (b"#?RADIANCE", ImageFormat::Hdr), - (b"P1", ImageFormat::Pnm), - (b"P2", ImageFormat::Pnm), - (b"P3", ImageFormat::Pnm), - (b"P4", ImageFormat::Pnm), - (b"P5", ImageFormat::Pnm), - (b"P6", ImageFormat::Pnm), - (b"P7", ImageFormat::Pnm), - (b"farbfeld", ImageFormat::Farbfeld), - (b"\0\0\0 ftypavif", ImageFormat::Avif), - (b"\0\0\0\x1cftypavif", ImageFormat::Avif), - (&[0x76, 0x2f, 0x31, 0x01], ImageFormat::OpenExr), // = &exr::meta::magic_number::BYTES - (b"qoif", ImageFormat::Qoi), -]; - -/// Guess image format from memory block -/// -/// Makes an educated guess about the image format based on the Magic Bytes at the beginning. -/// TGA is not supported by this function. -/// This is not to be trusted on the validity of the whole memory block -pub fn guess_format(buffer: &[u8]) -> ImageResult<ImageFormat> { - match guess_format_impl(buffer) { - Some(format) => Ok(format), - None => Err(ImageError::Unsupported(ImageFormatHint::Unknown.into())), - } -} - -pub(crate) fn guess_format_impl(buffer: &[u8]) -> Option<ImageFormat> { - for &(signature, format) in &MAGIC_BYTES { - if buffer.starts_with(signature) { - return Some(format); - } - } - - None -} diff --git a/vendor/image/src/io/mod.rs b/vendor/image/src/io/mod.rs deleted file mode 100644 index 8fbc6e2..0000000 --- a/vendor/image/src/io/mod.rs +++ /dev/null @@ -1,166 +0,0 @@ -//! Input and output of images. - -use std::convert::TryFrom; - -use crate::{error, ImageError, ImageResult}; - -pub(crate) mod free_functions; -mod reader; - -pub use self::reader::Reader; - -/// Set of supported strict limits for a decoder. -#[derive(Clone, Debug, Eq, PartialEq, Hash)] -#[allow(missing_copy_implementations)] -#[allow(clippy::manual_non_exhaustive)] -pub struct LimitSupport { - _non_exhaustive: (), -} - -#[allow(clippy::derivable_impls)] -impl Default for LimitSupport { - fn default() -> LimitSupport { - LimitSupport { - _non_exhaustive: (), - } - } -} - -/// Resource limits for decoding. -/// -/// Limits can be either *strict* or *non-strict*. Non-strict limits are best-effort -/// limits where the library does not guarantee that limit will not be exceeded. Do note -/// that it is still considered a bug if a non-strict limit is exceeded, however as -/// some of the underlying decoders do not support not support such limits one cannot -/// rely on these limits being supported. For stric limits the library makes a stronger -/// guarantee that the limit will not be exceeded. Exceeding a strict limit is considered -/// a critical bug. If a decoder cannot guarantee that it will uphold a strict limit it -/// *must* fail with `image::error::LimitErrorKind::Unsupported`. -/// -/// Currently the only strict limits supported are the `max_image_width` and `max_image_height` -/// limits, however more will be added in the future. [`LimitSupport`] will default to support -/// being false and decoders should enable support for the limits they support in -/// [`ImageDecoder::set_limits`]. -/// -/// The limit check should only ever fail if a limit will be exceeded or an unsupported strict -/// limit is used. -/// -/// [`LimitSupport`]: ./struct.LimitSupport.html -/// [`ImageDecoder::set_limits`]: ../trait.ImageDecoder.html#method.set_limits -#[derive(Clone, Debug, Eq, PartialEq, Hash)] -#[allow(missing_copy_implementations)] -#[allow(clippy::manual_non_exhaustive)] -pub struct Limits { - /// The maximum allowed image width. This limit is strict. The default is no limit. - pub max_image_width: Option<u32>, - /// The maximum allowed image height. This limit is strict. The default is no limit. - pub max_image_height: Option<u32>, - /// The maximum allowed sum of allocations allocated by the decoder at any one time excluding - /// allocator overhead. This limit is non-strict by default and some decoders may ignore it. - /// The default is 512MiB. - pub max_alloc: Option<u64>, - _non_exhaustive: (), -} - -impl Default for Limits { - fn default() -> Limits { - Limits { - max_image_width: None, - max_image_height: None, - max_alloc: Some(512 * 1024 * 1024), - _non_exhaustive: (), - } - } -} - -impl Limits { - /// Disable all limits. - pub fn no_limits() -> Limits { - Limits { - max_image_width: None, - max_image_height: None, - max_alloc: None, - _non_exhaustive: (), - } - } - - /// This function checks that all currently set strict limits are supported. - pub fn check_support(&self, _supported: &LimitSupport) -> ImageResult<()> { - Ok(()) - } - - /// This function checks the `max_image_width` and `max_image_height` limits given - /// the image width and height. - pub fn check_dimensions(&self, width: u32, height: u32) -> ImageResult<()> { - if let Some(max_width) = self.max_image_width { - if width > max_width { - return Err(ImageError::Limits(error::LimitError::from_kind( - error::LimitErrorKind::DimensionError, - ))); - } - } - - if let Some(max_height) = self.max_image_height { - if height > max_height { - return Err(ImageError::Limits(error::LimitError::from_kind( - error::LimitErrorKind::DimensionError, - ))); - } - } - - Ok(()) - } - - /// This function checks that the current limit allows for reserving the set amount - /// of bytes, it then reduces the limit accordingly. - pub fn reserve(&mut self, amount: u64) -> ImageResult<()> { - if let Some(max_alloc) = self.max_alloc.as_mut() { - if *max_alloc < amount { - return Err(ImageError::Limits(error::LimitError::from_kind( - error::LimitErrorKind::InsufficientMemory, - ))); - } - - *max_alloc -= amount; - } - - Ok(()) - } - - /// This function acts identically to [`reserve`], but takes a `usize` for convenience. - pub fn reserve_usize(&mut self, amount: usize) -> ImageResult<()> { - match u64::try_from(amount) { - Ok(n) => self.reserve(n), - Err(_) if self.max_alloc.is_some() => Err(ImageError::Limits( - error::LimitError::from_kind(error::LimitErrorKind::InsufficientMemory), - )), - Err(_) => { - // Out of bounds, but we weren't asked to consider any limit. - Ok(()) - } - } - } - - /// This function increases the `max_alloc` limit with amount. Should only be used - /// together with [`reserve`]. - /// - /// [`reserve`]: #method.reserve - pub fn free(&mut self, amount: u64) { - if let Some(max_alloc) = self.max_alloc.as_mut() { - *max_alloc = max_alloc.saturating_add(amount); - } - } - - /// This function acts identically to [`free`], but takes a `usize` for convenience. - pub fn free_usize(&mut self, amount: usize) { - match u64::try_from(amount) { - Ok(n) => self.free(n), - Err(_) if self.max_alloc.is_some() => { - panic!("max_alloc is set, we should have exited earlier when the reserve failed"); - } - Err(_) => { - // Out of bounds, but we weren't asked to consider any limit. - } - } - } -} diff --git a/vendor/image/src/io/reader.rs b/vendor/image/src/io/reader.rs deleted file mode 100644 index 660780f..0000000 --- a/vendor/image/src/io/reader.rs +++ /dev/null @@ -1,239 +0,0 @@ -use std::fs::File; -use std::io::{self, BufRead, BufReader, Cursor, Read, Seek, SeekFrom}; -use std::path::Path; - -use crate::dynimage::DynamicImage; -use crate::error::{ImageFormatHint, UnsupportedError, UnsupportedErrorKind}; -use crate::image::ImageFormat; -use crate::{ImageError, ImageResult}; - -use super::free_functions; - -/// A multi-format image reader. -/// -/// Wraps an input reader to facilitate automatic detection of an image's format, appropriate -/// decoding method, and dispatches into the set of supported [`ImageDecoder`] implementations. -/// -/// ## Usage -/// -/// Opening a file, deducing the format based on the file path automatically, and trying to decode -/// the image contained can be performed by constructing the reader and immediately consuming it. -/// -/// ```no_run -/// # use image::ImageError; -/// # use image::io::Reader; -/// # fn main() -> Result<(), ImageError> { -/// let image = Reader::open("path/to/image.png")? -/// .decode()?; -/// # Ok(()) } -/// ``` -/// -/// It is also possible to make a guess based on the content. This is especially handy if the -/// source is some blob in memory and you have constructed the reader in another way. Here is an -/// example with a `pnm` black-and-white subformat that encodes its pixel matrix with ascii values. -/// -/// ``` -/// # use image::ImageError; -/// # use image::io::Reader; -/// # fn main() -> Result<(), ImageError> { -/// use std::io::Cursor; -/// use image::ImageFormat; -/// -/// let raw_data = b"P1 2 2\n\ -/// 0 1\n\ -/// 1 0\n"; -/// -/// let mut reader = Reader::new(Cursor::new(raw_data)) -/// .with_guessed_format() -/// .expect("Cursor io never fails"); -/// assert_eq!(reader.format(), Some(ImageFormat::Pnm)); -/// -/// # #[cfg(feature = "pnm")] -/// let image = reader.decode()?; -/// # Ok(()) } -/// ``` -/// -/// As a final fallback or if only a specific format must be used, the reader always allows manual -/// specification of the supposed image format with [`set_format`]. -/// -/// [`set_format`]: #method.set_format -/// [`ImageDecoder`]: ../trait.ImageDecoder.html -pub struct Reader<R: Read> { - /// The reader. Should be buffered. - inner: R, - /// The format, if one has been set or deduced. - format: Option<ImageFormat>, - /// Decoding limits - limits: super::Limits, -} - -impl<R: Read> Reader<R> { - /// Create a new image reader without a preset format. - /// - /// Assumes the reader is already buffered. For optimal performance, - /// consider wrapping the reader with a `BufReader::new()`. - /// - /// It is possible to guess the format based on the content of the read object with - /// [`with_guessed_format`], or to set the format directly with [`set_format`]. - /// - /// [`with_guessed_format`]: #method.with_guessed_format - /// [`set_format`]: method.set_format - pub fn new(buffered_reader: R) -> Self { - Reader { - inner: buffered_reader, - format: None, - limits: super::Limits::default(), - } - } - - /// Construct a reader with specified format. - /// - /// Assumes the reader is already buffered. For optimal performance, - /// consider wrapping the reader with a `BufReader::new()`. - pub fn with_format(buffered_reader: R, format: ImageFormat) -> Self { - Reader { - inner: buffered_reader, - format: Some(format), - limits: super::Limits::default(), - } - } - - /// Get the currently determined format. - pub fn format(&self) -> Option<ImageFormat> { - self.format - } - - /// Supply the format as which to interpret the read image. - pub fn set_format(&mut self, format: ImageFormat) { - self.format = Some(format); - } - - /// Remove the current information on the image format. - /// - /// Note that many operations require format information to be present and will return e.g. an - /// `ImageError::Unsupported` when the image format has not been set. - pub fn clear_format(&mut self) { - self.format = None; - } - - /// Disable all decoding limits. - pub fn no_limits(&mut self) { - self.limits = super::Limits::no_limits(); - } - - /// Set a custom set of decoding limits. - pub fn limits(&mut self, limits: super::Limits) { - self.limits = limits; - } - - /// Unwrap the reader. - pub fn into_inner(self) -> R { - self.inner - } -} - -impl Reader<BufReader<File>> { - /// Open a file to read, format will be guessed from path. - /// - /// This will not attempt any io operation on the opened file. - /// - /// If you want to inspect the content for a better guess on the format, which does not depend - /// on file extensions, follow this call with a call to [`with_guessed_format`]. - /// - /// [`with_guessed_format`]: #method.with_guessed_format - pub fn open<P>(path: P) -> io::Result<Self> - where - P: AsRef<Path>, - { - Self::open_impl(path.as_ref()) - } - - fn open_impl(path: &Path) -> io::Result<Self> { - Ok(Reader { - inner: BufReader::new(File::open(path)?), - format: ImageFormat::from_path(path).ok(), - limits: super::Limits::default(), - }) - } -} - -impl<R: BufRead + Seek> Reader<R> { - /// Make a format guess based on the content, replacing it on success. - /// - /// Returns `Ok` with the guess if no io error occurs. Additionally, replaces the current - /// format if the guess was successful. If the guess was unable to determine a format then - /// the current format of the reader is unchanged. - /// - /// Returns an error if the underlying reader fails. The format is unchanged. The error is a - /// `std::io::Error` and not `ImageError` since the only error case is an error when the - /// underlying reader seeks. - /// - /// When an error occurs, the reader may not have been properly reset and it is potentially - /// hazardous to continue with more io. - /// - /// ## Usage - /// - /// This supplements the path based type deduction from [`open`](Reader::open) with content based deduction. - /// This is more common in Linux and UNIX operating systems and also helpful if the path can - /// not be directly controlled. - /// - /// ```no_run - /// # use image::ImageError; - /// # use image::io::Reader; - /// # fn main() -> Result<(), ImageError> { - /// let image = Reader::open("image.unknown")? - /// .with_guessed_format()? - /// .decode()?; - /// # Ok(()) } - /// ``` - pub fn with_guessed_format(mut self) -> io::Result<Self> { - let format = self.guess_format()?; - // Replace format if found, keep current state if not. - self.format = format.or(self.format); - Ok(self) - } - - fn guess_format(&mut self) -> io::Result<Option<ImageFormat>> { - let mut start = [0; 16]; - - // Save current offset, read start, restore offset. - let cur = self.inner.stream_position()?; - let len = io::copy( - // Accept shorter files but read at most 16 bytes. - &mut self.inner.by_ref().take(16), - &mut Cursor::new(&mut start[..]), - )?; - self.inner.seek(SeekFrom::Start(cur))?; - - Ok(free_functions::guess_format_impl(&start[..len as usize])) - } - - /// Read the image dimensions. - /// - /// Uses the current format to construct the correct reader for the format. - /// - /// If no format was determined, returns an `ImageError::Unsupported`. - pub fn into_dimensions(mut self) -> ImageResult<(u32, u32)> { - let format = self.require_format()?; - free_functions::image_dimensions_with_format_impl(self.inner, format) - } - - /// Read the image (replaces `load`). - /// - /// Uses the current format to construct the correct reader for the format. - /// - /// If no format was determined, returns an `ImageError::Unsupported`. - pub fn decode(mut self) -> ImageResult<DynamicImage> { - let format = self.require_format()?; - free_functions::load_inner(self.inner, self.limits, format) - } - - fn require_format(&mut self) -> ImageResult<ImageFormat> { - self.format.ok_or_else(|| { - ImageError::Unsupported(UnsupportedError::from_format_and_kind( - ImageFormatHint::Unknown, - UnsupportedErrorKind::Format(ImageFormatHint::Unknown), - )) - }) - } -} |