diff options
Diffstat (limited to 'vendor/jpeg-decoder/src/decoder/lossless.rs')
-rw-r--r-- | vendor/jpeg-decoder/src/decoder/lossless.rs | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/vendor/jpeg-decoder/src/decoder/lossless.rs b/vendor/jpeg-decoder/src/decoder/lossless.rs new file mode 100644 index 0000000..6422220 --- /dev/null +++ b/vendor/jpeg-decoder/src/decoder/lossless.rs @@ -0,0 +1,259 @@ +use std::io::Read; +use crate::decoder::{Decoder, MAX_COMPONENTS}; +use crate::error::{Error, Result}; +use crate::huffman::HuffmanDecoder; +use crate::marker::Marker; +use crate::parser::Predictor; +use crate::parser::{Component, FrameInfo, ScanInfo}; + +impl<R: Read> Decoder<R> { + /// decode_scan_lossless + pub fn decode_scan_lossless( + &mut self, + frame: &FrameInfo, + scan: &ScanInfo, + ) -> Result<(Option<Marker>, Vec<Vec<u16>>)> { + let ncomp = scan.component_indices.len(); + let npixel = frame.image_size.height as usize * frame.image_size.width as usize; + assert!(ncomp <= MAX_COMPONENTS); + let mut results = vec![vec![0u16; npixel]; ncomp]; + + let components: Vec<Component> = scan + .component_indices + .iter() + .map(|&i| frame.components[i].clone()) + .collect(); + + // Verify that all required huffman tables has been set. + if scan + .dc_table_indices + .iter() + .any(|&i| self.dc_huffman_tables[i].is_none()) + { + return Err(Error::Format( + "scan makes use of unset dc huffman table".to_owned(), + )); + } + + let mut huffman = HuffmanDecoder::new(); + let reader = &mut self.reader; + let mut mcus_left_until_restart = self.restart_interval; + let mut expected_rst_num = 0; + let mut ra = [0u16; MAX_COMPONENTS]; + let mut rb = [0u16; MAX_COMPONENTS]; + let mut rc = [0u16; MAX_COMPONENTS]; + + let width = frame.image_size.width as usize; + let height = frame.image_size.height as usize; + + let mut differences = vec![Vec::with_capacity(npixel); ncomp]; + for _mcu_y in 0..height { + for _mcu_x in 0..width { + if self.restart_interval > 0 { + if mcus_left_until_restart == 0 { + match huffman.take_marker(reader)? { + Some(Marker::RST(n)) => { + if n != expected_rst_num { + return Err(Error::Format(format!( + "found RST{} where RST{} was expected", + n, expected_rst_num + ))); + } + + huffman.reset(); + + expected_rst_num = (expected_rst_num + 1) % 8; + mcus_left_until_restart = self.restart_interval; + } + Some(marker) => { + return Err(Error::Format(format!( + "found marker {:?} inside scan where RST{} was expected", + marker, expected_rst_num + ))) + } + None => { + return Err(Error::Format(format!( + "no marker found where RST{} was expected", + expected_rst_num + ))) + } + } + } + + mcus_left_until_restart -= 1; + } + + for (i, _component) in components.iter().enumerate() { + let dc_table = self.dc_huffman_tables[scan.dc_table_indices[i]] + .as_ref() + .unwrap(); + let value = huffman.decode(reader, dc_table)?; + let diff = match value { + 0 => 0, + 1..=15 => huffman.receive_extend(reader, value)? as i32, + 16 => 32768, + _ => { + // Section F.1.2.1.1 + // Table F.1 + return Err(Error::Format( + "invalid DC difference magnitude category".to_owned(), + )); + } + }; + differences[i].push(diff); + } + } + } + + if scan.predictor_selection == Predictor::Ra { + for (i, _component) in components.iter().enumerate() { + // calculate the top left pixel + let diff = differences[i][0]; + let prediction = 1 << (frame.precision - scan.point_transform - 1) as i32; + let result = ((prediction + diff) & 0xFFFF) as u16; // modulo 2^16 + let result = result << scan.point_transform; + results[i][0] = result; + + // calculate leftmost column, using top pixel as predictor + let mut previous = result; + for mcu_y in 1..height { + let diff = differences[i][mcu_y * width]; + let prediction = previous as i32; + let result = ((prediction + diff) & 0xFFFF) as u16; // modulo 2^16 + let result = result << scan.point_transform; + results[i][mcu_y * width] = result; + previous = result; + } + + // calculate rows, using left pixel as predictor + for mcu_y in 0..height { + for mcu_x in 1..width { + let diff = differences[i][mcu_y * width + mcu_x]; + let prediction = results[i][mcu_y * width + mcu_x - 1] as i32; + let result = ((prediction + diff) & 0xFFFF) as u16; // modulo 2^16 + let result = result << scan.point_transform; + results[i][mcu_y * width + mcu_x] = result; + } + } + } + } else { + for mcu_y in 0..height { + for mcu_x in 0..width { + for (i, _component) in components.iter().enumerate() { + let diff = differences[i][mcu_y * width + mcu_x]; + + // The following lines could be further optimized, e.g. moving the checks + // and updates of the previous values into the prediction function or + // iterating such that diagonals with mcu_x + mcu_y = const are computed at + // the same time to exploit independent predictions in this case + if mcu_x > 0 { + ra[i] = results[i][mcu_y * frame.image_size.width as usize + mcu_x - 1]; + } + if mcu_y > 0 { + rb[i] = + results[i][(mcu_y - 1) * frame.image_size.width as usize + mcu_x]; + if mcu_x > 0 { + rc[i] = results[i] + [(mcu_y - 1) * frame.image_size.width as usize + (mcu_x - 1)]; + } + } + let prediction = predict( + ra[i] as i32, + rb[i] as i32, + rc[i] as i32, + scan.predictor_selection, + scan.point_transform, + frame.precision, + mcu_x, + mcu_y, + self.restart_interval > 0 + && mcus_left_until_restart == self.restart_interval - 1, + ); + let result = ((prediction + diff) & 0xFFFF) as u16; // modulo 2^16 + results[i][mcu_y * width + mcu_x] = result << scan.point_transform; + } + } + } + } + + let mut marker = huffman.take_marker(&mut self.reader)?; + while let Some(Marker::RST(_)) = marker { + marker = self.read_marker().ok(); + } + Ok((marker, results)) + } +} + +/// H.1.2.1 +fn predict( + ra: i32, + rb: i32, + rc: i32, + predictor: Predictor, + point_transform: u8, + input_precision: u8, + ix: usize, + iy: usize, + restart: bool, +) -> i32 { + if (ix == 0 && iy == 0) || restart { + // start of first line or restart + if input_precision > 1 + point_transform { + 1 << (input_precision - point_transform - 1) + } else { + 0 + } + } else if iy == 0 { + // rest of first line + ra + } else if ix == 0 { + // start of other line + rb + } else { + // use predictor Table H.1 + match predictor { + Predictor::NoPrediction => 0, + Predictor::Ra => ra, + Predictor::Rb => rb, + Predictor::Rc => rc, + Predictor::RaRbRc1 => ra + rb - rc, + Predictor::RaRbRc2 => ra + ((rb - rc) >> 1), + Predictor::RaRbRc3 => rb + ((ra - rc) >> 1), + Predictor::RaRb => (ra + rb) / 2, + } + } +} + +pub fn compute_image_lossless(frame: &FrameInfo, mut data: Vec<Vec<u16>>) -> Result<Vec<u8>> { + if data.is_empty() || data.iter().any(Vec::is_empty) { + return Err(Error::Format("not all components have data".to_owned())); + } + let output_size = frame.output_size; + let components = &frame.components; + let ncomp = components.len(); + + if ncomp == 1 { + let decoded = convert_to_u8(frame, data.remove(0)); + Ok(decoded) + } else { + let mut decoded: Vec<u16> = + vec![0u16; ncomp * output_size.width as usize * output_size.height as usize]; + for (x, chunk) in decoded.chunks_mut(ncomp).enumerate() { + for (i, (component_data, _)) in data.iter().zip(components.iter()).enumerate() { + chunk[i] = component_data[x]; + } + } + let decoded = convert_to_u8(frame, decoded); + Ok(decoded) + } +} + +fn convert_to_u8(frame: &FrameInfo, data: Vec<u16>) -> Vec<u8> { + if frame.precision == 8 { + data.iter().map(|x| *x as u8).collect() + } else { + // we output native endian, which is the standard for image-rs + let ne_bytes: Vec<_> = data.iter().map(|x| x.to_ne_bytes()).collect(); + ne_bytes.concat() + } +} |