Skip to content

Commit 3123fc5

Browse files
committed
Add support for IDCT downscaling
Currently only adds 1/8 scale because the 1x1 IDCT is trivial, but this adds the infrastructure to easily support the others.
1 parent c8e2525 commit 3123fc5

File tree

5 files changed

+53
-25
lines changed

5 files changed

+53
-25
lines changed

src/decoder.rs

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ pub struct ImageInfo {
5050
/// JPEG decoder
5151
pub struct Decoder<R> {
5252
reader: R,
53+
scale: usize,
5354

5455
frame: Option<FrameInfo>,
5556
dc_huffman_tables: Vec<Option<HuffmanTable>>,
@@ -70,8 +71,15 @@ pub struct Decoder<R> {
7071
impl<R: Read> Decoder<R> {
7172
/// Creates a new `Decoder` using the reader `reader`.
7273
pub fn new(reader: R) -> Decoder<R> {
74+
Decoder::new_scaled(reader, 8)
75+
}
76+
77+
/// Creates a new `Decoder` using the reader `reader` that scales
78+
/// down the image by a factor of `scale/8`.
79+
pub fn new_scaled(reader: R, scale: usize) -> Decoder<R> {
7380
Decoder {
7481
reader: reader,
82+
scale: scale,
7583
frame: None,
7684
dc_huffman_tables: vec![None, None, None, None],
7785
ac_huffman_tables: vec![None, None, None, None],
@@ -100,8 +108,8 @@ impl<R: Read> Decoder<R> {
100108
};
101109

102110
Some(ImageInfo {
103-
width: frame.image_size.width,
104-
height: frame.image_size.height,
111+
width: frame.output_size.width,
112+
height: frame.output_size.height,
105113
pixel_format: pixel_format,
106114
})
107115
},
@@ -153,7 +161,7 @@ impl<R: Read> Decoder<R> {
153161
return Err(Error::Unsupported(UnsupportedFeature::Hierarchical));
154162
}
155163

156-
let frame = parse_sof(&mut self.reader, marker)?;
164+
let frame = parse_sof(&mut self.reader, marker, self.scale)?;
157165
let component_count = frame.components.len();
158166

159167
if frame.is_differential {
@@ -329,7 +337,7 @@ impl<R: Read> Decoder<R> {
329337
}
330338

331339
let frame = self.frame.as_ref().unwrap();
332-
compute_image(&frame.components, &planes, frame.image_size, self.is_jfif, self.color_transform)
340+
compute_image(&frame.components, &planes, frame.output_size, self.is_jfif, self.color_transform)
333341
}
334342

335343
fn read_marker(&mut self) -> Result<Marker> {
@@ -436,7 +444,7 @@ impl<R: Read> Decoder<R> {
436444
let x = (block_num % blocks_per_row) as u16;
437445
let y = (block_num / blocks_per_row) as u16;
438446

439-
if x * 8 >= component.size.width || y * 8 >= component.size.height {
447+
if x * component.dct_scale as u16 >= component.size.width || y * component.dct_scale as u16 >= component.size.height {
440448
continue;
441449
}
442450

@@ -762,12 +770,15 @@ fn compute_image(components: &[Component],
762770
return Ok(data[0].clone())
763771
}
764772

765-
let mut buffer = vec![0u8; component.size.width as usize * component.size.height as usize];
766-
let line_stride = component.block_size.width as usize * 8;
773+
let width = component.size.width as usize;
774+
let height = component.size.height as usize;
775+
776+
let mut buffer = vec![0u8; width * height];
777+
let line_stride = width * component.dct_scale;
767778

768-
for y in 0 .. component.size.height as usize {
769-
for x in 0 .. component.size.width as usize {
770-
buffer[y * component.size.width as usize + x] = data[0][y * line_stride + x];
779+
for y in 0 .. width {
780+
for x in 0 .. height {
781+
buffer[y * width + x] = data[0][y * line_stride + x];
771782
}
772783
}
773784

src/idct.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,15 @@
22
// One example is tests/crashtest/images/imagetestsuite/b0b8914cc5f7a6eff409f16d8cc236c5.jpg
33
// That's why wrapping operators are needed.
44

5+
pub fn dequantize_and_idct_block_1x1(coefficients: &[i16], quantization_table: &[u16; 64], _output_linestride: usize, output: &mut [u8]) {
6+
debug_assert_eq!(coefficients.len(), 64);
7+
8+
let s0 = (coefficients[0] as i32 * quantization_table[0] as i32).wrapping_add(128 * 8) / 8;
9+
output[0] = stbi_clamp(s0);
10+
}
11+
512
// This is based on stb_image's 'stbi__idct_block'.
6-
pub fn dequantize_and_idct_block(coefficients: &[i16], quantization_table: &[u16; 64], output_linestride: usize, output: &mut [u8]) {
13+
pub fn dequantize_and_idct_block_8x8(coefficients: &[i16], quantization_table: &[u16; 64], output_linestride: usize, output: &mut [u8]) {
714
debug_assert_eq!(coefficients.len(), 64);
815

916
let mut temp = [0i32; 64];

src/parser.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ pub struct FrameInfo {
3434
pub precision: u8,
3535

3636
pub image_size: Dimensions,
37+
pub output_size: Dimensions,
3738
pub mcu_size: Dimensions,
3839
pub components: Vec<Component>,
3940
}
@@ -58,6 +59,8 @@ pub struct Component {
5859

5960
pub quantization_table_index: usize,
6061

62+
pub dct_scale: usize,
63+
6164
pub size: Dimensions,
6265
pub block_size: Dimensions,
6366
}
@@ -104,7 +107,7 @@ fn skip_bytes<R: Read>(reader: &mut R, length: usize) -> Result<()> {
104107
}
105108

106109
// Section B.2.2
107-
pub fn parse_sof<R: Read>(reader: &mut R, marker: Marker) -> Result<FrameInfo> {
110+
pub fn parse_sof<R: Read>(reader: &mut R, marker: Marker, scale: usize) -> Result<FrameInfo> {
108111
let length = read_length(reader, marker)?;
109112

110113
if length <= 6 {
@@ -201,6 +204,7 @@ pub fn parse_sof<R: Read>(reader: &mut R, marker: Marker) -> Result<FrameInfo> {
201204
horizontal_sampling_factor: horizontal_sampling_factor,
202205
vertical_sampling_factor: vertical_sampling_factor,
203206
quantization_table_index: quantization_table_index as usize,
207+
dct_scale: scale,
204208
size: Dimensions {width: 0, height: 0},
205209
block_size: Dimensions {width: 0, height: 0},
206210
});
@@ -214,8 +218,8 @@ pub fn parse_sof<R: Read>(reader: &mut R, marker: Marker) -> Result<FrameInfo> {
214218
};
215219

216220
for component in &mut components {
217-
component.size.width = (width as f32 * (component.horizontal_sampling_factor as f32 / h_max as f32)).ceil() as u16;
218-
component.size.height = (height as f32 * (component.vertical_sampling_factor as f32 / v_max as f32)).ceil() as u16;
221+
component.size.width = (width as f32 * component.horizontal_sampling_factor as f32 * component.dct_scale as f32 / (h_max as f32 * 8.0)).ceil() as u16;
222+
component.size.height = (height as f32 * component.vertical_sampling_factor as f32 * component.dct_scale as f32 / (v_max as f32 * 8.0)).ceil() as u16;
219223

220224
component.block_size.width = mcu_size.width * component.horizontal_sampling_factor as u16;
221225
component.block_size.height = mcu_size.height * component.vertical_sampling_factor as u16;
@@ -228,6 +232,7 @@ pub fn parse_sof<R: Read>(reader: &mut R, marker: Marker) -> Result<FrameInfo> {
228232
entropy_coding: entropy_coding,
229233
precision: precision,
230234
image_size: Dimensions {width: width, height: height},
235+
output_size: Dimensions {width: (width as f32 * scale as f32 / 8.0).ceil() as u16, height: (height as f32 * scale as f32 / 8.0).ceil() as u16},
231236
mcu_size: mcu_size,
232237
components: components,
233238
})

src/upsampler.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ impl Upsampler {
2929
upsampler: upsampler,
3030
width: component.size.width as usize,
3131
height: component.size.height as usize,
32-
row_stride: component.block_size.width as usize * 8,
32+
row_stride: component.block_size.width as usize * component.dct_scale,
3333
});
3434
}
3535

src/worker/immediate.rs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use decoder::MAX_COMPONENTS;
22
use error::Result;
3-
use idct::dequantize_and_idct_block;
3+
use idct::{ dequantize_and_idct_block_8x8, dequantize_and_idct_block_1x1 };
44
use std::mem;
55
use std::sync::Arc;
66
use parser::Component;
@@ -26,7 +26,7 @@ impl ImmediateWorker {
2626
assert!(self.results[data.index].is_empty());
2727

2828
self.offsets[data.index] = 0;
29-
self.results[data.index].resize(data.component.block_size.width as usize * data.component.block_size.height as usize * 64, 0u8);
29+
self.results[data.index].resize(data.component.block_size.width as usize * data.component.block_size.height as usize * data.component.dct_scale * data.component.dct_scale, 0u8);
3030
self.components[data.index] = Some(data.component);
3131
self.quantization_tables[data.index] = Some(data.quantization_table);
3232
}
@@ -36,20 +36,25 @@ impl ImmediateWorker {
3636
let component = self.components[index].as_ref().unwrap();
3737
let quantization_table = self.quantization_tables[index].as_ref().unwrap();
3838
let block_count = component.block_size.width as usize * component.vertical_sampling_factor as usize;
39-
let line_stride = component.block_size.width as usize * 8;
39+
let line_stride = component.block_size.width as usize * component.dct_scale;
4040

4141
assert_eq!(data.len(), block_count * 64);
4242

4343
for i in 0..block_count {
44-
let x = (i % component.block_size.width as usize) * 8;
45-
let y = (i / component.block_size.width as usize) * 8;
46-
dequantize_and_idct_block(&data[i * 64..(i + 1) * 64],
47-
quantization_table,
48-
line_stride,
49-
&mut self.results[index][self.offsets[index] + y * line_stride + x..]);
44+
let x = (i % component.block_size.width as usize) * component.dct_scale;
45+
let y = (i / component.block_size.width as usize) * component.dct_scale;
46+
47+
let coefficients = &data[i * 64..(i + 1) * 64];
48+
let output = &mut self.results[index][self.offsets[index] + y * line_stride + x..];
49+
50+
match component.dct_scale {
51+
8 => dequantize_and_idct_block_8x8(coefficients, quantization_table, line_stride, output),
52+
1 => dequantize_and_idct_block_1x1(coefficients, quantization_table, line_stride, output),
53+
_ => unimplemented!(),
54+
}
5055
}
5156

52-
self.offsets[index] += data.len();
57+
self.offsets[index] += block_count * component.dct_scale * component.dct_scale;
5358
}
5459
pub fn get_result_immediate(&mut self, index: usize) -> Vec<u8> {
5560
mem::replace(&mut self.results[index], Vec::new())

0 commit comments

Comments
 (0)