| 1 | use alloc::borrow::ToOwned; |
| 2 | use alloc::{format, vec}; |
| 3 | use alloc::vec::Vec; |
| 4 | use core::ops::{self, Range}; |
| 5 | use std::io::{self, Read}; |
| 6 | use crate::{read_u16_from_be, read_u8}; |
| 7 | use crate::error::{Error, Result, UnsupportedFeature}; |
| 8 | use crate::huffman::{HuffmanTable, HuffmanTableClass}; |
| 9 | use crate::marker::Marker; |
| 10 | use crate::marker::Marker::*; |
| 11 | |
| 12 | #[derive (Clone, Copy, Debug, PartialEq)] |
| 13 | pub struct Dimensions { |
| 14 | pub width: u16, |
| 15 | pub height: u16, |
| 16 | } |
| 17 | |
| 18 | #[derive (Clone, Copy, Debug, PartialEq)] |
| 19 | pub enum EntropyCoding { |
| 20 | Huffman, |
| 21 | Arithmetic, |
| 22 | } |
| 23 | |
| 24 | /// Represents the coding process of an image. |
| 25 | #[derive (Clone, Copy, Debug, PartialEq)] |
| 26 | pub enum CodingProcess { |
| 27 | /// Sequential Discrete Cosine Transform |
| 28 | DctSequential, |
| 29 | /// Progressive Discrete Cosine Transform |
| 30 | DctProgressive, |
| 31 | /// Lossless |
| 32 | Lossless, |
| 33 | } |
| 34 | |
| 35 | // Table H.1 |
| 36 | #[derive (Clone, Copy, Debug, PartialEq)] |
| 37 | pub enum Predictor { |
| 38 | NoPrediction, |
| 39 | Ra, |
| 40 | Rb, |
| 41 | Rc, |
| 42 | RaRbRc1, // Ra + Rb - Rc |
| 43 | RaRbRc2, // Ra + ((Rb - Rc) >> 1) |
| 44 | RaRbRc3, // Rb + ((Ra - Rb) >> 1) |
| 45 | RaRb, // (Ra + Rb)/2 |
| 46 | } |
| 47 | |
| 48 | |
| 49 | #[derive (Clone)] |
| 50 | pub struct FrameInfo { |
| 51 | pub is_baseline: bool, |
| 52 | pub is_differential: bool, |
| 53 | pub coding_process: CodingProcess, |
| 54 | pub entropy_coding: EntropyCoding, |
| 55 | pub precision: u8, |
| 56 | |
| 57 | pub image_size: Dimensions, |
| 58 | pub output_size: Dimensions, |
| 59 | pub mcu_size: Dimensions, |
| 60 | pub components: Vec<Component>, |
| 61 | } |
| 62 | |
| 63 | #[derive (Debug)] |
| 64 | pub struct ScanInfo { |
| 65 | pub component_indices: Vec<usize>, |
| 66 | pub dc_table_indices: Vec<usize>, |
| 67 | pub ac_table_indices: Vec<usize>, |
| 68 | |
| 69 | pub spectral_selection: Range<u8>, |
| 70 | pub predictor_selection: Predictor, // for lossless |
| 71 | pub successive_approximation_high: u8, |
| 72 | pub successive_approximation_low: u8, |
| 73 | pub point_transform: u8, // for lossless |
| 74 | } |
| 75 | |
| 76 | #[derive (Clone, Debug)] |
| 77 | pub struct Component { |
| 78 | pub identifier: u8, |
| 79 | |
| 80 | pub horizontal_sampling_factor: u8, |
| 81 | pub vertical_sampling_factor: u8, |
| 82 | |
| 83 | pub quantization_table_index: usize, |
| 84 | |
| 85 | pub dct_scale: usize, |
| 86 | |
| 87 | pub size: Dimensions, |
| 88 | pub block_size: Dimensions, |
| 89 | } |
| 90 | |
| 91 | #[derive (Debug)] |
| 92 | pub enum AppData { |
| 93 | Adobe(AdobeColorTransform), |
| 94 | Jfif, |
| 95 | Avi1, |
| 96 | Icc(IccChunk), |
| 97 | Exif(Vec<u8>), |
| 98 | Xmp(Vec<u8>), |
| 99 | Psir(Vec<u8>), |
| 100 | } |
| 101 | |
| 102 | // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#Adobe |
| 103 | #[allow (clippy::upper_case_acronyms)] |
| 104 | #[derive (Clone, Copy, Debug, PartialEq)] |
| 105 | pub enum AdobeColorTransform { |
| 106 | // RGB or CMYK |
| 107 | Unknown, |
| 108 | YCbCr, |
| 109 | // YCbCrK |
| 110 | YCCK, |
| 111 | } |
| 112 | #[derive (Debug)] |
| 113 | pub struct IccChunk { |
| 114 | pub num_markers: u8, |
| 115 | pub seq_no: u8, |
| 116 | pub data: Vec<u8>, |
| 117 | } |
| 118 | |
| 119 | impl FrameInfo { |
| 120 | pub(crate) fn update_idct_size(&mut self, idct_size: usize) -> Result<()> { |
| 121 | for component: &mut Component in &mut self.components { |
| 122 | component.dct_scale = idct_size; |
| 123 | } |
| 124 | |
| 125 | update_component_sizes(self.image_size, &mut self.components)?; |
| 126 | |
| 127 | self.output_size = Dimensions { |
| 128 | width: (self.image_size.width as f32 * idct_size as f32 / 8.0).ceil() as u16, |
| 129 | height: (self.image_size.height as f32 * idct_size as f32 / 8.0).ceil() as u16 |
| 130 | }; |
| 131 | |
| 132 | Ok(()) |
| 133 | } |
| 134 | } |
| 135 | |
| 136 | fn read_length<R: Read>(reader: &mut R, marker: Marker) -> Result<usize> { |
| 137 | assert!(marker.has_length()); |
| 138 | |
| 139 | // length is including itself. |
| 140 | let length: usize = usize::from(read_u16_from_be(reader)?); |
| 141 | |
| 142 | if length < 2 { |
| 143 | return Err(Error::Format(format!("encountered {:?} with invalid length {}" , marker, length))); |
| 144 | } |
| 145 | |
| 146 | Ok(length - 2) |
| 147 | } |
| 148 | |
| 149 | fn skip_bytes<R: Read>(reader: &mut R, length: usize) -> Result<()> { |
| 150 | let length: u64 = length as u64; |
| 151 | let to_skip: &mut Take<&mut R> = &mut reader.by_ref().take(limit:length); |
| 152 | let copied: u64 = io::copy(reader:to_skip, &mut io::sink())?; |
| 153 | if copied < length { |
| 154 | Err(Error::Io(io::ErrorKind::UnexpectedEof.into())) |
| 155 | } else { |
| 156 | Ok(()) |
| 157 | } |
| 158 | } |
| 159 | |
| 160 | // Section B.2.2 |
| 161 | pub fn parse_sof<R: Read>(reader: &mut R, marker: Marker) -> Result<FrameInfo> { |
| 162 | let length = read_length(reader, marker)?; |
| 163 | |
| 164 | if length <= 6 { |
| 165 | return Err(Error::Format("invalid length in SOF" .to_owned())); |
| 166 | } |
| 167 | |
| 168 | let is_baseline = marker == SOF(0); |
| 169 | let is_differential = match marker { |
| 170 | SOF(0 ..= 3) | SOF(9 ..= 11) => false, |
| 171 | SOF(5 ..= 7) | SOF(13 ..= 15) => true, |
| 172 | _ => panic!(), |
| 173 | }; |
| 174 | let coding_process = match marker { |
| 175 | SOF(0) | SOF(1) | SOF(5) | SOF(9) | SOF(13) => CodingProcess::DctSequential, |
| 176 | SOF(2) | SOF(6) | SOF(10) | SOF(14) => CodingProcess::DctProgressive, |
| 177 | SOF(3) | SOF(7) | SOF(11) | SOF(15) => CodingProcess::Lossless, |
| 178 | _ => panic!(), |
| 179 | }; |
| 180 | let entropy_coding = match marker { |
| 181 | SOF(0 ..= 3) | SOF(5 ..= 7) => EntropyCoding::Huffman, |
| 182 | SOF(9 ..= 11) | SOF(13 ..= 15) => EntropyCoding::Arithmetic, |
| 183 | _ => panic!(), |
| 184 | }; |
| 185 | |
| 186 | let precision = read_u8(reader)?; |
| 187 | |
| 188 | match precision { |
| 189 | 8 => {}, |
| 190 | 12 => { |
| 191 | if is_baseline { |
| 192 | return Err(Error::Format("12 bit sample precision is not allowed in baseline" .to_owned())); |
| 193 | } |
| 194 | }, |
| 195 | _ => { |
| 196 | if coding_process != CodingProcess::Lossless || precision > 16 { |
| 197 | return Err(Error::Format(format!("invalid precision {} in frame header" , precision))) |
| 198 | } |
| 199 | }, |
| 200 | } |
| 201 | |
| 202 | let height = read_u16_from_be(reader)?; |
| 203 | let width = read_u16_from_be(reader)?; |
| 204 | |
| 205 | // height: |
| 206 | // "Value 0 indicates that the number of lines shall be defined by the DNL marker and |
| 207 | // parameters at the end of the first scan (see B.2.5)." |
| 208 | if height == 0 { |
| 209 | return Err(Error::Unsupported(UnsupportedFeature::DNL)); |
| 210 | } |
| 211 | |
| 212 | if width == 0 { |
| 213 | return Err(Error::Format("zero width in frame header" .to_owned())); |
| 214 | } |
| 215 | |
| 216 | let component_count = read_u8(reader)?; |
| 217 | |
| 218 | if component_count == 0 { |
| 219 | return Err(Error::Format("zero component count in frame header" .to_owned())); |
| 220 | } |
| 221 | if coding_process == CodingProcess::DctProgressive && component_count > 4 { |
| 222 | return Err(Error::Format("progressive frame with more than 4 components" .to_owned())); |
| 223 | } |
| 224 | |
| 225 | if length != 6 + 3 * component_count as usize { |
| 226 | return Err(Error::Format("invalid length in SOF" .to_owned())); |
| 227 | } |
| 228 | |
| 229 | let mut components: Vec<Component> = Vec::with_capacity(component_count as usize); |
| 230 | |
| 231 | for _ in 0 .. component_count { |
| 232 | let identifier = read_u8(reader)?; |
| 233 | |
| 234 | // Each component's identifier must be unique. |
| 235 | if components.iter().any(|c| c.identifier == identifier) { |
| 236 | return Err(Error::Format(format!("duplicate frame component identifier {}" , identifier))); |
| 237 | } |
| 238 | |
| 239 | let byte = read_u8(reader)?; |
| 240 | let horizontal_sampling_factor = byte >> 4; |
| 241 | let vertical_sampling_factor = byte & 0x0f; |
| 242 | |
| 243 | if horizontal_sampling_factor == 0 || horizontal_sampling_factor > 4 { |
| 244 | return Err(Error::Format(format!("invalid horizontal sampling factor {}" , horizontal_sampling_factor))); |
| 245 | } |
| 246 | if vertical_sampling_factor == 0 || vertical_sampling_factor > 4 { |
| 247 | return Err(Error::Format(format!("invalid vertical sampling factor {}" , vertical_sampling_factor))); |
| 248 | } |
| 249 | |
| 250 | let quantization_table_index = read_u8(reader)?; |
| 251 | |
| 252 | if quantization_table_index > 3 || (coding_process == CodingProcess::Lossless && quantization_table_index != 0) { |
| 253 | return Err(Error::Format(format!("invalid quantization table index {}" , quantization_table_index))); |
| 254 | } |
| 255 | |
| 256 | components.push(Component { |
| 257 | identifier, |
| 258 | horizontal_sampling_factor, |
| 259 | vertical_sampling_factor, |
| 260 | quantization_table_index: quantization_table_index as usize, |
| 261 | dct_scale: 8, |
| 262 | size: Dimensions {width: 0, height: 0}, |
| 263 | block_size: Dimensions {width: 0, height: 0}, |
| 264 | }); |
| 265 | } |
| 266 | |
| 267 | let mcu_size = update_component_sizes(Dimensions { width, height }, &mut components)?; |
| 268 | |
| 269 | Ok(FrameInfo { |
| 270 | is_baseline, |
| 271 | is_differential, |
| 272 | coding_process, |
| 273 | entropy_coding, |
| 274 | precision, |
| 275 | image_size: Dimensions { width, height }, |
| 276 | output_size: Dimensions { width, height }, |
| 277 | mcu_size, |
| 278 | components, |
| 279 | }) |
| 280 | } |
| 281 | |
| 282 | /// Returns ceil(x/y), requires x>0 |
| 283 | fn ceil_div(x: u32, y: u32) -> Result<u16> { |
| 284 | if x == 0 || y == 0 { |
| 285 | // TODO Determine how this error is reached. Can we validate input |
| 286 | // earlier and error out then? |
| 287 | return Err(Error::Format("invalid dimensions" .to_owned())); |
| 288 | } |
| 289 | Ok((1 + ((x - 1) / y)) as u16) |
| 290 | } |
| 291 | |
| 292 | fn update_component_sizes(size: Dimensions, components: &mut [Component]) -> Result<Dimensions> { |
| 293 | let h_max: u32 = components.iter().map(|c: &Component| c.horizontal_sampling_factor).max().unwrap() as u32; |
| 294 | let v_max: u32 = components.iter().map(|c: &Component| c.vertical_sampling_factor).max().unwrap() as u32; |
| 295 | |
| 296 | let mcu_size: Dimensions = Dimensions { |
| 297 | width: ceil_div(x:size.width as u32, y:h_max * 8)?, |
| 298 | height: ceil_div(x:size.height as u32, y:v_max * 8)?, |
| 299 | }; |
| 300 | |
| 301 | for component: &mut Component in components { |
| 302 | component.size.width = ceil_div(x:size.width as u32 * component.horizontal_sampling_factor as u32 * component.dct_scale as u32, y:h_max * 8)?; |
| 303 | component.size.height = ceil_div(x:size.height as u32 * component.vertical_sampling_factor as u32 * component.dct_scale as u32, y:v_max * 8)?; |
| 304 | |
| 305 | component.block_size.width = mcu_size.width * component.horizontal_sampling_factor as u16; |
| 306 | component.block_size.height = mcu_size.height * component.vertical_sampling_factor as u16; |
| 307 | } |
| 308 | |
| 309 | Ok(mcu_size) |
| 310 | } |
| 311 | |
| 312 | #[test ] |
| 313 | fn test_update_component_sizes() { |
| 314 | let mut components = [Component { |
| 315 | identifier: 1, |
| 316 | horizontal_sampling_factor: 2, |
| 317 | vertical_sampling_factor: 2, |
| 318 | quantization_table_index: 0, |
| 319 | dct_scale: 8, |
| 320 | size: Dimensions { width: 0, height: 0 }, |
| 321 | block_size: Dimensions { width: 0, height: 0 }, |
| 322 | }]; |
| 323 | let mcu = update_component_sizes( |
| 324 | Dimensions { width: 800, height: 280 }, |
| 325 | &mut components).unwrap(); |
| 326 | assert_eq!(mcu, Dimensions { width: 50, height: 18 }); |
| 327 | assert_eq!(components[0].block_size, Dimensions { width: 100, height: 36 }); |
| 328 | assert_eq!(components[0].size, Dimensions { width: 800, height: 280 }); |
| 329 | } |
| 330 | |
| 331 | // Section B.2.3 |
| 332 | pub fn parse_sos<R: Read>(reader: &mut R, frame: &FrameInfo) -> Result<ScanInfo> { |
| 333 | let length = read_length(reader, SOS)?; |
| 334 | if 0 == length { |
| 335 | return Err(Error::Format("zero length in SOS" .to_owned())); |
| 336 | } |
| 337 | |
| 338 | let component_count = read_u8(reader)?; |
| 339 | |
| 340 | if component_count == 0 || component_count > 4 { |
| 341 | return Err(Error::Format(format!("invalid component count {} in scan header" , component_count))); |
| 342 | } |
| 343 | |
| 344 | if length != 4 + 2 * component_count as usize { |
| 345 | return Err(Error::Format("invalid length in SOS" .to_owned())); |
| 346 | } |
| 347 | |
| 348 | let mut component_indices = Vec::with_capacity(component_count as usize); |
| 349 | let mut dc_table_indices = Vec::with_capacity(component_count as usize); |
| 350 | let mut ac_table_indices = Vec::with_capacity(component_count as usize); |
| 351 | |
| 352 | for _ in 0 .. component_count { |
| 353 | let identifier = read_u8(reader)?; |
| 354 | |
| 355 | let component_index = match frame.components.iter().position(|c| c.identifier == identifier) { |
| 356 | Some(value) => value, |
| 357 | None => return Err(Error::Format(format!("scan component identifier {} does not match any of the component identifiers defined in the frame" , identifier))), |
| 358 | }; |
| 359 | |
| 360 | // Each of the scan's components must be unique. |
| 361 | if component_indices.contains(&component_index) { |
| 362 | return Err(Error::Format(format!("duplicate scan component identifier {}" , identifier))); |
| 363 | } |
| 364 | |
| 365 | // "... the ordering in the scan header shall follow the ordering in the frame header." |
| 366 | if component_index < *component_indices.iter().max().unwrap_or(&0) { |
| 367 | return Err(Error::Format("the scan component order does not follow the order in the frame header" .to_owned())); |
| 368 | } |
| 369 | |
| 370 | let byte = read_u8(reader)?; |
| 371 | let dc_table_index = byte >> 4; |
| 372 | let ac_table_index = byte & 0x0f; |
| 373 | |
| 374 | if dc_table_index > 3 || (frame.is_baseline && dc_table_index > 1) { |
| 375 | return Err(Error::Format(format!("invalid dc table index {}" , dc_table_index))); |
| 376 | } |
| 377 | if ac_table_index > 3 || (frame.is_baseline && ac_table_index > 1) { |
| 378 | return Err(Error::Format(format!("invalid ac table index {}" , ac_table_index))); |
| 379 | } |
| 380 | |
| 381 | component_indices.push(component_index); |
| 382 | dc_table_indices.push(dc_table_index as usize); |
| 383 | ac_table_indices.push(ac_table_index as usize); |
| 384 | } |
| 385 | |
| 386 | let blocks_per_mcu = component_indices.iter().map(|&i| { |
| 387 | frame.components[i].horizontal_sampling_factor as u32 * frame.components[i].vertical_sampling_factor as u32 |
| 388 | }).fold(0, ops::Add::add); |
| 389 | |
| 390 | if component_count > 1 && blocks_per_mcu > 10 { |
| 391 | return Err(Error::Format("scan with more than one component and more than 10 blocks per MCU" .to_owned())); |
| 392 | } |
| 393 | |
| 394 | // Also utilized as 'Predictor' in lossless coding, as MEAN in JPEG-LS etc. |
| 395 | let spectral_selection_start = read_u8(reader)?; |
| 396 | // Also utilized as ILV parameter in JPEG-LS. |
| 397 | let mut spectral_selection_end = read_u8(reader)?; |
| 398 | |
| 399 | let byte = read_u8(reader)?; |
| 400 | let successive_approximation_high = byte >> 4; |
| 401 | let successive_approximation_low = byte & 0x0f; |
| 402 | |
| 403 | // The Differential Pulse-Mode prediction used (similar to png). Only utilized in Lossless |
| 404 | // coding. Don't confuse with the JPEG-LS parameter coded using the same scan info portion. |
| 405 | let predictor_selection; |
| 406 | let point_transform = successive_approximation_low; |
| 407 | |
| 408 | if frame.coding_process == CodingProcess::DctProgressive { |
| 409 | predictor_selection = Predictor::NoPrediction; |
| 410 | if spectral_selection_end > 63 || spectral_selection_start > spectral_selection_end || |
| 411 | (spectral_selection_start == 0 && spectral_selection_end != 0) { |
| 412 | return Err(Error::Format(format!("invalid spectral selection parameters: ss= {}, se= {}" , spectral_selection_start, spectral_selection_end))); |
| 413 | } |
| 414 | if spectral_selection_start != 0 && component_count != 1 { |
| 415 | return Err(Error::Format("spectral selection scan with AC coefficients can't have more than one component" .to_owned())); |
| 416 | } |
| 417 | |
| 418 | if successive_approximation_high > 13 || successive_approximation_low > 13 { |
| 419 | return Err(Error::Format(format!("invalid successive approximation parameters: ah= {}, al= {}" , successive_approximation_high, successive_approximation_low))); |
| 420 | } |
| 421 | |
| 422 | // Section G.1.1.1.2 |
| 423 | // "Each scan which follows the first scan for a given band progressively improves |
| 424 | // the precision of the coefficients by one bit, until full precision is reached." |
| 425 | if successive_approximation_high != 0 && successive_approximation_high != successive_approximation_low + 1 { |
| 426 | return Err(Error::Format("successive approximation scan with more than one bit of improvement" .to_owned())); |
| 427 | } |
| 428 | } |
| 429 | else if frame.coding_process == CodingProcess::Lossless { |
| 430 | if spectral_selection_end != 0 { |
| 431 | return Err(Error::Format("spectral selection end shall be zero in lossless scan" .to_owned())); |
| 432 | } |
| 433 | if successive_approximation_high != 0 { |
| 434 | return Err(Error::Format("successive approximation high shall be zero in lossless scan" .to_owned())); |
| 435 | } |
| 436 | predictor_selection = match spectral_selection_start { |
| 437 | 0 => Predictor::NoPrediction, |
| 438 | 1 => Predictor::Ra, |
| 439 | 2 => Predictor::Rb, |
| 440 | 3 => Predictor::Rc, |
| 441 | 4 => Predictor::RaRbRc1, |
| 442 | 5 => Predictor::RaRbRc2, |
| 443 | 6 => Predictor::RaRbRc3, |
| 444 | 7 => Predictor::RaRb, |
| 445 | _ => { |
| 446 | return Err(Error::Format(format!("invalid predictor selection value: {}" , spectral_selection_start))); |
| 447 | }, |
| 448 | }; |
| 449 | } |
| 450 | else { |
| 451 | predictor_selection = Predictor::NoPrediction; |
| 452 | if spectral_selection_end == 0 { |
| 453 | spectral_selection_end = 63; |
| 454 | } |
| 455 | if spectral_selection_start != 0 || spectral_selection_end != 63 { |
| 456 | return Err(Error::Format("spectral selection is not allowed in non-progressive scan" .to_owned())); |
| 457 | } |
| 458 | if successive_approximation_high != 0 || successive_approximation_low != 0 { |
| 459 | return Err(Error::Format("successive approximation is not allowed in non-progressive scan" .to_owned())); |
| 460 | } |
| 461 | } |
| 462 | |
| 463 | Ok(ScanInfo { |
| 464 | component_indices, |
| 465 | dc_table_indices, |
| 466 | ac_table_indices, |
| 467 | spectral_selection: Range { |
| 468 | start: spectral_selection_start, |
| 469 | end: spectral_selection_end + 1, |
| 470 | }, |
| 471 | predictor_selection, |
| 472 | successive_approximation_high, |
| 473 | successive_approximation_low, |
| 474 | point_transform, |
| 475 | }) |
| 476 | } |
| 477 | |
| 478 | // Section B.2.4.1 |
| 479 | pub fn parse_dqt<R: Read>(reader: &mut R) -> Result<[Option<[u16; 64]>; 4]> { |
| 480 | let mut length = read_length(reader, DQT)?; |
| 481 | let mut tables = [None; 4]; |
| 482 | |
| 483 | // Each DQT segment may contain multiple quantization tables. |
| 484 | while length > 0 { |
| 485 | let byte = read_u8(reader)?; |
| 486 | let precision = (byte >> 4) as usize; |
| 487 | let index = (byte & 0x0f) as usize; |
| 488 | |
| 489 | // The combination of 8-bit sample precision and 16-bit quantization tables is explicitly |
| 490 | // disallowed by the JPEG spec: |
| 491 | // "An 8-bit DCT-based process shall not use a 16-bit precision quantization table." |
| 492 | // "Pq: Quantization table element precision – Specifies the precision of the Qk |
| 493 | // values. Value 0 indicates 8-bit Qk values; value 1 indicates 16-bit Qk values. Pq |
| 494 | // shall be zero for 8 bit sample precision P (see B.2.2)." |
| 495 | // libjpeg allows this behavior though, and there are images in the wild using it. So to |
| 496 | // match libjpeg's behavior we are deviating from the JPEG spec here. |
| 497 | if precision > 1 { |
| 498 | return Err(Error::Format(format!("invalid precision {} in DQT" , precision))); |
| 499 | } |
| 500 | if index > 3 { |
| 501 | return Err(Error::Format(format!("invalid destination identifier {} in DQT" , index))); |
| 502 | } |
| 503 | if length < 65 + 64 * precision { |
| 504 | return Err(Error::Format("invalid length in DQT" .to_owned())); |
| 505 | } |
| 506 | |
| 507 | let mut table = [0u16; 64]; |
| 508 | |
| 509 | for item in table.iter_mut() { |
| 510 | *item = match precision { |
| 511 | 0 => u16::from(read_u8(reader)?), |
| 512 | 1 => read_u16_from_be(reader)?, |
| 513 | _ => unreachable!(), |
| 514 | }; |
| 515 | } |
| 516 | |
| 517 | if table.iter().any(|&val| val == 0) { |
| 518 | return Err(Error::Format("quantization table contains element with a zero value" .to_owned())); |
| 519 | } |
| 520 | |
| 521 | tables[index] = Some(table); |
| 522 | length -= 65 + 64 * precision; |
| 523 | } |
| 524 | |
| 525 | Ok(tables) |
| 526 | } |
| 527 | |
| 528 | // Section B.2.4.2 |
| 529 | #[allow (clippy::type_complexity)] |
| 530 | pub fn parse_dht<R: Read>(reader: &mut R, is_baseline: Option<bool>) -> Result<(Vec<Option<HuffmanTable>>, Vec<Option<HuffmanTable>>)> { |
| 531 | let mut length = read_length(reader, DHT)?; |
| 532 | let mut dc_tables = vec![None, None, None, None]; |
| 533 | let mut ac_tables = vec![None, None, None, None]; |
| 534 | |
| 535 | // Each DHT segment may contain multiple huffman tables. |
| 536 | while length > 17 { |
| 537 | let byte = read_u8(reader)?; |
| 538 | let class = byte >> 4; |
| 539 | let index = (byte & 0x0f) as usize; |
| 540 | |
| 541 | if class != 0 && class != 1 { |
| 542 | return Err(Error::Format(format!("invalid class {} in DHT" , class))); |
| 543 | } |
| 544 | if is_baseline == Some(true) && index > 1 { |
| 545 | return Err(Error::Format("a maximum of two huffman tables per class are allowed in baseline" .to_owned())); |
| 546 | } |
| 547 | if index > 3 { |
| 548 | return Err(Error::Format(format!("invalid destination identifier {} in DHT" , index))); |
| 549 | } |
| 550 | |
| 551 | let mut counts = [0u8; 16]; |
| 552 | reader.read_exact(&mut counts)?; |
| 553 | |
| 554 | let size = counts.iter().map(|&val| val as usize).fold(0, ops::Add::add); |
| 555 | |
| 556 | if size == 0 { |
| 557 | return Err(Error::Format("encountered table with zero length in DHT" .to_owned())); |
| 558 | } |
| 559 | else if size > 256 { |
| 560 | return Err(Error::Format("encountered table with excessive length in DHT" .to_owned())); |
| 561 | } |
| 562 | else if size > length - 17 { |
| 563 | return Err(Error::Format("invalid length in DHT" .to_owned())); |
| 564 | } |
| 565 | |
| 566 | let mut values = vec![0u8; size]; |
| 567 | reader.read_exact(&mut values)?; |
| 568 | |
| 569 | match class { |
| 570 | 0 => dc_tables[index] = Some(HuffmanTable::new(&counts, &values, HuffmanTableClass::DC)?), |
| 571 | 1 => ac_tables[index] = Some(HuffmanTable::new(&counts, &values, HuffmanTableClass::AC)?), |
| 572 | _ => unreachable!(), |
| 573 | } |
| 574 | |
| 575 | length -= 17 + size; |
| 576 | } |
| 577 | |
| 578 | if length != 0 { |
| 579 | return Err(Error::Format("invalid length in DHT" .to_owned())); |
| 580 | } |
| 581 | |
| 582 | Ok((dc_tables, ac_tables)) |
| 583 | } |
| 584 | |
| 585 | // Section B.2.4.4 |
| 586 | pub fn parse_dri<R: Read>(reader: &mut R) -> Result<u16> { |
| 587 | let length: usize = read_length(reader, marker:DRI)?; |
| 588 | |
| 589 | if length != 2 { |
| 590 | return Err(Error::Format("DRI with invalid length" .to_owned())); |
| 591 | } |
| 592 | |
| 593 | Ok(read_u16_from_be(reader)?) |
| 594 | } |
| 595 | |
| 596 | // Section B.2.4.5 |
| 597 | pub fn parse_com<R: Read>(reader: &mut R) -> Result<Vec<u8>> { |
| 598 | let length: usize = read_length(reader, marker:COM)?; |
| 599 | let mut buffer: Vec = vec![0u8; length]; |
| 600 | |
| 601 | reader.read_exact(&mut buffer)?; |
| 602 | |
| 603 | Ok(buffer) |
| 604 | } |
| 605 | |
| 606 | // Section B.2.4.6 |
| 607 | pub fn parse_app<R: Read>(reader: &mut R, marker: Marker) -> Result<Option<AppData>> { |
| 608 | let length = read_length(reader, marker)?; |
| 609 | let mut bytes_read = 0; |
| 610 | let mut result = None; |
| 611 | |
| 612 | match marker { |
| 613 | APP(0) => { |
| 614 | if length >= 5 { |
| 615 | let mut buffer = [0u8; 5]; |
| 616 | reader.read_exact(&mut buffer)?; |
| 617 | bytes_read = buffer.len(); |
| 618 | |
| 619 | // http://www.w3.org/Graphics/JPEG/jfif3.pdf |
| 620 | if buffer[0..5] == *b"JFIF \0" { |
| 621 | result = Some(AppData::Jfif); |
| 622 | // https://sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#AVI1 |
| 623 | } else if buffer[0..5] == *b"AVI1 \0" { |
| 624 | result = Some(AppData::Avi1); |
| 625 | } |
| 626 | } |
| 627 | } |
| 628 | APP(1) => { |
| 629 | let mut buffer = vec![0u8; length]; |
| 630 | reader.read_exact(&mut buffer)?; |
| 631 | bytes_read = buffer.len(); |
| 632 | |
| 633 | // https://web.archive.org/web/20190624045241if_/http://www.cipa.jp:80/std/documents/e/DC-008-Translation-2019-E.pdf |
| 634 | // 4.5.4 Basic Structure of JPEG Compressed Data |
| 635 | if length >= 6 && buffer[0..6] == *b"Exif \x00\x00" { |
| 636 | result = Some(AppData::Exif(buffer[6..].to_vec())); |
| 637 | } |
| 638 | // XMP packet |
| 639 | // https://github.com/adobe/XMP-Toolkit-SDK/blob/main/docs/XMPSpecificationPart3.pdf |
| 640 | else if length >= 29 && buffer[0..29] == *b"http://ns.adobe.com/xap/1.0/ \0" { |
| 641 | result = Some(AppData::Xmp(buffer[29..].to_vec())); |
| 642 | } |
| 643 | } |
| 644 | APP(2) => { |
| 645 | if length > 14 { |
| 646 | let mut buffer = [0u8; 14]; |
| 647 | reader.read_exact(&mut buffer)?; |
| 648 | bytes_read = buffer.len(); |
| 649 | |
| 650 | // http://www.color.org/ICC_Minor_Revision_for_Web.pdf |
| 651 | // B.4 Embedding ICC profiles in JFIF files |
| 652 | if buffer[0..12] == *b"ICC_PROFILE \0" { |
| 653 | let mut data = vec![0; length - bytes_read]; |
| 654 | reader.read_exact(&mut data)?; |
| 655 | bytes_read += data.len(); |
| 656 | result = Some(AppData::Icc(IccChunk { |
| 657 | seq_no: buffer[12], |
| 658 | num_markers: buffer[13], |
| 659 | data, |
| 660 | })); |
| 661 | } |
| 662 | } |
| 663 | } |
| 664 | APP(13) => { |
| 665 | if length >= 14 { |
| 666 | let mut buffer = [0u8; 14]; |
| 667 | reader.read_exact(&mut buffer)?; |
| 668 | bytes_read = buffer.len(); |
| 669 | |
| 670 | // PSIR (Photoshop) |
| 671 | // https://github.com/adobe/XMP-Toolkit-SDK/blob/main/docs/XMPSpecificationPart3.pdf |
| 672 | if buffer[0..14] == *b"Photoshop 3.0 \0" { |
| 673 | let mut data = vec![0; length - bytes_read]; |
| 674 | reader.read_exact(&mut data)?; |
| 675 | bytes_read += data.len(); |
| 676 | result = Some(AppData::Psir(data)); |
| 677 | } |
| 678 | } |
| 679 | } |
| 680 | APP(14) => { |
| 681 | if length >= 12 { |
| 682 | let mut buffer = [0u8; 12]; |
| 683 | reader.read_exact(&mut buffer)?; |
| 684 | bytes_read = buffer.len(); |
| 685 | |
| 686 | // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#Adobe |
| 687 | if buffer[0 .. 6] == *b"Adobe \0" { |
| 688 | let color_transform = match buffer[11] { |
| 689 | 0 => AdobeColorTransform::Unknown, |
| 690 | 1 => AdobeColorTransform::YCbCr, |
| 691 | 2 => AdobeColorTransform::YCCK, |
| 692 | _ => return Err(Error::Format("invalid color transform in adobe app segment" .to_owned())), |
| 693 | }; |
| 694 | |
| 695 | result = Some(AppData::Adobe(color_transform)); |
| 696 | } |
| 697 | } |
| 698 | }, |
| 699 | _ => {}, |
| 700 | } |
| 701 | |
| 702 | skip_bytes(reader, length - bytes_read)?; |
| 703 | Ok(result) |
| 704 | } |
| 705 | |