Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
239
third-party/vendor/image/src/io/reader.rs
vendored
Normal file
239
third-party/vendor/image/src/io/reader.rs
vendored
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
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),
|
||||
))
|
||||
})
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue