Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rename Reader to ImageReader #2243

Merged
merged 4 commits into from
May 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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()?;
Expand Down
2 changes: 1 addition & 1 deletion fuzz/fuzzers/fuzzer_script_exr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
20 changes: 7 additions & 13 deletions src/dynimage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -1097,29 +1098,25 @@ fn decoder_to_image<I: ImageDecoder>(decoder: I) -> ImageResult<DynamicImage> {
/// 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<P>(path: P) -> ImageResult<DynamicImage>
where
P: AsRef<Path>,
{
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<P>(path: P) -> ImageResult<(u32, u32)>
where
P: AsRef<Path>,
{
crate::io::Reader::open(path)?.into_dimensions()
ImageReader::open(path)?.into_dimensions()
}

/// Saves the supplied buffer to a file at the path specified.
Expand Down Expand Up @@ -1191,9 +1188,7 @@ pub fn write_buffer_with_format<W: Write + Seek>(
/// 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<DynamicImage> {
let format = free_functions::guess_format(buffer)?;
load_from_memory_with_format(buffer, format)
Expand All @@ -1204,10 +1199,9 @@ pub fn load_from_memory(buffer: &[u8]) -> ImageResult<DynamicImage> {
/// 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<DynamicImage> {
let b = io::Cursor::new(buf);
Expand Down
8 changes: 3 additions & 5 deletions src/io/free_functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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: BufRead + Seek>(r: R, format: ImageFormat) -> ImageResult<DynamicImage> {
let mut reader = crate::io::Reader::new(r);
let mut reader = ImageReader::new(r);
reader.set_format(format);
reader.decode()
}
Expand Down
26 changes: 13 additions & 13 deletions src/io/reader.rs → src/io/image_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(()) }
/// ```
Expand All @@ -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;
Expand All @@ -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));
Expand All @@ -58,7 +58,7 @@ use super::free_functions;
///
/// [`set_format`]: #method.set_format
/// [`ImageDecoder`]: ../trait.ImageDecoder.html
pub struct Reader<R: Read + Seek> {
pub struct ImageReader<R: Read + Seek> {
/// The reader. Should be buffered.
inner: R,
/// The format, if one has been set or deduced.
Expand All @@ -67,7 +67,7 @@ pub struct Reader<R: Read + Seek> {
limits: super::Limits,
}

impl<'a, R: 'a + BufRead + Seek> Reader<R> {
impl<'a, R: 'a + BufRead + Seek> ImageReader<R> {
/// Create a new image reader without a preset format.
///
/// Assumes the reader is already buffered. For optimal performance,
Expand All @@ -79,7 +79,7 @@ impl<'a, R: 'a + BufRead + Seek> Reader<R> {
/// [`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(),
Expand All @@ -91,7 +91,7 @@ impl<'a, R: 'a + BufRead + Seek> Reader<R> {
/// 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(),
Expand Down Expand Up @@ -208,15 +208,15 @@ impl<'a, R: 'a + BufRead + Seek> Reader<R> {
///
/// ## 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(()) }
Expand Down Expand Up @@ -281,7 +281,7 @@ impl<'a, R: 'a + BufRead + Seek> Reader<R> {
}
}

impl Reader<BufReader<File>> {
impl ImageReader<BufReader<File>> {
/// Open a file to read, format will be guessed from path.
///
/// This will not attempt any io operation on the opened file.
Expand All @@ -298,7 +298,7 @@ impl Reader<BufReader<File>> {
}

fn open_impl(path: &Path) -> io::Result<Self> {
Ok(Reader {
Ok(ImageReader {
inner: BufReader::new(File::open(path)?),
format: ImageFormat::from_path(path).ok(),
limits: super::Limits::default(),
Expand Down
4 changes: 2 additions & 2 deletions src/io/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
11 changes: 5 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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];
//!
Expand Down Expand Up @@ -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
//!
Expand Down Expand Up @@ -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;

Expand All @@ -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;

Expand Down Expand Up @@ -290,6 +288,7 @@ mod buffer_par;
mod color;
mod dynimage;
mod image;
mod io;
mod traits;
mod utils;

Expand Down
22 changes: 12 additions & 10 deletions tests/limits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,17 @@
//! 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.
//!
//! These tests also don't cover animation (yet). Adding tests for that would be very welcome too.

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;
Expand Down Expand Up @@ -58,7 +60,7 @@ fn load_through_reader(
format: ImageFormat,
limits: Limits,
) -> Result<image::DynamicImage, image::ImageError> {
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()
Expand All @@ -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!

Expand Down Expand Up @@ -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());

Expand All @@ -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());

Expand All @@ -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());

Expand All @@ -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());

Expand All @@ -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());

Expand All @@ -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());

Expand Down
2 changes: 1 addition & 1 deletion tests/limits_anim.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
3 changes: 2 additions & 1 deletion tests/reference_images.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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()
Expand Down
Loading