Skip to content

Commit 83e6dac

Browse files
committed
make jpeg strict mode configurable
1 parent 22ea722 commit 83e6dac

File tree

2 files changed

+41
-8
lines changed

2 files changed

+41
-8
lines changed

src/codecs/jpeg/decoder.rs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ type ZuneColorSpace = zune_core::colorspace::ColorSpace;
1616
pub struct JpegDecoder<R> {
1717
input: Vec<u8>,
1818
orig_color_space: ZuneColorSpace,
19+
strict_mode: bool,
1920
width: u16,
2021
height: u16,
2122
limits: Limits,
@@ -65,13 +66,21 @@ impl<R: BufRead + Seek> JpegDecoder<R> {
6566
Ok(JpegDecoder {
6667
input,
6768
orig_color_space,
69+
strict_mode: false,
6870
width,
6971
height,
7072
limits,
7173
orientation: None,
7274
phantom: PhantomData,
7375
})
7476
}
77+
78+
/// Set whether the decoder should be in standards conforming/strict mode.
79+
/// Off by default to ensure maximum compatibility. For details, see
80+
/// [zune_core::options::DecoderOptions::set_strict_mode].
81+
pub fn set_strict_mode(&mut self, strict_mode: bool) {
82+
self.strict_mode = strict_mode;
83+
}
7584
}
7685

7786
impl<R: BufRead + Seek> ImageDecoder for JpegDecoder<R> {
@@ -85,7 +94,7 @@ impl<R: BufRead + Seek> ImageDecoder for JpegDecoder<R> {
8594

8695
fn icc_profile(&mut self) -> ImageResult<Option<Vec<u8>>> {
8796
let options = zune_core::options::DecoderOptions::default()
88-
.set_strict_mode(false)
97+
.set_strict_mode(self.strict_mode)
8998
.set_max_width(usize::MAX)
9099
.set_max_height(usize::MAX);
91100
let mut decoder =
@@ -96,7 +105,7 @@ impl<R: BufRead + Seek> ImageDecoder for JpegDecoder<R> {
96105

97106
fn exif_metadata(&mut self) -> ImageResult<Option<Vec<u8>>> {
98107
let options = zune_core::options::DecoderOptions::default()
99-
.set_strict_mode(false)
108+
.set_strict_mode(self.strict_mode)
100109
.set_max_width(usize::MAX)
101110
.set_max_height(usize::MAX);
102111
let mut decoder =
@@ -115,7 +124,7 @@ impl<R: BufRead + Seek> ImageDecoder for JpegDecoder<R> {
115124

116125
fn xmp_metadata(&mut self) -> ImageResult<Option<Vec<u8>>> {
117126
let options = zune_core::options::DecoderOptions::default()
118-
.set_strict_mode(false)
127+
.set_strict_mode(self.strict_mode)
119128
.set_max_width(usize::MAX)
120129
.set_max_height(usize::MAX);
121130
let mut decoder =
@@ -127,7 +136,7 @@ impl<R: BufRead + Seek> ImageDecoder for JpegDecoder<R> {
127136

128137
fn iptc_metadata(&mut self) -> ImageResult<Option<Vec<u8>>> {
129138
let options = zune_core::options::DecoderOptions::default()
130-
.set_strict_mode(false)
139+
.set_strict_mode(self.strict_mode)
131140
.set_max_width(usize::MAX)
132141
.set_max_height(usize::MAX);
133142
let mut decoder =
@@ -160,7 +169,12 @@ impl<R: BufRead + Seek> ImageDecoder for JpegDecoder<R> {
160169
)));
161170
}
162171

163-
let mut decoder = new_zune_decoder(&self.input, self.orig_color_space, self.limits);
172+
let mut decoder = new_zune_decoder(
173+
&self.input,
174+
self.orig_color_space,
175+
self.strict_mode,
176+
self.limits,
177+
);
164178
decoder.decode_into(buf).map_err(ImageError::from_jpeg)?;
165179
Ok(())
166180
}
@@ -207,12 +221,13 @@ fn to_supported_color_space(orig: ZuneColorSpace) -> ZuneColorSpace {
207221
fn new_zune_decoder(
208222
input: &[u8],
209223
orig_color_space: ZuneColorSpace,
224+
strict_mode: bool,
210225
limits: Limits,
211226
) -> zune_jpeg::JpegDecoder<ZCursor<&[u8]>> {
212227
let target_color_space = to_supported_color_space(orig_color_space);
213228
let mut options = zune_core::options::DecoderOptions::default()
214229
.jpeg_set_out_colorspace(target_color_space)
215-
.set_strict_mode(false);
230+
.set_strict_mode(strict_mode);
216231
options = options.set_max_width(match limits.max_image_width {
217232
Some(max_width) => max_width as usize, // u32 to usize never truncates
218233
None => usize::MAX,

tests/save_jpeg.rs renamed to tests/jpeg.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22
#![cfg(all(feature = "jpeg", feature = "tiff"))]
33
extern crate image;
44

5-
use image::codecs::jpeg::JpegEncoder;
5+
use image::codecs::jpeg::{JpegDecoder, JpegEncoder};
6+
use image::ImageDecoder;
7+
use std::fs;
8+
use std::io::Cursor;
69

710
#[test]
8-
fn jqeg_qualitys() {
11+
fn save_qualities() {
912
let img = image::open("tests/images/tiff/testsuite/mandrill.tiff").unwrap();
1013

1114
let mut default = vec![];
@@ -27,3 +30,18 @@ fn jqeg_qualitys() {
2730

2831
assert!(large.len() > default.len());
2932
}
33+
34+
#[test]
35+
fn strict_mode() {
36+
let mut image = fs::read("tests/images/jpg/progressive/cat.jpg").unwrap();
37+
image.truncate(image.len() - 1000); // simulate a truncated image.
38+
39+
let mut decoder = JpegDecoder::new(Cursor::new(&image)).unwrap();
40+
let mut buffer = vec![0; decoder.total_bytes() as usize];
41+
decoder.set_strict_mode(false);
42+
assert!(decoder.read_image(&mut buffer).is_ok());
43+
44+
let mut decoder = JpegDecoder::new(Cursor::new(&image)).unwrap();
45+
decoder.set_strict_mode(true);
46+
assert!(!decoder.read_image(&mut buffer).is_ok());
47+
}

0 commit comments

Comments
 (0)