Skip to content

Commit 0920c4c

Browse files
authored
Fix #148 (#149)
* Fix #148 * Safer size check & integer size calculations * Added a few test images The blank test image was generated with convert -size 800x280 -sampling-factor 2x2 xc:white tests/reftest/images/blank_800x280.jpg This creates a grayscale image with a sampling factor of 2 and a height that is a multiple of 8 but not 16, so that it triggers #148. * Add more test images The images were generated with imagemagick to match variants of bug #148 convert -size 16x24 -sampling-factor 2x2 -colorspace gray xc: +noise Random grayscale_16x24_sampling2x2.png convert grayscale_16x24_sampling2x2.png -quality 100 -sampling-factor 2x2 grayscale_16x24_sampling2x2.jpg The idea is that even though they are currently treated the same, images with a width that is an integer number of blocks are not the same as images for which the height is an integer number of blocks. If only the height is not an integer number of blocks, more optimizations can be applied. This will be the subject of another pull request.
1 parent 0c6f5a2 commit 0920c4c

11 files changed

+41
-13
lines changed

src/decoder.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -776,22 +776,25 @@ fn compute_image(components: &[Component],
776776

777777
if components.len() == 1 {
778778
let component = &components[0];
779-
780-
if component.size.width % 8 == 0 && component.size.height % 8 == 0 {
781-
return Ok(data[0].clone())
782-
}
779+
let decoded = &data[0];
783780

784781
let width = component.size.width as usize;
785782
let height = component.size.height as usize;
783+
let size = width * height;
784+
785+
// if the image size is a multiple of the block size
786+
if decoded.len() == size {
787+
return Ok(decoded.to_vec())
788+
}
786789

787-
let mut buffer = vec![0u8; width * height];
790+
let mut buffer = vec![0u8; size];
788791
let line_stride = component.block_size.width as usize * component.dct_scale;
789792

790-
for y in 0 .. height {
793+
for y in 0..height {
791794
let destination_idx = y * width;
792795
let source_idx = y * line_stride;
793796
let destination = &mut buffer[destination_idx..][..width];
794-
let source = &data[0][source_idx..][..width];
797+
let source = &decoded[source_idx..][..width];
795798
destination.copy_from_slice(source);
796799
}
797800

src/parser.rs

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -240,18 +240,24 @@ pub fn parse_sof<R: Read>(reader: &mut R, marker: Marker) -> Result<FrameInfo> {
240240
})
241241
}
242242

243+
/// Returns ceil(x/y), requires x>0
244+
fn ceil_div(x: u32, y: u32) -> u16 {
245+
assert!(x>0 && y>0, "invalid dimensions");
246+
(1 + ((x - 1) / y)) as u16
247+
}
248+
243249
fn update_component_sizes(size: Dimensions, components: &mut [Component]) -> Dimensions {
244-
let h_max = components.iter().map(|c| c.horizontal_sampling_factor).max().unwrap();
245-
let v_max = components.iter().map(|c| c.vertical_sampling_factor).max().unwrap();
250+
let h_max = components.iter().map(|c| c.horizontal_sampling_factor).max().unwrap() as u32;
251+
let v_max = components.iter().map(|c| c.vertical_sampling_factor).max().unwrap() as u32;
246252

247253
let mcu_size = Dimensions {
248-
width: (size.width as f32 / (h_max as f32 * 8.0)).ceil() as u16,
249-
height: (size.height as f32 / (v_max as f32 * 8.0)).ceil() as u16,
254+
width: ceil_div(size.width as u32, h_max * 8),
255+
height: ceil_div(size.height as u32, v_max * 8),
250256
};
251257

252258
for component in components {
253-
component.size.width = (size.width as f32 * component.horizontal_sampling_factor as f32 * component.dct_scale as f32 / (h_max as f32 * 8.0)).ceil() as u16;
254-
component.size.height = (size.height as f32 * component.vertical_sampling_factor as f32 * component.dct_scale as f32 / (v_max as f32 * 8.0)).ceil() as u16;
259+
component.size.width = ceil_div(size.width as u32 * component.horizontal_sampling_factor as u32 * component.dct_scale as u32, h_max * 8);
260+
component.size.height = ceil_div(size.height as u32 * component.vertical_sampling_factor as u32 * component.dct_scale as u32, v_max * 8);
255261

256262
component.block_size.width = mcu_size.width * component.horizontal_sampling_factor as u16;
257263
component.block_size.height = mcu_size.height * component.vertical_sampling_factor as u16;
@@ -260,6 +266,25 @@ fn update_component_sizes(size: Dimensions, components: &mut [Component]) -> Dim
260266
mcu_size
261267
}
262268

269+
#[test]
270+
fn test_update_component_sizes() {
271+
let mut components = [Component {
272+
identifier: 1,
273+
horizontal_sampling_factor: 2,
274+
vertical_sampling_factor: 2,
275+
quantization_table_index: 0,
276+
dct_scale: 8,
277+
size: Dimensions { width: 0, height: 0 },
278+
block_size: Dimensions { width: 0, height: 0 },
279+
}];
280+
let mcu = update_component_sizes(
281+
Dimensions { width: 800, height: 280 },
282+
&mut components);
283+
assert_eq!(mcu, Dimensions { width: 50, height: 18 });
284+
assert_eq!(components[0].block_size, Dimensions { width: 100, height: 36 });
285+
assert_eq!(components[0].size, Dimensions { width: 800, height: 280 });
286+
}
287+
263288
// Section B.2.3
264289
pub fn parse_sos<R: Read>(reader: &mut R, frame: &FrameInfo) -> Result<ScanInfo> {
265290
let length = read_length(reader, SOS)?;

tests/crashtest/images/empty.jpg

Loading

tests/crashtest/images/max_size.jpg

186 Bytes
Loading
186 Bytes
Loading
1.01 KB
Loading
371 Bytes
Loading
Loading
1007 Bytes
Loading
Loading

0 commit comments

Comments
 (0)