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

Add BufRead + Seek bound on many decoders #2149

Merged
merged 2 commits into from
Feb 19, 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
15 changes: 8 additions & 7 deletions fuzz/fuzzers/fuzzer_script_exr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,13 @@ use image::ExtendedColorType;
use image::ImageDecoder;
use image::ImageEncoder;
use image::ImageResult;
use std::convert::TryFrom;
use std::io::Cursor;
use std::io::Read;
use std::io::Seek;
use std::io::Write;
use std::io::{BufRead, Cursor, Seek, Write};

// "just dont panic"
fn roundtrip(bytes: &[u8]) -> ImageResult<()> {
/// Read the file from the specified path into an `Rgba32FImage`.
// TODO this method should probably already exist in the main image crate
fn read_as_rgba_byte_image(read: impl Read + Seek) -> ImageResult<(u32, u32, Vec<u8>)> {
fn read_as_rgba_byte_image(read: impl BufRead + Seek) -> ImageResult<(u32, u32, Vec<u8>)> {
let mut decoder = OpenExrDecoder::with_alpha_preference(read, Some(true))?;
match usize::try_from(decoder.total_bytes()) {
Ok(decoded_size) if decoded_size <= 256 * 1024 * 1024 => {
Expand All @@ -45,7 +41,12 @@ fn roundtrip(bytes: &[u8]) -> ImageResult<()> {
write: impl Write + Seek,
(width, height, data): &(u32, u32, Vec<u8>),
) -> ImageResult<()> {
OpenExrEncoder::new(write).write_image(data.as_slice(), *width, *height, ExtendedColorType::Rgba32F)
OpenExrEncoder::new(write).write_image(
data.as_slice(),
*width,
*height,
ExtendedColorType::Rgba32F,
)
}

let decoded_image = read_as_rgba_byte_image(Cursor::new(bytes))?;
Expand Down
13 changes: 7 additions & 6 deletions src/codecs/bmp/decoder.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::cmp::{self, Ordering};
use std::io::{self, Read, Seek, SeekFrom};
use std::io::{self, BufRead, Seek, SeekFrom};
use std::iter::{repeat, Rev};
use std::slice::ChunksMut;
use std::{error, fmt};
Expand Down Expand Up @@ -502,7 +502,7 @@ enum RLEInsn {
PixelRun(u8, u8),
}

impl<R: Read + Seek> BmpDecoder<R> {
impl<R: BufRead + Seek> BmpDecoder<R> {
fn new_decoder(reader: R) -> BmpDecoder<R> {
BmpDecoder {
reader,
Expand Down Expand Up @@ -1329,7 +1329,7 @@ impl<R: Read + Seek> BmpDecoder<R> {
}
}

impl<R: Read + Seek> ImageDecoder for BmpDecoder<R> {
impl<R: BufRead + Seek> ImageDecoder for BmpDecoder<R> {
fn dimensions(&self) -> (u32, u32) {
(self.width as u32, self.height as u32)
}
Expand All @@ -1354,7 +1354,7 @@ impl<R: Read + Seek> ImageDecoder for BmpDecoder<R> {
}
}

impl<R: Read + Seek> ImageDecoderRect for BmpDecoder<R> {
impl<R: BufRead + Seek> ImageDecoderRect for BmpDecoder<R> {
fn read_rect(
&mut self,
x: u32,
Expand Down Expand Up @@ -1384,7 +1384,7 @@ impl<R: Read + Seek> ImageDecoderRect for BmpDecoder<R> {

#[cfg(test)]
mod test {
use std::io::Cursor;
use std::io::{BufReader, Cursor};

use super::*;

Expand All @@ -1405,7 +1405,8 @@ mod test {

#[test]
fn read_rect() {
let f = std::fs::File::open("tests/images/bmp/images/Core_8_Bit.bmp").unwrap();
let f =
BufReader::new(std::fs::File::open("tests/images/bmp/images/Core_8_Bit.bmp").unwrap());
let mut decoder = super::BmpDecoder::new(f).unwrap();

let mut buf: Vec<u8> = vec![0; 8 * 8 * 3];
Expand Down
11 changes: 6 additions & 5 deletions src/codecs/gif.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@
//! use image::codecs::gif::{GifDecoder, GifEncoder};
//! use image::{ImageDecoder, AnimationDecoder};
//! use std::fs::File;
//! use std::io::BufReader;
//! # fn main() -> std::io::Result<()> {
//! // Decode a gif into frames
//! let file_in = File::open("foo.gif")?;
//! let file_in = BufReader::new(File::open("foo.gif")?);
//! let mut decoder = GifDecoder::new(file_in).unwrap();
//! let frames = decoder.into_frames();
//! let frames = frames.collect_frames().expect("error decoding gif");
Expand All @@ -26,7 +27,7 @@
//! ```
#![allow(clippy::while_let_loop)]

use std::io::{self, Cursor, Read, Write};
use std::io::{self, BufRead, Cursor, Read, Seek, Write};
use std::marker::PhantomData;
use std::mem;

Expand Down Expand Up @@ -82,7 +83,7 @@ impl<R> Read for GifReader<R> {
}
}

impl<R: Read> ImageDecoder for GifDecoder<R> {
impl<R: BufRead + Seek> ImageDecoder for GifDecoder<R> {
fn dimensions(&self) -> (u32, u32) {
(
u32::from(self.reader.width()),
Expand Down Expand Up @@ -226,7 +227,7 @@ struct GifFrameIterator<R: Read> {
limits: Limits,
}

impl<R: Read> GifFrameIterator<R> {
impl<R: BufRead + Seek> GifFrameIterator<R> {
fn new(decoder: GifDecoder<R>) -> GifFrameIterator<R> {
let (width, height) = decoder.dimensions();
let limits = decoder.limits.clone();
Expand Down Expand Up @@ -392,7 +393,7 @@ impl<R: Read> Iterator for GifFrameIterator<R> {
}
}

impl<'a, R: Read + 'a> AnimationDecoder<'a> for GifDecoder<R> {
impl<'a, R: BufRead + Seek + 'a> AnimationDecoder<'a> for GifDecoder<R> {
fn into_frames(self) -> animation::Frames<'a> {
animation::Frames::new(Box::new(GifFrameIterator::new(self)))
}
Expand Down
12 changes: 6 additions & 6 deletions src/codecs/ico/decoder.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use byteorder::{LittleEndian, ReadBytesExt};
use std::io::{Read, Seek, SeekFrom};
use std::io::{BufRead, Read, Seek, SeekFrom};
use std::{error, fmt};

use crate::color::ColorType;
Expand Down Expand Up @@ -106,12 +106,12 @@ impl From<IcoEntryImageFormat> for ImageFormat {
}

/// An ico decoder
pub struct IcoDecoder<R: Read> {
pub struct IcoDecoder<R: BufRead + Seek> {
selected_entry: DirEntry,
inner_decoder: InnerDecoder<R>,
}

enum InnerDecoder<R: Read> {
enum InnerDecoder<R: BufRead + Seek> {
Bmp(BmpDecoder<R>),
Png(Box<PngDecoder<R>>),
}
Expand Down Expand Up @@ -141,7 +141,7 @@ struct DirEntry {
image_offset: u32,
}

impl<R: Read + Seek> IcoDecoder<R> {
impl<R: BufRead + Seek> IcoDecoder<R> {
/// Create a new decoder that decodes from the stream ```r```
pub fn new(mut r: R) -> ImageResult<IcoDecoder<R>> {
let entries = read_entries(&mut r)?;
Expand Down Expand Up @@ -248,7 +248,7 @@ impl DirEntry {
Ok(signature == PNG_SIGNATURE)
}

fn decoder<R: Read + Seek>(&self, mut r: R) -> ImageResult<InnerDecoder<R>> {
fn decoder<R: BufRead + Seek>(&self, mut r: R) -> ImageResult<InnerDecoder<R>> {
let is_png = self.is_png(&mut r)?;
self.seek_to_start(&mut r)?;

Expand All @@ -260,7 +260,7 @@ impl DirEntry {
}
}

impl<R: Read + Seek> ImageDecoder for IcoDecoder<R> {
impl<R: BufRead + Seek> ImageDecoder for IcoDecoder<R> {
fn dimensions(&self) -> (u32, u32) {
match self.inner_decoder {
Bmp(ref decoder) => decoder.dimensions(),
Expand Down
6 changes: 3 additions & 3 deletions src/codecs/jpeg/decoder.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::io::Read;
use std::io::{BufRead, Seek};
use std::marker::PhantomData;

use crate::color::ColorType;
Expand All @@ -22,7 +22,7 @@ pub struct JpegDecoder<R> {
phantom: PhantomData<R>,
}

impl<R: Read> JpegDecoder<R> {
impl<R: BufRead + Seek> JpegDecoder<R> {
/// Create a new decoder that decodes from the stream ```r```
pub fn new(r: R) -> ImageResult<JpegDecoder<R>> {
let mut input = Vec::new();
Expand Down Expand Up @@ -50,7 +50,7 @@ impl<R: Read> JpegDecoder<R> {
}
}

impl<R: Read> ImageDecoder for JpegDecoder<R> {
impl<R: BufRead + Seek> ImageDecoder for JpegDecoder<R> {
fn dimensions(&self) -> (u32, u32) {
(u32::from(self.width), u32::from(self.height))
}
Expand Down
10 changes: 5 additions & 5 deletions src/codecs/openexr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use crate::{
ColorType, ExtendedColorType, ImageDecoder, ImageEncoder, ImageError, ImageFormat, ImageResult,
};

use std::io::{Read, Seek, Write};
use std::io::{BufRead, Seek, Write};

/// An OpenEXR decoder. Immediately reads the meta data from the file.
#[derive(Debug)]
Expand All @@ -45,7 +45,7 @@ pub struct OpenExrDecoder<R> {
alpha_present_in_file: bool,
}

impl<R: Read + Seek> OpenExrDecoder<R> {
impl<R: BufRead + Seek> OpenExrDecoder<R> {
/// Create a decoder. Consumes the first few bytes of the source to extract image dimensions.
/// Assumes the reader is buffered. In most cases,
/// you should wrap your reader in a `BufReader` for best performance.
Expand Down Expand Up @@ -104,7 +104,7 @@ impl<R: Read + Seek> OpenExrDecoder<R> {
}
}

impl<R: Read + Seek> ImageDecoder for OpenExrDecoder<R> {
impl<R: BufRead + Seek> ImageDecoder for OpenExrDecoder<R> {
fn dimensions(&self) -> (u32, u32) {
let size = self
.selected_exr_header()
Expand Down Expand Up @@ -382,7 +382,7 @@ mod test {
}

/// Read the file from the specified path into an `Rgb32FImage`.
fn read_as_rgb_image(read: impl Read + Seek) -> ImageResult<Rgb32FImage> {
fn read_as_rgb_image(read: impl BufRead + Seek) -> ImageResult<Rgb32FImage> {
let decoder = OpenExrDecoder::with_alpha_preference(read, Some(false))?;
let (width, height) = decoder.dimensions();
let buffer: Vec<f32> = crate::image::decoder_to_vec(decoder)?;
Expand All @@ -396,7 +396,7 @@ mod test {
}

/// Read the file from the specified path into an `Rgba32FImage`.
fn read_as_rgba_image(read: impl Read + Seek) -> ImageResult<Rgba32FImage> {
fn read_as_rgba_image(read: impl BufRead + Seek) -> ImageResult<Rgba32FImage> {
let decoder = OpenExrDecoder::with_alpha_preference(read, Some(true))?;
let (width, height) = decoder.dimensions();
let buffer: Vec<f32> = crate::image::decoder_to_vec(decoder)?;
Expand Down
26 changes: 13 additions & 13 deletions src/codecs/png.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
//!

use std::fmt;
use std::io::{Read, Write};
use std::io::{BufRead, Seek, Write};

use png::{BlendOp, DisposeOp};

Expand All @@ -26,13 +26,13 @@ use crate::{DynamicImage, GenericImage, ImageBuffer, Luma, LumaA, Rgb, Rgba, Rgb
pub(crate) const PNG_SIGNATURE: [u8; 8] = [137, 80, 78, 71, 13, 10, 26, 10];

/// PNG decoder
pub struct PngDecoder<R: Read> {
pub struct PngDecoder<R: BufRead + Seek> {
color_type: ColorType,
reader: png::Reader<R>,
limits: Limits,
}

impl<R: Read> PngDecoder<R> {
impl<R: BufRead + Seek> PngDecoder<R> {
/// Creates a new decoder that decodes from the stream ```r```
pub fn new(r: R) -> ImageResult<PngDecoder<R>> {
Self::with_limits(r, Limits::no_limits())
Expand Down Expand Up @@ -164,7 +164,7 @@ fn unsupported_color(ect: ExtendedColorType) -> ImageError {
))
}

impl<R: Read> ImageDecoder for PngDecoder<R> {
impl<R: BufRead + Seek> ImageDecoder for PngDecoder<R> {
fn dimensions(&self) -> (u32, u32) {
self.reader.info().size()
}
Expand Down Expand Up @@ -221,7 +221,7 @@ impl<R: Read> ImageDecoder for PngDecoder<R> {
/// [`AnimationDecoder`]: ../trait.AnimationDecoder.html
/// [`PngDecoder`]: struct.PngDecoder.html
/// [`PngDecoder::apng`]: struct.PngDecoder.html#method.apng
pub struct ApngDecoder<R: Read> {
pub struct ApngDecoder<R: BufRead + Seek> {
inner: PngDecoder<R>,
/// The current output buffer.
current: Option<RgbaImage>,
Expand All @@ -235,7 +235,7 @@ pub struct ApngDecoder<R: Read> {
has_thumbnail: bool,
}

impl<R: Read> ApngDecoder<R> {
impl<R: BufRead + Seek> ApngDecoder<R> {
fn new(inner: PngDecoder<R>) -> Self {
let info = inner.reader.info();
let remaining = match info.animation_control() {
Expand Down Expand Up @@ -419,11 +419,11 @@ impl<R: Read> ApngDecoder<R> {
}
}

impl<'a, R: Read + 'a> AnimationDecoder<'a> for ApngDecoder<R> {
impl<'a, R: BufRead + Seek + 'a> AnimationDecoder<'a> for ApngDecoder<R> {
fn into_frames(self) -> Frames<'a> {
struct FrameIterator<R: Read>(ApngDecoder<R>);
struct FrameIterator<R: BufRead + Seek>(ApngDecoder<R>);

impl<R: Read> Iterator for FrameIterator<R> {
impl<R: BufRead + Seek> Iterator for FrameIterator<R> {
type Item = ImageResult<Frame>;

fn next(&mut self) -> Option<Self::Item> {
Expand Down Expand Up @@ -685,14 +685,14 @@ impl std::error::Error for BadPngRepresentation {}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Cursor;
use std::io::{BufReader, Cursor, Read};

#[test]
fn ensure_no_decoder_off_by_one() {
let dec = PngDecoder::new(
let dec = PngDecoder::new(BufReader::new(
std::fs::File::open("tests/images/png/bugfixes/debug_triangle_corners_widescreen.png")
.unwrap(),
)
))
.expect("Unable to read PNG file (does it exist?)");

assert_eq![(2000, 1000), dec.dimensions()];
Expand Down Expand Up @@ -721,7 +721,7 @@ mod tests {
.unwrap();
not_png[0] = 0;

let error = PngDecoder::new(&not_png[..]).err().unwrap();
let error = PngDecoder::new(Cursor::new(&not_png)).err().unwrap();
let _ = error
.source()
.unwrap()
Expand Down
8 changes: 4 additions & 4 deletions src/codecs/tga/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
image::{ImageDecoder, ImageFormat},
};
use byteorder::ReadBytesExt;
use std::io::{self, Read, Seek};
use std::io::{self, Read};

struct ColorMap {
/// sizes in bytes
Expand Down Expand Up @@ -59,7 +59,7 @@ pub struct TgaDecoder<R> {
color_map: Option<ColorMap>,
}

impl<R: Read + Seek> TgaDecoder<R> {
impl<R: Read> TgaDecoder<R> {
/// Create a new decoder that decodes from the stream `r`
pub fn new(r: R) -> ImageResult<TgaDecoder<R>> {
let mut decoder = TgaDecoder {
Expand Down Expand Up @@ -172,7 +172,7 @@ impl<R: Read + Seek> TgaDecoder<R> {
/// is present
fn read_image_id(&mut self) -> ImageResult<()> {
self.r
.seek(io::SeekFrom::Current(i64::from(self.header.id_length)))?;
.read_exact(&mut vec![0; self.header.id_length as usize])?;
Ok(())
}

Expand Down Expand Up @@ -336,7 +336,7 @@ impl<R: Read + Seek> TgaDecoder<R> {
}
}

impl<R: Read + Seek> ImageDecoder for TgaDecoder<R> {
impl<R: Read> ImageDecoder for TgaDecoder<R> {
fn dimensions(&self) -> (u32, u32) {
(self.width as u32, self.height as u32)
}
Expand Down
Loading
Loading