summaryrefslogtreecommitdiff
path: root/vendor/jpeg-decoder/src/decoder
diff options
context:
space:
mode:
authorValentin Popov <valentin@popov.link>2024-01-08 00:21:28 +0300
committerValentin Popov <valentin@popov.link>2024-01-08 00:21:28 +0300
commit1b6a04ca5504955c571d1c97504fb45ea0befee4 (patch)
tree7579f518b23313e8a9748a88ab6173d5e030b227 /vendor/jpeg-decoder/src/decoder
parent5ecd8cf2cba827454317368b68571df0d13d7842 (diff)
downloadfparkan-1b6a04ca5504955c571d1c97504fb45ea0befee4.tar.xz
fparkan-1b6a04ca5504955c571d1c97504fb45ea0befee4.zip
Initial vendor packages
Signed-off-by: Valentin Popov <valentin@popov.link>
Diffstat (limited to 'vendor/jpeg-decoder/src/decoder')
-rw-r--r--vendor/jpeg-decoder/src/decoder/lossless.rs259
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()
+ }
+}