Skip to content

Commit 201ca4f

Browse files
authored
Merge pull request #5 from vstroebel/bad_color_conversion
Fix integer overflow in rgb to ycbcr conversion.
2 parents 1864e4e + fa2b214 commit 201ca4f

File tree

4 files changed

+49
-7
lines changed

4 files changed

+49
-7
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "jpeg-encoder"
3-
version = "0.5.0"
3+
version = "0.5.1"
44
authors = ["Volker Ströbel <[email protected]>"]
55
edition = "2018"
66
license = "MIT OR Apache-2.0"

src/avx2/ycbcr.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ macro_rules! ycbcr_image_avx2 {
7070
let yb = _mm256_mullo_epi32(ymulb, b);
7171

7272
let y = _mm256_add_epi32(_mm256_add_epi32(yr, yg), yb);
73-
let y = _mm256_add_epi32(y, _mm256_set1_epi32(1 << 15));
73+
let y = _mm256_add_epi32(y, _mm256_set1_epi32(0x7FFF));
7474
let y = _mm256_srli_epi32(y, 16);
7575
let y: [i32; 8] = core::mem::transmute(y);
7676

@@ -80,7 +80,7 @@ macro_rules! ycbcr_image_avx2 {
8080

8181
let cb = _mm256_add_epi32(_mm256_sub_epi32(cbr, cbg), cbb);
8282
let cb = _mm256_add_epi32(cb, _mm256_set1_epi32(128 << 16));
83-
let cb = _mm256_add_epi32(cb, _mm256_set1_epi32(1 << 15));
83+
let cb = _mm256_add_epi32(cb, _mm256_set1_epi32(0x7FFF));
8484
let cb = _mm256_srli_epi32(cb, 16);
8585
let cb: [i32; 8] = core::mem::transmute(cb);
8686

@@ -90,7 +90,7 @@ macro_rules! ycbcr_image_avx2 {
9090

9191
let cr = _mm256_sub_epi32(_mm256_sub_epi32(crr, crg), crb);
9292
let cr = _mm256_add_epi32(cr, _mm256_set1_epi32(128 << 16));
93-
let cr = _mm256_add_epi32(cr, _mm256_set1_epi32(1 << 15));
93+
let cr = _mm256_add_epi32(cr, _mm256_set1_epi32(0x7FFF));
9494
let cr = _mm256_srli_epi32(cr, 16);
9595
let cr: [i32; 8] = core::mem::transmute(cr);
9696

src/image_buffer.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ pub fn rgb_to_ycbcr(r: u8, g: u8, b: u8) -> (u8, u8, u8) {
2323
let cb = -11059 * r - 21709 * g + 32768 * b + (128 << 16);
2424
let cr = 32768 * r - 27439 * g - 5329 * b + (128 << 16);
2525

26-
let y = (y + (1 << 15)) >> 16;
27-
let cb = (cb + (1 << 15)) >> 16;
28-
let cr = (cr + (1 << 15)) >> 16;
26+
let y = (y + 0x7FFF) >> 16;
27+
let cb = (cb + 0x7FFF) >> 16;
28+
let cr = (cr + 0x7FFF) >> 16;
2929

3030
(y as u8, cb as u8, cr as u8)
3131
}
@@ -287,6 +287,13 @@ mod tests {
287287

288288
#[test]
289289
fn test_rgb_to_ycbcr() {
290+
291+
assert_rgb_to_ycbcr([0, 0, 0], [0, 128, 128]);
292+
assert_rgb_to_ycbcr([255, 255, 255], [255, 128, 128]);
293+
assert_rgb_to_ycbcr([255, 0, 0], [76, 85, 255]);
294+
assert_rgb_to_ycbcr([0, 255, 0], [150, 44, 21]);
295+
assert_rgb_to_ycbcr([0, 0, 255], [29, 255, 107]);
296+
290297
// Values taken from libjpeg for a common image
291298

292299
assert_rgb_to_ycbcr([59, 109, 6], [82, 85, 111]);

src/lib.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,26 @@ mod tests {
7777
(data, width as u16, height as u16)
7878
}
7979

80+
fn create_test_img_rgba() -> (Vec<u8>, u16, u16) {
81+
// Ensure size which which ensures an odd MCU count per row to test chroma subsampling
82+
let width = 258;
83+
let height = 128;
84+
85+
let mut data = Vec::with_capacity(width * height * 3);
86+
87+
for y in 0..height {
88+
for x in 0..width {
89+
let x = x.min(255);
90+
data.push(x as u8);
91+
data.push((y * 2) as u8);
92+
data.push(((x + y * 2) / 2) as u8);
93+
data.push(x as u8);
94+
}
95+
}
96+
97+
(data, width as u16, height as u16)
98+
}
99+
80100
fn create_test_img_gray() -> (Vec<u8>, u16, u16) {
81101
let width = 258;
82102
let height = 128;
@@ -184,6 +204,21 @@ mod tests {
184204
check_result(data, width, height, &mut result, PixelFormat::RGB24);
185205
}
186206

207+
#[test]
208+
fn test_rgba_80() {
209+
let (data, width, height) = create_test_img_rgba();
210+
211+
let mut result = Vec::new();
212+
let encoder = Encoder::new(&mut result, 80);
213+
encoder
214+
.encode(&data, width, height, ColorType::Rgba)
215+
.unwrap();
216+
217+
let (data, width, height) = create_test_img_rgb();
218+
219+
check_result(data, width, height, &mut result, PixelFormat::RGB24);
220+
}
221+
187222
#[test]
188223
fn test_rgb_custom_q_table() {
189224
let (data, width, height) = create_test_img_rgb();

0 commit comments

Comments
 (0)