Skip to content

Commit 017fa55

Browse files
authored
Merge pull request #3 from vstroebel/sequential_subsampling
Fix chroma subsampling in sequential encoding
2 parents fb9b6a9 + d57b157 commit 017fa55

File tree

5 files changed

+68
-5
lines changed

5 files changed

+68
-5
lines changed

fuzz/Cargo.toml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,15 @@ name = "encode_rgb_custom_q_table"
4141
path = "fuzz_targets/encode_rgb_custom_q_table.rs"
4242
test = false
4343
doc = false
44+
45+
[[bin]]
46+
name = "encode_rgb_subsampled"
47+
path = "fuzz_targets/encode_rgb_subsampled.rs"
48+
test = false
49+
doc = false
50+
51+
[[bin]]
52+
name = "encode_rgb_progressive"
53+
path = "fuzz_targets/encode_rgb_progressive.rs"
54+
test = false
55+
doc = false
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#![no_main]
2+
3+
use libfuzzer_sys::fuzz_target;
4+
5+
use jpeg_encoder::*;
6+
7+
fuzz_target!(|data: &[u8]| {
8+
9+
let pixels = data.len() / 3;
10+
11+
let width = (pixels as f64).sqrt() as u16;
12+
let height = width;
13+
14+
if width >0 && width < u16::MAX && height >0 && height < u16::MAX {
15+
let mut out = Vec::new();
16+
let mut encoder = Encoder::new(&mut out, 80);
17+
encoder.set_sampling_factor(SamplingFactor::F_2_2);
18+
encoder.set_progressive(true);
19+
encoder.encode(data, width as u16, height as u16, ColorType::Rgb).unwrap();
20+
}
21+
});
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#![no_main]
2+
3+
use libfuzzer_sys::fuzz_target;
4+
5+
use jpeg_encoder::*;
6+
7+
fuzz_target!(|data: &[u8]| {
8+
9+
let pixels = data.len() / 3;
10+
11+
let width = (pixels as f64).sqrt() as u16;
12+
let height = width;
13+
14+
if width >0 && width < u16::MAX && height >0 && height < u16::MAX {
15+
let mut out = Vec::new();
16+
let mut encoder = Encoder::new(&mut out, 80);
17+
encoder.set_sampling_factor(SamplingFactor::F_4_2);
18+
encoder.encode(data, width as u16, height as u16, ColorType::Rgb).unwrap();
19+
}
20+
});

src/encoder.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -969,14 +969,20 @@ impl<W: JfifWrite> Encoder<W> {
969969
}
970970
}
971971

972+
let num_cols = ceil_div(usize::from(width), 8);
973+
let num_rows = ceil_div(usize::from(height), 8);
974+
975+
debug_assert!(num_cols > 0);
976+
debug_assert!(num_rows > 0);
977+
972978
let mut blocks: [Vec<_>; 4] = self.init_block_buffers(buffer_size / 64);
973979

974980
for (i, component) in self.components.iter().enumerate() {
975981
let h_scale = max_h_sampling as usize / component.horizontal_sampling_factor as usize;
976982
let v_scale = max_v_sampling as usize / component.vertical_sampling_factor as usize;
977983

978-
let cols = num_cols as usize / h_scale;
979-
let rows = num_rows as usize / v_scale;
984+
let cols = ceil_div(num_cols as usize , h_scale);
985+
let rows = ceil_div(num_rows as usize , v_scale);
980986

981987
debug_assert!(cols > 0);
982988
debug_assert!(rows > 0);

src/lib.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,15 @@ mod tests {
5959
use alloc::vec::Vec;
6060

6161
fn create_test_img_rgb() -> (Vec<u8>, u16, u16) {
62-
let width = 255;
62+
// Ensure size which which ensures an odd MCU count per row to test chroma subsampling
63+
let width = 258;
6364
let height = 128;
6465

6566
let mut data = Vec::with_capacity(width * height * 3);
6667

6768
for y in 0..height {
6869
for x in 0..width {
70+
let x = x.min(255);
6971
data.push(x as u8);
7072
data.push((y * 2) as u8);
7173
data.push(((x + y * 2) / 2) as u8);
@@ -76,13 +78,14 @@ mod tests {
7678
}
7779

7880
fn create_test_img_gray() -> (Vec<u8>, u16, u16) {
79-
let width = 255;
81+
let width = 258;
8082
let height = 128;
8183

8284
let mut data = Vec::with_capacity(width * height);
8385

8486
for y in 0..height {
8587
for x in 0..width {
88+
let x = x.min(255);
8689
let (y, _, _) = rgb_to_ycbcr(x as u8, (y * 2) as u8, ((x + y * 2) / 2) as u8);
8790
data.push(y);
8891
}
@@ -92,13 +95,14 @@ mod tests {
9295
}
9396

9497
fn create_test_img_cmyk() -> (Vec<u8>, u16, u16) {
95-
let width = 255;
98+
let width = 258;
9699
let height = 192;
97100

98101
let mut data = Vec::with_capacity(width * height * 4);
99102

100103
for y in 0..height {
101104
for x in 0..width {
105+
let x = x.min(255);
102106
data.push(x as u8);
103107
data.push((y * 3 / 2) as u8);
104108
data.push(((x + y * 3 / 2) / 2) as u8);

0 commit comments

Comments
 (0)