Skip to content

Commit 545121d

Browse files
committed
Set scale factor with a decoder method, rather than constructor.
1 parent 2f5c940 commit 545121d

File tree

4 files changed

+63
-45
lines changed

4 files changed

+63
-45
lines changed

src/decoder.rs

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ pub struct ImageInfo {
5050
/// JPEG decoder
5151
pub struct Decoder<R> {
5252
reader: R,
53-
requested_size: Option<Dimensions>,
5453

5554
frame: Option<FrameInfo>,
5655
dc_huffman_tables: Vec<Option<HuffmanTable>>,
@@ -71,26 +70,8 @@ pub struct Decoder<R> {
7170
impl<R: Read> Decoder<R> {
7271
/// Creates a new `Decoder` using the reader `reader`.
7372
pub fn new(reader: R) -> Decoder<R> {
74-
Decoder::init(reader, None)
75-
}
76-
77-
/// Creates a new `Decoder` using the reader `reader` that returns a
78-
/// scaled image that is equal to or larger than the requested size in at
79-
/// least one axis, or the full size of the image if the requested size is
80-
/// larger.
81-
///
82-
/// This efficiently scales down the image by one of a fixed set of
83-
/// available ratios during decoding. To generate a thumbnail of an
84-
/// exact size, pass the desired size or larger and then scale to the
85-
/// final size using a traditional resampling algorithm.
86-
pub fn scaled(reader: R, requested_width: u16, requested_height: u16) -> Decoder<R> {
87-
Decoder::init(reader, Some(Dimensions{ width: requested_width, height: requested_height }))
88-
}
89-
90-
fn init(reader: R, requested_size: Option<Dimensions>) -> Decoder<R> {
9173
Decoder {
9274
reader: reader,
93-
requested_size,
9475
frame: None,
9576
dc_huffman_tables: vec![None, None, None, None],
9677
ac_huffman_tables: vec![None, None, None, None],
@@ -135,6 +116,23 @@ impl<R: Read> Decoder<R> {
135116
self.decode_internal(true).map(|_| ())
136117
}
137118

119+
/// Configure the decoder to scale the image during decoding.
120+
///
121+
/// This efficiently scales the image by the smallest supported scale
122+
/// factor that produces an image larger than or equal to the requested
123+
/// size in at least one axis. The currently implemented scale factors
124+
/// are 1/8, 1/4, 1/2 and 1.
125+
///
126+
/// To generate a thumbnail of an exact size, pass the desired size and
127+
/// then scale to the final size using a traditional resampling algorithm.
128+
pub fn scale(&mut self, requested_width: u16, requested_height: u16) -> Result<(u16, u16)> {
129+
self.read_info()?;
130+
let frame = self.frame.as_mut().unwrap();
131+
let idct_size = crate::idct::choose_idct_size(frame.image_size, Dimensions{ width: requested_width, height: requested_height });
132+
frame.update_idct_size(idct_size);
133+
Ok((frame.output_size.width, frame.output_size.height))
134+
}
135+
138136
/// Decodes the image and returns the decoded pixels if successful.
139137
pub fn decode(&mut self) -> Result<Vec<u8>> {
140138
self.decode_internal(false)
@@ -172,7 +170,7 @@ impl<R: Read> Decoder<R> {
172170
return Err(Error::Unsupported(UnsupportedFeature::Hierarchical));
173171
}
174172

175-
let frame = parse_sof(&mut self.reader, marker, self.requested_size)?;
173+
let frame = parse_sof(&mut self.reader, marker)?;
176174
let component_count = frame.components.len();
177175

178176
if frame.is_differential {

src/idct.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// That's why wrapping operators are needed.
44
use crate::parser::Dimensions;
55

6-
pub fn choose_idct_size(full_size: Dimensions, requested_size: Dimensions) -> usize {
6+
pub(crate) fn choose_idct_size(full_size: Dimensions, requested_size: Dimensions) -> usize {
77
fn scaled(len: u16, scale: usize) -> u16 { ((len as u32 * scale as u32 - 1) / 8 + 1) as u16 }
88

99
for &scale in &[1, 2, 4] {
@@ -34,7 +34,7 @@ fn test_choose_idct_size() {
3434
assert_eq!(choose_idct_size(Dimensions{width: 5472, height: 3648}, Dimensions{width: 16384, height: 16384}), 8);
3535
}
3636

37-
pub fn dequantize_and_idct_block(scale: usize, coefficients: &[i16], quantization_table: &[u16; 64], output_linestride: usize, output: &mut [u8]) {
37+
pub(crate) fn dequantize_and_idct_block(scale: usize, coefficients: &[i16], quantization_table: &[u16; 64], output_linestride: usize, output: &mut [u8]) {
3838
match scale {
3939
8 => dequantize_and_idct_block_8x8(coefficients, quantization_table, output_linestride, output),
4040
4 => dequantize_and_idct_block_4x4(coefficients, quantization_table, output_linestride, output),

src/parser.rs

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,21 @@ pub enum AdobeColorTransform {
8282
YCCK,
8383
}
8484

85+
impl FrameInfo {
86+
pub(crate) fn update_idct_size(&mut self, idct_size: usize) {
87+
for component in &mut self.components {
88+
component.dct_scale = idct_size;
89+
}
90+
91+
update_component_sizes(self.image_size, &mut self.components);
92+
93+
self.output_size = Dimensions {
94+
width: (self.image_size.width as f32 * idct_size as f32 / 8.0).ceil() as u16,
95+
height: (self.image_size.height as f32 * idct_size as f32 / 8.0).ceil() as u16
96+
};
97+
}
98+
}
99+
85100
fn read_length<R: Read>(reader: &mut R, marker: Marker) -> Result<usize> {
86101
assert!(marker.has_length());
87102

@@ -107,7 +122,7 @@ fn skip_bytes<R: Read>(reader: &mut R, length: usize) -> Result<()> {
107122
}
108123

109124
// Section B.2.2
110-
pub fn parse_sof<R: Read>(reader: &mut R, marker: Marker, requested_size: Option<Dimensions>) -> Result<FrameInfo> {
125+
pub fn parse_sof<R: Read>(reader: &mut R, marker: Marker) -> Result<FrameInfo> {
111126
let length = read_length(reader, marker)?;
112127

113128
if length <= 6 {
@@ -159,10 +174,6 @@ pub fn parse_sof<R: Read>(reader: &mut R, marker: Marker, requested_size: Option
159174
return Err(Error::Format("zero width in frame header".to_owned()));
160175
}
161176

162-
let scale = if let Some(req) = requested_size {
163-
crate::idct::choose_idct_size(Dimensions { width, height }, req)
164-
} else { 8 };
165-
166177
let component_count = reader.read_u8()?;
167178

168179
if component_count == 0 {
@@ -208,38 +219,45 @@ pub fn parse_sof<R: Read>(reader: &mut R, marker: Marker, requested_size: Option
208219
horizontal_sampling_factor: horizontal_sampling_factor,
209220
vertical_sampling_factor: vertical_sampling_factor,
210221
quantization_table_index: quantization_table_index as usize,
211-
dct_scale: scale,
222+
dct_scale: 8,
212223
size: Dimensions {width: 0, height: 0},
213224
block_size: Dimensions {width: 0, height: 0},
214225
});
215226
}
216227

228+
let mcu_size = update_component_sizes(Dimensions { width, height }, &mut components);
229+
230+
Ok(FrameInfo {
231+
is_baseline: is_baseline,
232+
is_differential: is_differential,
233+
coding_process: coding_process,
234+
entropy_coding: entropy_coding,
235+
precision: precision,
236+
image_size: Dimensions { width, height },
237+
output_size: Dimensions { width, height },
238+
mcu_size,
239+
components: components,
240+
})
241+
}
242+
243+
fn update_component_sizes(size: Dimensions, components: &mut [Component]) -> Dimensions {
217244
let h_max = components.iter().map(|c| c.horizontal_sampling_factor).max().unwrap();
218245
let v_max = components.iter().map(|c| c.vertical_sampling_factor).max().unwrap();
246+
219247
let mcu_size = Dimensions {
220-
width: (width as f32 / (h_max as f32 * 8.0)).ceil() as u16,
221-
height: (height as f32 / (v_max as f32 * 8.0)).ceil() as u16,
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,
222250
};
223251

224-
for component in &mut components {
225-
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;
226-
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;
252+
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;
227255

228256
component.block_size.width = mcu_size.width * component.horizontal_sampling_factor as u16;
229257
component.block_size.height = mcu_size.height * component.vertical_sampling_factor as u16;
230258
}
231259

232-
Ok(FrameInfo {
233-
is_baseline: is_baseline,
234-
is_differential: is_differential,
235-
coding_process: coding_process,
236-
entropy_coding: entropy_coding,
237-
precision: precision,
238-
image_size: Dimensions {width: width, height: height},
239-
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},
240-
mcu_size: mcu_size,
241-
components: components,
242-
})
260+
mcu_size
243261
}
244262

245263
// Section B.2.3

tests/reftest/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ fn reftest_file(path: &Path) {
3232

3333
fn reftest_scaled_file(path: &Path, width: u16, height: u16, ref_path: &Path) {
3434
let file = File::open(path).unwrap();
35-
let decoder = jpeg::Decoder::scaled(file, width, height);
35+
let mut decoder = jpeg::Decoder::new(file);
36+
decoder.read_info().unwrap();
37+
decoder.scale(width, height).unwrap();
3638
reftest_decoder(decoder, path, &ref_path);
3739
}
3840

0 commit comments

Comments
 (0)