| 1 | use crate::decoder::{Decoder, MAX_COMPONENTS}; |
| 2 | use crate::error::{Error, Result}; |
| 3 | use crate::huffman::HuffmanDecoder; |
| 4 | use crate::marker::Marker; |
| 5 | use crate::parser::Predictor; |
| 6 | use crate::parser::{Component, FrameInfo, ScanInfo}; |
| 7 | use std::io::Read; |
| 8 | |
| 9 | impl<R: Read> Decoder<R> { |
| 10 | /// decode_scan_lossless |
| 11 | pub fn decode_scan_lossless( |
| 12 | &mut self, |
| 13 | frame: &FrameInfo, |
| 14 | scan: &ScanInfo, |
| 15 | ) -> Result<(Option<Marker>, Vec<Vec<u16>>)> { |
| 16 | let ncomp = scan.component_indices.len(); |
| 17 | let npixel = frame.image_size.height as usize * frame.image_size.width as usize; |
| 18 | assert!(ncomp <= MAX_COMPONENTS); |
| 19 | let mut results = vec![vec![0u16; npixel]; ncomp]; |
| 20 | |
| 21 | let components: Vec<Component> = scan |
| 22 | .component_indices |
| 23 | .iter() |
| 24 | .map(|&i| frame.components[i].clone()) |
| 25 | .collect(); |
| 26 | |
| 27 | // Verify that all required huffman tables has been set. |
| 28 | if scan |
| 29 | .dc_table_indices |
| 30 | .iter() |
| 31 | .any(|&i| self.dc_huffman_tables[i].is_none()) |
| 32 | { |
| 33 | return Err(Error::Format( |
| 34 | "scan makes use of unset dc huffman table" .to_owned(), |
| 35 | )); |
| 36 | } |
| 37 | |
| 38 | let mut huffman = HuffmanDecoder::new(); |
| 39 | let reader = &mut self.reader; |
| 40 | let mut mcus_left_until_restart = self.restart_interval; |
| 41 | let mut expected_rst_num = 0; |
| 42 | let mut ra = [0u16; MAX_COMPONENTS]; |
| 43 | let mut rb = [0u16; MAX_COMPONENTS]; |
| 44 | let mut rc = [0u16; MAX_COMPONENTS]; |
| 45 | |
| 46 | let width = frame.image_size.width as usize; |
| 47 | let height = frame.image_size.height as usize; |
| 48 | |
| 49 | let mut differences = vec![Vec::with_capacity(npixel); ncomp]; |
| 50 | for _mcu_y in 0..height { |
| 51 | for _mcu_x in 0..width { |
| 52 | if self.restart_interval > 0 { |
| 53 | if mcus_left_until_restart == 0 { |
| 54 | match huffman.take_marker(reader)? { |
| 55 | Some(Marker::RST(n)) => { |
| 56 | if n != expected_rst_num { |
| 57 | return Err(Error::Format(format!( |
| 58 | "found RST {} where RST {} was expected" , |
| 59 | n, expected_rst_num |
| 60 | ))); |
| 61 | } |
| 62 | |
| 63 | huffman.reset(); |
| 64 | |
| 65 | expected_rst_num = (expected_rst_num + 1) % 8; |
| 66 | mcus_left_until_restart = self.restart_interval; |
| 67 | } |
| 68 | Some(marker) => { |
| 69 | return Err(Error::Format(format!( |
| 70 | "found marker {:?} inside scan where RST {} was expected" , |
| 71 | marker, expected_rst_num |
| 72 | ))) |
| 73 | } |
| 74 | None => { |
| 75 | return Err(Error::Format(format!( |
| 76 | "no marker found where RST {} was expected" , |
| 77 | expected_rst_num |
| 78 | ))) |
| 79 | } |
| 80 | } |
| 81 | } |
| 82 | |
| 83 | mcus_left_until_restart -= 1; |
| 84 | } |
| 85 | |
| 86 | for (i, _component) in components.iter().enumerate() { |
| 87 | let dc_table = self.dc_huffman_tables[scan.dc_table_indices[i]] |
| 88 | .as_ref() |
| 89 | .unwrap(); |
| 90 | let value = huffman.decode(reader, dc_table)?; |
| 91 | let diff = match value { |
| 92 | 0 => 0, |
| 93 | 1..=15 => huffman.receive_extend(reader, value)? as i32, |
| 94 | 16 => 32768, |
| 95 | _ => { |
| 96 | // Section F.1.2.1.1 |
| 97 | // Table F.1 |
| 98 | return Err(Error::Format( |
| 99 | "invalid DC difference magnitude category" .to_owned(), |
| 100 | )); |
| 101 | } |
| 102 | }; |
| 103 | differences[i].push(diff); |
| 104 | } |
| 105 | } |
| 106 | } |
| 107 | |
| 108 | if scan.predictor_selection == Predictor::Ra { |
| 109 | for (i, _component) in components.iter().enumerate() { |
| 110 | // calculate the top left pixel |
| 111 | let diff = differences[i][0]; |
| 112 | let prediction = 1 << (frame.precision - scan.point_transform - 1) as i32; |
| 113 | let result = ((prediction + diff) & 0xFFFF) as u16; // modulo 2^16 |
| 114 | let result = result << scan.point_transform; |
| 115 | results[i][0] = result; |
| 116 | |
| 117 | // calculate leftmost column, using top pixel as predictor |
| 118 | let mut previous = result; |
| 119 | for mcu_y in 1..height { |
| 120 | let diff = differences[i][mcu_y * width]; |
| 121 | let prediction = previous as i32; |
| 122 | let result = ((prediction + diff) & 0xFFFF) as u16; // modulo 2^16 |
| 123 | let result = result << scan.point_transform; |
| 124 | results[i][mcu_y * width] = result; |
| 125 | previous = result; |
| 126 | } |
| 127 | |
| 128 | // calculate rows, using left pixel as predictor |
| 129 | for mcu_y in 0..height { |
| 130 | for mcu_x in 1..width { |
| 131 | let diff = differences[i][mcu_y * width + mcu_x]; |
| 132 | let prediction = results[i][mcu_y * width + mcu_x - 1] as i32; |
| 133 | let result = ((prediction + diff) & 0xFFFF) as u16; // modulo 2^16 |
| 134 | let result = result << scan.point_transform; |
| 135 | results[i][mcu_y * width + mcu_x] = result; |
| 136 | } |
| 137 | } |
| 138 | } |
| 139 | } else { |
| 140 | for mcu_y in 0..height { |
| 141 | for mcu_x in 0..width { |
| 142 | for (i, _component) in components.iter().enumerate() { |
| 143 | let diff = differences[i][mcu_y * width + mcu_x]; |
| 144 | |
| 145 | // The following lines could be further optimized, e.g. moving the checks |
| 146 | // and updates of the previous values into the prediction function or |
| 147 | // iterating such that diagonals with mcu_x + mcu_y = const are computed at |
| 148 | // the same time to exploit independent predictions in this case |
| 149 | if mcu_x > 0 { |
| 150 | ra[i] = results[i][mcu_y * frame.image_size.width as usize + mcu_x - 1]; |
| 151 | } |
| 152 | if mcu_y > 0 { |
| 153 | rb[i] = |
| 154 | results[i][(mcu_y - 1) * frame.image_size.width as usize + mcu_x]; |
| 155 | if mcu_x > 0 { |
| 156 | rc[i] = results[i] |
| 157 | [(mcu_y - 1) * frame.image_size.width as usize + (mcu_x - 1)]; |
| 158 | } |
| 159 | } |
| 160 | let prediction = predict( |
| 161 | ra[i] as i32, |
| 162 | rb[i] as i32, |
| 163 | rc[i] as i32, |
| 164 | scan.predictor_selection, |
| 165 | scan.point_transform, |
| 166 | frame.precision, |
| 167 | mcu_x, |
| 168 | mcu_y, |
| 169 | self.restart_interval > 0 |
| 170 | && mcus_left_until_restart == self.restart_interval - 1, |
| 171 | ); |
| 172 | let result = ((prediction + diff) & 0xFFFF) as u16; // modulo 2^16 |
| 173 | results[i][mcu_y * width + mcu_x] = result << scan.point_transform; |
| 174 | } |
| 175 | } |
| 176 | } |
| 177 | } |
| 178 | |
| 179 | let mut marker = huffman.take_marker(&mut self.reader)?; |
| 180 | while let Some(Marker::RST(_)) = marker { |
| 181 | marker = self.read_marker().ok(); |
| 182 | } |
| 183 | Ok((marker, results)) |
| 184 | } |
| 185 | } |
| 186 | |
| 187 | /// H.1.2.1 |
| 188 | #[allow (clippy::too_many_arguments)] |
| 189 | fn predict( |
| 190 | ra: i32, |
| 191 | rb: i32, |
| 192 | rc: i32, |
| 193 | predictor: Predictor, |
| 194 | point_transform: u8, |
| 195 | input_precision: u8, |
| 196 | ix: usize, |
| 197 | iy: usize, |
| 198 | restart: bool, |
| 199 | ) -> i32 { |
| 200 | if (ix == 0 && iy == 0) || restart { |
| 201 | // start of first line or restart |
| 202 | if input_precision > 1 + point_transform { |
| 203 | 1 << (input_precision - point_transform - 1) |
| 204 | } else { |
| 205 | 0 |
| 206 | } |
| 207 | } else if iy == 0 { |
| 208 | // rest of first line |
| 209 | ra |
| 210 | } else if ix == 0 { |
| 211 | // start of other line |
| 212 | rb |
| 213 | } else { |
| 214 | // use predictor Table H.1 |
| 215 | match predictor { |
| 216 | Predictor::NoPrediction => 0, |
| 217 | Predictor::Ra => ra, |
| 218 | Predictor::Rb => rb, |
| 219 | Predictor::Rc => rc, |
| 220 | Predictor::RaRbRc1 => ra + rb - rc, |
| 221 | Predictor::RaRbRc2 => ra + ((rb - rc) >> 1), |
| 222 | Predictor::RaRbRc3 => rb + ((ra - rc) >> 1), |
| 223 | Predictor::RaRb => (ra + rb) / 2, |
| 224 | } |
| 225 | } |
| 226 | } |
| 227 | |
| 228 | pub fn compute_image_lossless(frame: &FrameInfo, mut data: Vec<Vec<u16>>) -> Result<Vec<u8>> { |
| 229 | if data.is_empty() || data.iter().any(Vec::is_empty) { |
| 230 | return Err(Error::Format("not all components have data" .to_owned())); |
| 231 | } |
| 232 | let output_size: Dimensions = frame.output_size; |
| 233 | let components: &Vec = &frame.components; |
| 234 | let ncomp: usize = components.len(); |
| 235 | |
| 236 | if ncomp == 1 { |
| 237 | let decoded: Vec = convert_to_u8(frame, data.remove(index:0)); |
| 238 | Ok(decoded) |
| 239 | } else { |
| 240 | let mut decoded: Vec<u16> = |
| 241 | vec![0u16; ncomp * output_size.width as usize * output_size.height as usize]; |
| 242 | for (x: usize, chunk: &mut [u16]) in decoded.chunks_mut(chunk_size:ncomp).enumerate() { |
| 243 | for (i: usize, (component_data: &Vec, _)) in data.iter().zip(components.iter()).enumerate() { |
| 244 | chunk[i] = component_data[x]; |
| 245 | } |
| 246 | } |
| 247 | let decoded: Vec = convert_to_u8(frame, data:decoded); |
| 248 | Ok(decoded) |
| 249 | } |
| 250 | } |
| 251 | |
| 252 | fn convert_to_u8(frame: &FrameInfo, data: Vec<u16>) -> Vec<u8> { |
| 253 | if frame.precision == 8 { |
| 254 | data.iter().map(|x: &u16| *x as u8).collect() |
| 255 | } else { |
| 256 | // we output native endian, which is the standard for image-rs |
| 257 | let ne_bytes: Vec<_> = data.iter().map(|x: &u16| x.to_ne_bytes()).collect(); |
| 258 | ne_bytes.concat() |
| 259 | } |
| 260 | } |
| 261 | |