summaryrefslogtreecommitdiff
path: root/vendor/jpeg-decoder/src/upsampler.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/jpeg-decoder/src/upsampler.rs')
-rw-r--r--vendor/jpeg-decoder/src/upsampler.rs252
1 files changed, 252 insertions, 0 deletions
diff --git a/vendor/jpeg-decoder/src/upsampler.rs b/vendor/jpeg-decoder/src/upsampler.rs
new file mode 100644
index 0000000..a5c39d4
--- /dev/null
+++ b/vendor/jpeg-decoder/src/upsampler.rs
@@ -0,0 +1,252 @@
+use alloc::boxed::Box;
+use alloc::vec;
+use alloc::vec::Vec;
+use crate::error::{Error, Result, UnsupportedFeature};
+use crate::parser::Component;
+
+pub struct Upsampler {
+ components: Vec<UpsamplerComponent>,
+ line_buffer_size: usize
+}
+
+struct UpsamplerComponent {
+ upsampler: Box<dyn Upsample + Sync>,
+ width: usize,
+ height: usize,
+ row_stride: usize,
+}
+
+impl Upsampler {
+ pub fn new(components: &[Component], output_width: u16, output_height: u16) -> Result<Upsampler> {
+ let h_max = components.iter().map(|c| c.horizontal_sampling_factor).max().unwrap();
+ let v_max = components.iter().map(|c| c.vertical_sampling_factor).max().unwrap();
+ let mut upsampler_components = Vec::with_capacity(components.len());
+
+ for component in components {
+ let upsampler = choose_upsampler((component.horizontal_sampling_factor,
+ component.vertical_sampling_factor),
+ (h_max, v_max),
+ output_width,
+ output_height)?;
+ upsampler_components.push(UpsamplerComponent {
+ upsampler,
+ width: component.size.width as usize,
+ height: component.size.height as usize,
+ row_stride: component.block_size.width as usize * component.dct_scale,
+ });
+ }
+
+ let buffer_size = components.iter().map(|c| c.size.width).max().unwrap() as usize * h_max as usize;
+
+ Ok(Upsampler {
+ components: upsampler_components,
+ line_buffer_size: buffer_size
+ })
+ }
+
+ pub fn upsample_and_interleave_row(&self, component_data: &[Vec<u8>], row: usize, output_width: usize, output: &mut [u8], color_convert: fn(&[Vec<u8>], &mut [u8])) {
+ let component_count = component_data.len();
+ let mut line_buffers = vec![vec![0u8; self.line_buffer_size]; component_count];
+
+ debug_assert_eq!(component_count, self.components.len());
+
+ for (i, component) in self.components.iter().enumerate() {
+ component.upsampler.upsample_row(&component_data[i],
+ component.width,
+ component.height,
+ component.row_stride,
+ row,
+ output_width,
+ &mut line_buffers[i]);
+ }
+ color_convert(&line_buffers, output);
+ }
+}
+
+struct UpsamplerH1V1;
+struct UpsamplerH2V1;
+struct UpsamplerH1V2;
+struct UpsamplerH2V2;
+
+struct UpsamplerGeneric {
+ horizontal_scaling_factor: u8,
+ vertical_scaling_factor: u8
+}
+
+fn choose_upsampler(sampling_factors: (u8, u8),
+ max_sampling_factors: (u8, u8),
+ output_width: u16,
+ output_height: u16) -> Result<Box<dyn Upsample + Sync>> {
+ let h1 = sampling_factors.0 == max_sampling_factors.0 || output_width == 1;
+ let v1 = sampling_factors.1 == max_sampling_factors.1 || output_height == 1;
+ let h2 = sampling_factors.0 * 2 == max_sampling_factors.0;
+ let v2 = sampling_factors.1 * 2 == max_sampling_factors.1;
+
+ if h1 && v1 {
+ Ok(Box::new(UpsamplerH1V1))
+ }
+ else if h2 && v1 {
+ Ok(Box::new(UpsamplerH2V1))
+ }
+ else if h1 && v2 {
+ Ok(Box::new(UpsamplerH1V2))
+ }
+ else if h2 && v2 {
+ Ok(Box::new(UpsamplerH2V2))
+ }
+ else {
+ if max_sampling_factors.0 % sampling_factors.0 != 0 || max_sampling_factors.1 % sampling_factors.1 != 0 {
+ Err(Error::Unsupported(UnsupportedFeature::NonIntegerSubsamplingRatio))
+ }
+ else {
+ Ok(Box::new(UpsamplerGeneric {
+ horizontal_scaling_factor: max_sampling_factors.0 / sampling_factors.0,
+ vertical_scaling_factor: max_sampling_factors.1 / sampling_factors.1
+ }))
+ }
+ }
+}
+
+trait Upsample {
+ fn upsample_row(&self,
+ input: &[u8],
+ input_width: usize,
+ input_height: usize,
+ row_stride: usize,
+ row: usize,
+ output_width: usize,
+ output: &mut [u8]);
+}
+
+impl Upsample for UpsamplerH1V1 {
+ fn upsample_row(&self,
+ input: &[u8],
+ _input_width: usize,
+ _input_height: usize,
+ row_stride: usize,
+ row: usize,
+ output_width: usize,
+ output: &mut [u8]) {
+ let input = &input[row * row_stride ..];
+
+ output[..output_width].copy_from_slice(&input[..output_width]);
+ }
+}
+
+impl Upsample for UpsamplerH2V1 {
+ fn upsample_row(&self,
+ input: &[u8],
+ input_width: usize,
+ _input_height: usize,
+ row_stride: usize,
+ row: usize,
+ _output_width: usize,
+ output: &mut [u8]) {
+ let input = &input[row * row_stride ..];
+
+ if input_width == 1 {
+ output[0] = input[0];
+ output[1] = input[0];
+ return;
+ }
+
+ output[0] = input[0];
+ output[1] = ((input[0] as u32 * 3 + input[1] as u32 + 2) >> 2) as u8;
+
+ for i in 1 .. input_width - 1 {
+ let sample = 3 * input[i] as u32 + 2;
+ output[i * 2] = ((sample + input[i - 1] as u32) >> 2) as u8;
+ output[i * 2 + 1] = ((sample + input[i + 1] as u32) >> 2) as u8;
+ }
+
+ output[(input_width - 1) * 2] = ((input[input_width - 1] as u32 * 3 + input[input_width - 2] as u32 + 2) >> 2) as u8;
+ output[(input_width - 1) * 2 + 1] = input[input_width - 1];
+ }
+}
+
+impl Upsample for UpsamplerH1V2 {
+ fn upsample_row(&self,
+ input: &[u8],
+ _input_width: usize,
+ input_height: usize,
+ row_stride: usize,
+ row: usize,
+ output_width: usize,
+ output: &mut [u8]) {
+ let row_near = row as f32 / 2.0;
+ // If row_near's fractional is 0.0 we want row_far to be the previous row and if it's 0.5 we
+ // want it to be the next row.
+ let row_far = (row_near + row_near.fract() * 3.0 - 0.25).min((input_height - 1) as f32);
+
+ let input_near = &input[row_near as usize * row_stride ..];
+ let input_far = &input[row_far as usize * row_stride ..];
+
+ let output = &mut output[..output_width];
+ let input_near = &input_near[..output_width];
+ let input_far = &input_far[..output_width];
+ for i in 0..output_width {
+ output[i] = ((3 * input_near[i] as u32 + input_far[i] as u32 + 2) >> 2) as u8;
+ }
+ }
+}
+
+impl Upsample for UpsamplerH2V2 {
+ fn upsample_row(&self,
+ input: &[u8],
+ input_width: usize,
+ input_height: usize,
+ row_stride: usize,
+ row: usize,
+ _output_width: usize,
+ output: &mut [u8]) {
+ let row_near = row as f32 / 2.0;
+ // If row_near's fractional is 0.0 we want row_far to be the previous row and if it's 0.5 we
+ // want it to be the next row.
+ let row_far = (row_near + row_near.fract() * 3.0 - 0.25).min((input_height - 1) as f32);
+
+ let input_near = &input[row_near as usize * row_stride ..];
+ let input_far = &input[row_far as usize * row_stride ..];
+
+ if input_width == 1 {
+ let value = ((3 * input_near[0] as u32 + input_far[0] as u32 + 2) >> 2) as u8;
+ output[0] = value;
+ output[1] = value;
+ return;
+ }
+
+ let mut t1 = 3 * input_near[0] as u32 + input_far[0] as u32;
+ output[0] = ((t1 + 2) >> 2) as u8;
+
+ for i in 1 .. input_width {
+ let t0 = t1;
+ t1 = 3 * input_near[i] as u32 + input_far[i] as u32;
+
+ output[i * 2 - 1] = ((3 * t0 + t1 + 8) >> 4) as u8;
+ output[i * 2] = ((3 * t1 + t0 + 8) >> 4) as u8;
+ }
+
+ output[input_width * 2 - 1] = ((t1 + 2) >> 2) as u8;
+ }
+}
+
+impl Upsample for UpsamplerGeneric {
+ // Uses nearest neighbor sampling
+ fn upsample_row(&self,
+ input: &[u8],
+ input_width: usize,
+ _input_height: usize,
+ row_stride: usize,
+ row: usize,
+ _output_width: usize,
+ output: &mut [u8]) {
+ let mut index = 0;
+ let start = (row / self.vertical_scaling_factor as usize) * row_stride;
+ let input = &input[start..(start + input_width)];
+ for val in input {
+ for _ in 0..self.horizontal_scaling_factor {
+ output[index] = *val;
+ index += 1;
+ }
+ }
+ }
+}