diff --git a/README.md b/README.md index ec218fbbe7..e3eb168058 100644 --- a/README.md +++ b/README.md @@ -16,11 +16,11 @@ All image processing functions provided operate on types that implement the `Gen ## High level API -Load images using [`io::Reader`]: +Load images using [`ImageReader`]: ```rust,ignore use std::io::Cursor; -use image::io::Reader as ImageReader; +use image::ImageReader; let img = ImageReader::open("myimage.png")?.decode()?; let img2 = ImageReader::new(Cursor::new(bytes)).with_guessed_format()?.decode()?; diff --git a/fuzz/fuzzers/fuzzer_script_exr.rs b/fuzz/fuzzers/fuzzer_script_exr.rs index f42ffec4d6..75893f3433 100644 --- a/fuzz/fuzzers/fuzzer_script_exr.rs +++ b/fuzz/fuzzers/fuzzer_script_exr.rs @@ -4,7 +4,7 @@ extern crate libfuzzer_sys; extern crate image; use image::codecs::openexr::*; -use image::io::Limits; +use image::Limits; use image::ExtendedColorType; use image::ImageDecoder; use image::ImageEncoder; diff --git a/src/dynimage.rs b/src/dynimage.rs index 94bfe8f4e8..dcb716f6de 100644 --- a/src/dynimage.rs +++ b/src/dynimage.rs @@ -17,6 +17,7 @@ use crate::image::{GenericImage, GenericImageView, ImageDecoder, ImageEncoder, I use crate::io::free_functions; use crate::math::resize_dimensions; use crate::traits::Pixel; +use crate::ImageReader; use crate::{image, Luma, LumaA}; use crate::{imageops, ExtendedColorType}; use crate::{Rgb32FImage, Rgba32FImage}; @@ -1097,29 +1098,25 @@ fn decoder_to_image(decoder: I) -> ImageResult { /// Open the image located at the path specified. /// The image's format is determined from the path's file extension. /// -/// Try [`io::Reader`] for more advanced uses, including guessing the format based on the file's +/// Try [`ImageReader`] for more advanced uses, including guessing the format based on the file's /// content before its path. -/// -/// [`io::Reader`]: io/struct.Reader.html pub fn open

(path: P) -> ImageResult where P: AsRef, { - crate::io::Reader::open(path)?.decode() + ImageReader::open(path)?.decode() } /// Read a tuple containing the (width, height) of the image located at the specified path. /// This is faster than fully loading the image and then getting its dimensions. /// -/// Try [`io::Reader`] for more advanced uses, including guessing the format based on the file's +/// Try [`ImageReader`] for more advanced uses, including guessing the format based on the file's /// content before its path or manually supplying the format. -/// -/// [`io::Reader`]: io/struct.Reader.html pub fn image_dimensions

(path: P) -> ImageResult<(u32, u32)> where P: AsRef, { - crate::io::Reader::open(path)?.into_dimensions() + ImageReader::open(path)?.into_dimensions() } /// Saves the supplied buffer to a file at the path specified. @@ -1191,9 +1188,7 @@ pub fn write_buffer_with_format( /// Makes an educated guess about the image format. /// TGA is not supported by this function. /// -/// Try [`io::Reader`] for more advanced uses. -/// -/// [`io::Reader`]: io/struct.Reader.html +/// Try [`ImageReader`] for more advanced uses. pub fn load_from_memory(buffer: &[u8]) -> ImageResult { let format = free_functions::guess_format(buffer)?; load_from_memory_with_format(buffer, format) @@ -1204,10 +1199,9 @@ pub fn load_from_memory(buffer: &[u8]) -> ImageResult { /// This is just a simple wrapper that constructs an `std::io::Cursor` around the buffer and then /// calls `load` with that reader. /// -/// Try [`io::Reader`] for more advanced uses. +/// Try [`ImageReader`] for more advanced uses. /// /// [`load`]: fn.load.html -/// [`io::Reader`]: io/struct.Reader.html #[inline(always)] pub fn load_from_memory_with_format(buf: &[u8], format: ImageFormat) -> ImageResult { let b = io::Cursor::new(buf); diff --git a/src/io/free_functions.rs b/src/io/free_functions.rs index 504efe8017..5cbf8325b2 100644 --- a/src/io/free_functions.rs +++ b/src/io/free_functions.rs @@ -2,7 +2,7 @@ use std::fs::File; use std::io::{BufRead, BufWriter, Seek}; use std::path::Path; -use crate::{codecs::*, ExtendedColorType}; +use crate::{codecs::*, ExtendedColorType, ImageReader}; use crate::dynimage::DynamicImage; use crate::error::{ImageError, ImageFormatHint, ImageResult}; @@ -16,11 +16,9 @@ use crate::image::{ImageDecoder, ImageEncoder}; /// 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 +/// Try [`ImageReader`] for more advanced uses. pub fn load(r: R, format: ImageFormat) -> ImageResult { - let mut reader = crate::io::Reader::new(r); + let mut reader = ImageReader::new(r); reader.set_format(format); reader.decode() } diff --git a/src/io/reader.rs b/src/io/image_reader.rs similarity index 94% rename from src/io/reader.rs rename to src/io/image_reader.rs index aeb13811f3..594786bddb 100644 --- a/src/io/reader.rs +++ b/src/io/image_reader.rs @@ -21,9 +21,9 @@ use super::free_functions; /// /// ```no_run /// # use image::ImageError; -/// # use image::io::Reader; +/// # use image::ImageReader; /// # fn main() -> Result<(), ImageError> { -/// let image = Reader::open("path/to/image.png")? +/// let image = ImageReader::open("path/to/image.png")? /// .decode()?; /// # Ok(()) } /// ``` @@ -34,7 +34,7 @@ use super::free_functions; /// /// ``` /// # use image::ImageError; -/// # use image::io::Reader; +/// # use image::ImageReader; /// # fn main() -> Result<(), ImageError> { /// use std::io::Cursor; /// use image::ImageFormat; @@ -43,7 +43,7 @@ use super::free_functions; /// 0 1\n\ /// 1 0\n"; /// -/// let mut reader = Reader::new(Cursor::new(raw_data)) +/// let mut reader = ImageReader::new(Cursor::new(raw_data)) /// .with_guessed_format() /// .expect("Cursor io never fails"); /// assert_eq!(reader.format(), Some(ImageFormat::Pnm)); @@ -58,7 +58,7 @@ use super::free_functions; /// /// [`set_format`]: #method.set_format /// [`ImageDecoder`]: ../trait.ImageDecoder.html -pub struct Reader { +pub struct ImageReader { /// The reader. Should be buffered. inner: R, /// The format, if one has been set or deduced. @@ -67,7 +67,7 @@ pub struct Reader { limits: super::Limits, } -impl<'a, R: 'a + BufRead + Seek> Reader { +impl<'a, R: 'a + BufRead + Seek> ImageReader { /// Create a new image reader without a preset format. /// /// Assumes the reader is already buffered. For optimal performance, @@ -79,7 +79,7 @@ impl<'a, R: 'a + BufRead + Seek> Reader { /// [`with_guessed_format`]: #method.with_guessed_format /// [`set_format`]: method.set_format pub fn new(buffered_reader: R) -> Self { - Reader { + ImageReader { inner: buffered_reader, format: None, limits: super::Limits::default(), @@ -91,7 +91,7 @@ impl<'a, R: 'a + BufRead + Seek> Reader { /// 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 { + ImageReader { inner: buffered_reader, format: Some(format), limits: super::Limits::default(), @@ -208,15 +208,15 @@ impl<'a, R: 'a + BufRead + Seek> Reader { /// /// ## Usage /// - /// This supplements the path based type deduction from [`open`](Reader::open) with content based deduction. + /// This supplements the path based type deduction from [`ImageReader::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; + /// # use image::ImageReader; /// # fn main() -> Result<(), ImageError> { - /// let image = Reader::open("image.unknown")? + /// let image = ImageReader::open("image.unknown")? /// .with_guessed_format()? /// .decode()?; /// # Ok(()) } @@ -281,7 +281,7 @@ impl<'a, R: 'a + BufRead + Seek> Reader { } } -impl Reader> { +impl ImageReader> { /// Open a file to read, format will be guessed from path. /// /// This will not attempt any io operation on the opened file. @@ -298,7 +298,7 @@ impl Reader> { } fn open_impl(path: &Path) -> io::Result { - Ok(Reader { + Ok(ImageReader { inner: BufReader::new(File::open(path)?), format: ImageFormat::from_path(path).ok(), limits: super::Limits::default(), diff --git a/src/io/mod.rs b/src/io/mod.rs index 67db114dc0..21ab00d5b9 100644 --- a/src/io/mod.rs +++ b/src/io/mod.rs @@ -3,9 +3,9 @@ use crate::{error, ColorType, ImageError, ImageResult}; pub(crate) mod free_functions; -mod reader; +mod image_reader; -pub use self::reader::Reader; +pub use self::image_reader::ImageReader; /// Set of supported strict limits for a decoder. #[derive(Clone, Debug, Default, Eq, PartialEq, Hash)] diff --git a/src/lib.rs b/src/lib.rs index 45e09572ec..abb45ca0d4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,11 +13,11 @@ //! //! # High level API //! -//! Load images using [`io::Reader`]: +//! Load images using [`ImageReader`]: //! //! ```rust,no_run //! use std::io::Cursor; -//! use image::io::Reader as ImageReader; +//! use image::ImageReader; //! # fn main() -> Result<(), image::ImageError> { //! # let bytes = vec![0u8]; //! @@ -49,7 +49,7 @@ //! //! [`save`]: enum.DynamicImage.html#method.save //! [`write_to`]: enum.DynamicImage.html#method.write_to -//! [`io::Reader`]: io/struct.Reader.html +//! [`ImageReader`]: struct.Reader.html //! //! # Image buffers //! @@ -167,6 +167,7 @@ pub use crate::dynimage::{ save_buffer_with_format, write_buffer_with_format, }; pub use crate::io::free_functions::{guess_format, load}; +pub use crate::io::{ImageReader, LimitSupport, Limits}; pub use crate::dynimage::DynamicImage; @@ -193,9 +194,6 @@ pub mod math; // Image processing functions pub mod imageops; -// Io bindings -pub mod io; - // Buffer representations for ffi. pub mod flat; @@ -290,6 +288,7 @@ mod buffer_par; mod color; mod dynimage; mod image; +mod io; mod traits; mod utils; diff --git a/tests/limits.rs b/tests/limits.rs index 7380deb5c6..f858a34ca4 100644 --- a/tests/limits.rs +++ b/tests/limits.rs @@ -7,7 +7,7 @@ //! There are several such buggy APIs in the crate. The tests for them are written but commented out. //! Pull requests fixing these APIs are very welcome. //! -//! It is possible that a maliciously crafted file coud bypass these checks +//! It is possible that a maliciously crafted file could bypass these checks //! and cause a large allocation inside the decoder despite these limits. //! These tests cannot catch that, but fuzzing can. //! @@ -15,7 +15,9 @@ use std::io::Cursor; -use image::{io::Limits, load_from_memory_with_format, ImageDecoder, ImageFormat, RgbImage}; +use image::{ + load_from_memory_with_format, ImageDecoder, ImageFormat, ImageReader, Limits, RgbImage, +}; const WIDTH: u32 = 256; const HEIGHT: u32 = 256; @@ -58,7 +60,7 @@ fn load_through_reader( format: ImageFormat, limits: Limits, ) -> Result { - let mut reader = image::io::Reader::new(Cursor::new(input)); + let mut reader = ImageReader::new(Cursor::new(input)); reader.set_format(format); reader.limits(limits); reader.decode() @@ -74,7 +76,7 @@ fn gif() { assert!(load_from_memory_with_format(&image, ImageFormat::Gif).is_ok()); // check that the limits implementation is not overly restrictive assert!(load_through_reader(&image, ImageFormat::Gif, permissive_limits()).is_ok()); - // image::io::Reader + // image::ImageReader assert!(load_through_reader(&image, ImageFormat::Gif, width_height_limits()).is_err()); assert!(load_through_reader(&image, ImageFormat::Gif, allocation_limits()).is_err()); // BROKEN! @@ -104,7 +106,7 @@ fn png() { assert!(load_from_memory_with_format(&image, ImageFormat::Png).is_ok()); // check that the limits implementation is not overly restrictive assert!(load_through_reader(&image, ImageFormat::Png, permissive_limits()).is_ok()); - // image::io::Reader + // image::ImageReader assert!(load_through_reader(&image, ImageFormat::Png, width_height_limits()).is_err()); assert!(load_through_reader(&image, ImageFormat::Png, allocation_limits()).is_err()); @@ -131,7 +133,7 @@ fn jpeg() { assert!(load_from_memory_with_format(&image, ImageFormat::Jpeg).is_ok()); // check that the limits implementation is not overly restrictive assert!(load_through_reader(&image, ImageFormat::Jpeg, permissive_limits()).is_ok()); - // image::io::Reader + // image::ImageReader assert!(load_through_reader(&image, ImageFormat::Jpeg, width_height_limits()).is_err()); assert!(load_through_reader(&image, ImageFormat::Jpeg, allocation_limits()).is_err()); @@ -151,7 +153,7 @@ fn webp() { assert!(load_from_memory_with_format(&image, ImageFormat::WebP).is_ok()); // check that the limits implementation is not overly restrictive assert!(load_through_reader(&image, ImageFormat::WebP, permissive_limits()).is_ok()); - // image::io::Reader + // image::ImageReader assert!(load_through_reader(&image, ImageFormat::WebP, width_height_limits()).is_err()); assert!(load_through_reader(&image, ImageFormat::WebP, allocation_limits()).is_err()); @@ -178,7 +180,7 @@ fn tiff() { tiff_permissive_limits.max_alloc = Some((WIDTH * HEIGHT * 10).into()); // `* 9` would be exactly three output buffers, `* 10`` has some slack space load_through_reader(&image, ImageFormat::Tiff, tiff_permissive_limits).unwrap(); - // image::io::Reader + // image::ImageReader assert!(load_through_reader(&image, ImageFormat::Tiff, width_height_limits()).is_err()); assert!(load_through_reader(&image, ImageFormat::Tiff, allocation_limits()).is_err()); @@ -198,7 +200,7 @@ fn avif() { assert!(load_from_memory_with_format(&image, ImageFormat::Avif).is_ok()); // check that the limits implementation is not overly restrictive assert!(load_through_reader(&image, ImageFormat::Avif, permissive_limits()).is_ok()); - // image::io::Reader + // image::ImageReader assert!(load_through_reader(&image, ImageFormat::Avif, width_height_limits()).is_err()); assert!(load_through_reader(&image, ImageFormat::Avif, allocation_limits()).is_err()); @@ -218,7 +220,7 @@ fn bmp() { assert!(load_from_memory_with_format(&image, ImageFormat::Bmp).is_ok()); // check that the limits implementation is not overly restrictive assert!(load_through_reader(&image, ImageFormat::Bmp, permissive_limits()).is_ok()); - // image::io::Reader + // image::ImageReader assert!(load_through_reader(&image, ImageFormat::Bmp, width_height_limits()).is_err()); assert!(load_through_reader(&image, ImageFormat::Bmp, allocation_limits()).is_err()); diff --git a/tests/limits_anim.rs b/tests/limits_anim.rs index d332f81b5c..c0983e8c46 100644 --- a/tests/limits_anim.rs +++ b/tests/limits_anim.rs @@ -1,6 +1,6 @@ //! Test enforcement of size and memory limits for animation decoding APIs. -use image::{io::Limits, AnimationDecoder, ImageDecoder, ImageResult}; +use image::{AnimationDecoder, ImageDecoder, ImageResult, Limits}; #[cfg(feature = "gif")] use image::codecs::gif::GifDecoder; diff --git a/tests/reference_images.rs b/tests/reference_images.rs index e695d1844a..02ef47d1d5 100644 --- a/tests/reference_images.rs +++ b/tests/reference_images.rs @@ -5,6 +5,7 @@ use std::path::PathBuf; use crc32fast::Hasher as Crc32; use image::DynamicImage; +use image::ImageReader; const BASE_PATH: [&str; 2] = [".", "tests"]; const IMAGE_DIR: &str = "images"; @@ -185,7 +186,7 @@ fn check_references() { match case.kind { ReferenceTestKind::AnimatedFrame { frame: frame_num } => { - let format = image::io::Reader::open(&img_path) + let format = ImageReader::open(&img_path) .unwrap() .with_guessed_format() .unwrap()