Skip to content

Commit 91cdd86

Browse files
lovasoa197g
authored andcommitted
Generalize the grayscale image computation optimization
When we are decoding a grayscale image and its width is a multiple of the block size, then we can directly return the internal decoding buffer without computation nor data copying. This gives a ~4% performance improvement on my machine when decoding a 512x512 grayscale image. Before: time: [896.42 us 900.54 us 904.92 us] After: time: [882.10 us 884.72 us 887.31 us] When decoding a grayscale image with a width multiple of the block size and a height that is not, the performance gains are even better compared to the old version that optimized only the case where the whole image size was a multiple of the block size.
1 parent 004d9b4 commit 91cdd86

File tree

1 file changed

+20
-16
lines changed

1 file changed

+20
-16
lines changed

src/decoder.rs

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ impl<R: Read> Decoder<R> {
346346
}
347347

348348
let frame = self.frame.as_ref().unwrap();
349-
compute_image(&frame.components, &planes, frame.output_size, self.is_jfif, self.color_transform)
349+
compute_image(&frame.components, planes, frame.output_size, self.is_jfif, self.color_transform)
350350
}
351351

352352
fn read_marker(&mut self) -> Result<Marker> {
@@ -766,7 +766,7 @@ fn refine_non_zeroes<R: Read>(reader: &mut R,
766766
}
767767

768768
fn compute_image(components: &[Component],
769-
data: &[Vec<u8>],
769+
mut data: Vec<Vec<u8>>,
770770
output_size: Dimensions,
771771
is_jfif: bool,
772772
color_transform: Option<AdobeColorTransform>) -> Result<Vec<u8>> {
@@ -776,19 +776,23 @@ fn compute_image(components: &[Component],
776776

777777
if components.len() == 1 {
778778
let component = &components[0];
779-
let decoded = &data[0];
779+
let mut decoded: Vec<u8> = data.remove(0);
780780

781781
let width = component.size.width as usize;
782782
let height = component.size.height as usize;
783783
let size = width * height;
784+
let line_stride = component.block_size.width as usize * component.dct_scale;
784785

785-
// if the image size is a multiple of the block size
786-
if decoded.len() == size {
787-
return Ok(decoded.to_vec())
786+
// if the image width is a multiple of the block size,
787+
// then we don't have to move bytes in the decoded data
788+
if usize::from(output_size.width) == line_stride {
789+
// If the height of the image is not a multiple of the block size,
790+
// Then we have lines at the end that we don't need
791+
decoded.resize(size, 0); // We are in greyscale, 1 byte per pixel
792+
return Ok(decoded)
788793
}
789794

790795
let mut buffer = vec![0u8; size];
791-
let line_stride = component.block_size.width as usize * component.dct_scale;
792796

793797
for y in 0..height {
794798
let destination_idx = y * width;
@@ -807,10 +811,10 @@ fn compute_image(components: &[Component],
807811

808812
#[cfg(feature="rayon")]
809813
fn compute_image_parallel(components: &[Component],
810-
data: &[Vec<u8>],
811-
output_size: Dimensions,
812-
is_jfif: bool,
813-
color_transform: Option<AdobeColorTransform>) -> Result<Vec<u8>> {
814+
data: Vec<Vec<u8>>,
815+
output_size: Dimensions,
816+
is_jfif: bool,
817+
color_transform: Option<AdobeColorTransform>) -> Result<Vec<u8>> {
814818
use rayon::prelude::*;
815819

816820
let color_convert_func = choose_color_convert_func(components.len(), is_jfif, color_transform)?;
@@ -822,7 +826,7 @@ fn compute_image_parallel(components: &[Component],
822826
.with_max_len(1)
823827
.enumerate()
824828
.for_each(|(row, line)| {
825-
upsampler.upsample_and_interleave_row(data, row, output_size.width as usize, line);
829+
upsampler.upsample_and_interleave_row(&data, row, output_size.width as usize, line);
826830
color_convert_func(line, output_size.width as usize);
827831
});
828832

@@ -831,10 +835,10 @@ fn compute_image_parallel(components: &[Component],
831835

832836
#[cfg(not(feature="rayon"))]
833837
fn compute_image_parallel(components: &[Component],
834-
data: &[Vec<u8>],
835-
output_size: Dimensions,
836-
is_jfif: bool,
837-
color_transform: Option<AdobeColorTransform>) -> Result<Vec<u8>> {
838+
data: Vec<Vec<u8>>,
839+
output_size: Dimensions,
840+
is_jfif: bool,
841+
color_transform: Option<AdobeColorTransform>) -> Result<Vec<u8>> {
838842
let color_convert_func = choose_color_convert_func(components.len(), is_jfif, color_transform)?;
839843
let upsampler = Upsampler::new(components, output_size.width, output_size.height)?;
840844
let line_size = output_size.width as usize * components.len();

0 commit comments

Comments
 (0)