1use alloc::borrow::ToOwned;
2use alloc::{format, vec};
3use alloc::vec::Vec;
4use core::ops::{self, Range};
5use std::io::{self, Read};
6use crate::{read_u16_from_be, read_u8};
7use crate::error::{Error, Result, UnsupportedFeature};
8use crate::huffman::{HuffmanTable, HuffmanTableClass};
9use crate::marker::Marker;
10use crate::marker::Marker::*;
11
12#[derive(Clone, Copy, Debug, PartialEq)]
13pub struct Dimensions {
14 pub width: u16,
15 pub height: u16,
16}
17
18#[derive(Clone, Copy, Debug, PartialEq)]
19pub enum EntropyCoding {
20 Huffman,
21 Arithmetic,
22}
23
24#[derive(Clone, Copy, Debug, PartialEq)]
26pub enum CodingProcess {
27 DctSequential,
29 DctProgressive,
31 Lossless,
33}
34
35#[derive(Clone, Copy, Debug, PartialEq)]
37pub enum Predictor {
38 NoPrediction,
39 Ra,
40 Rb,
41 Rc,
42 RaRbRc1, RaRbRc2, RaRbRc3, RaRb, }
47
48
49#[derive(Clone)]
50pub 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)]
64pub 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, pub successive_approximation_high: u8,
72 pub successive_approximation_low: u8,
73 pub point_transform: u8, }
75
76#[derive(Clone, Debug)]
77pub 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)]
92pub 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#[allow(clippy::upper_case_acronyms)]
104#[derive(Clone, Copy, Debug, PartialEq)]
105pub enum AdobeColorTransform {
106 Unknown,
108 YCbCr,
109 YCCK,
111}
112#[derive(Debug)]
113pub struct IccChunk {
114 pub num_markers: u8,
115 pub seq_no: u8,
116 pub data: Vec<u8>,
117}
118
119impl FrameInfo {
120 pub(crate) fn update_idct_size(&mut self, idct_size: usize) -> Result<()> {
121 for 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
136fn read_length<R: Read>(reader: &mut R, marker: Marker) -> Result<usize> {
137 assert!(marker.has_length());
138
139 let length = 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
149fn skip_bytes<R: Read>(reader: &mut R, length: usize) -> Result<()> {
150 let length = length as u64;
151 let to_skip = &mut reader.by_ref().take(length);
152 let copied = io::copy(to_skip, &mut io::sink())?;
153 if copied < length {
154 Err(Error::Io(io::ErrorKind::UnexpectedEof.into()))
155 } else {
156 Ok(())
157 }
158}
159
160pub 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 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 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
282fn ceil_div(x: u32, y: u32) -> Result<u16> {
284 if x == 0 || y == 0 {
285 return Err(Error::Format("invalid dimensions".to_owned()));
288 }
289 Ok((1 + ((x - 1) / y)) as u16)
290}
291
292fn update_component_sizes(size: Dimensions, components: &mut [Component]) -> Result<Dimensions> {
293 let h_max = components.iter().map(|c| c.horizontal_sampling_factor).max().unwrap() as u32;
294 let v_max = components.iter().map(|c| c.vertical_sampling_factor).max().unwrap() as u32;
295
296 let mcu_size = Dimensions {
297 width: ceil_div(size.width as u32, h_max * 8)?,
298 height: ceil_div(size.height as u32, v_max * 8)?,
299 };
300
301 for component in components {
302 component.size.width = ceil_div(size.width as u32 * component.horizontal_sampling_factor as u32 * component.dct_scale as u32, h_max * 8)?;
303 component.size.height = ceil_div(size.height as u32 * component.vertical_sampling_factor as u32 * component.dct_scale as u32, 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]
313fn 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
331pub 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 if component_indices.contains(&component_index) {
362 return Err(Error::Format(format!("duplicate scan component identifier {}", identifier)));
363 }
364
365 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 let spectral_selection_start = read_u8(reader)?;
396 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 let predictor_selection;
406 let point_transform = successive_approximation_low;
407
408 if point_transform >= frame.precision {
409 return Err(Error::Format(
410 "invalid point transform, must be less than the frame precision".to_owned(),
411 ));
412 }
413
414 if frame.coding_process == CodingProcess::DctProgressive {
415 predictor_selection = Predictor::NoPrediction;
416 if spectral_selection_end > 63 || spectral_selection_start > spectral_selection_end ||
417 (spectral_selection_start == 0 && spectral_selection_end != 0) {
418 return Err(Error::Format(format!("invalid spectral selection parameters: ss={}, se={}", spectral_selection_start, spectral_selection_end)));
419 }
420 if spectral_selection_start != 0 && component_count != 1 {
421 return Err(Error::Format("spectral selection scan with AC coefficients can't have more than one component".to_owned()));
422 }
423
424 if successive_approximation_high > 13 || successive_approximation_low > 13 {
425 return Err(Error::Format(format!("invalid successive approximation parameters: ah={}, al={}", successive_approximation_high, successive_approximation_low)));
426 }
427
428 if successive_approximation_high != 0 && successive_approximation_high != successive_approximation_low + 1 {
432 return Err(Error::Format("successive approximation scan with more than one bit of improvement".to_owned()));
433 }
434 }
435 else if frame.coding_process == CodingProcess::Lossless {
436 if spectral_selection_end != 0 {
437 return Err(Error::Format("spectral selection end shall be zero in lossless scan".to_owned()));
438 }
439 if successive_approximation_high != 0 {
440 return Err(Error::Format("successive approximation high shall be zero in lossless scan".to_owned()));
441 }
442 predictor_selection = match spectral_selection_start {
443 0 => Predictor::NoPrediction,
444 1 => Predictor::Ra,
445 2 => Predictor::Rb,
446 3 => Predictor::Rc,
447 4 => Predictor::RaRbRc1,
448 5 => Predictor::RaRbRc2,
449 6 => Predictor::RaRbRc3,
450 7 => Predictor::RaRb,
451 _ => {
452 return Err(Error::Format(format!("invalid predictor selection value: {}", spectral_selection_start)));
453 },
454 };
455 }
456 else {
457 predictor_selection = Predictor::NoPrediction;
458 if spectral_selection_end == 0 {
459 spectral_selection_end = 63;
460 }
461 if spectral_selection_start != 0 || spectral_selection_end != 63 {
462 return Err(Error::Format("spectral selection is not allowed in non-progressive scan".to_owned()));
463 }
464 if successive_approximation_high != 0 || successive_approximation_low != 0 {
465 return Err(Error::Format("successive approximation is not allowed in non-progressive scan".to_owned()));
466 }
467 }
468
469 Ok(ScanInfo {
470 component_indices,
471 dc_table_indices,
472 ac_table_indices,
473 spectral_selection: Range {
474 start: spectral_selection_start,
475 end: spectral_selection_end + 1,
476 },
477 predictor_selection,
478 successive_approximation_high,
479 successive_approximation_low,
480 point_transform,
481 })
482}
483
484pub fn parse_dqt<R: Read>(reader: &mut R) -> Result<[Option<[u16; 64]>; 4]> {
486 let mut length = read_length(reader, DQT)?;
487 let mut tables = [None; 4];
488
489 while length > 0 {
491 let byte = read_u8(reader)?;
492 let precision = (byte >> 4) as usize;
493 let index = (byte & 0x0f) as usize;
494
495 if precision > 1 {
504 return Err(Error::Format(format!("invalid precision {} in DQT", precision)));
505 }
506 if index > 3 {
507 return Err(Error::Format(format!("invalid destination identifier {} in DQT", index)));
508 }
509 if length < 65 + 64 * precision {
510 return Err(Error::Format("invalid length in DQT".to_owned()));
511 }
512
513 let mut table = [0u16; 64];
514
515 for item in table.iter_mut() {
516 *item = match precision {
517 0 => u16::from(read_u8(reader)?),
518 1 => read_u16_from_be(reader)?,
519 _ => unreachable!(),
520 };
521 }
522
523 if table.iter().any(|&val| val == 0) {
524 return Err(Error::Format("quantization table contains element with a zero value".to_owned()));
525 }
526
527 tables[index] = Some(table);
528 length -= 65 + 64 * precision;
529 }
530
531 Ok(tables)
532}
533
534#[allow(clippy::type_complexity)]
536pub fn parse_dht<R: Read>(reader: &mut R, is_baseline: Option<bool>) -> Result<(Vec<Option<HuffmanTable>>, Vec<Option<HuffmanTable>>)> {
537 let mut length = read_length(reader, DHT)?;
538 let mut dc_tables = vec![None, None, None, None];
539 let mut ac_tables = vec![None, None, None, None];
540
541 while length > 17 {
543 let byte = read_u8(reader)?;
544 let class = byte >> 4;
545 let index = (byte & 0x0f) as usize;
546
547 if class != 0 && class != 1 {
548 return Err(Error::Format(format!("invalid class {} in DHT", class)));
549 }
550 if is_baseline == Some(true) && index > 1 {
551 return Err(Error::Format("a maximum of two huffman tables per class are allowed in baseline".to_owned()));
552 }
553 if index > 3 {
554 return Err(Error::Format(format!("invalid destination identifier {} in DHT", index)));
555 }
556
557 let mut counts = [0u8; 16];
558 reader.read_exact(&mut counts)?;
559
560 let size = counts.iter().map(|&val| val as usize).fold(0, ops::Add::add);
561
562 if size == 0 {
563 return Err(Error::Format("encountered table with zero length in DHT".to_owned()));
564 }
565 else if size > 256 {
566 return Err(Error::Format("encountered table with excessive length in DHT".to_owned()));
567 }
568 else if size > length - 17 {
569 return Err(Error::Format("invalid length in DHT".to_owned()));
570 }
571
572 let mut values = vec![0u8; size];
573 reader.read_exact(&mut values)?;
574
575 match class {
576 0 => dc_tables[index] = Some(HuffmanTable::new(&counts, &values, HuffmanTableClass::DC)?),
577 1 => ac_tables[index] = Some(HuffmanTable::new(&counts, &values, HuffmanTableClass::AC)?),
578 _ => unreachable!(),
579 }
580
581 length -= 17 + size;
582 }
583
584 if length != 0 {
585 return Err(Error::Format("invalid length in DHT".to_owned()));
586 }
587
588 Ok((dc_tables, ac_tables))
589}
590
591pub fn parse_dri<R: Read>(reader: &mut R) -> Result<u16> {
593 let length = read_length(reader, DRI)?;
594
595 if length != 2 {
596 return Err(Error::Format("DRI with invalid length".to_owned()));
597 }
598
599 Ok(read_u16_from_be(reader)?)
600}
601
602pub fn parse_com<R: Read>(reader: &mut R) -> Result<Vec<u8>> {
604 let length = read_length(reader, COM)?;
605 let mut buffer = vec![0u8; length];
606
607 reader.read_exact(&mut buffer)?;
608
609 Ok(buffer)
610}
611
612pub fn parse_app<R: Read>(reader: &mut R, marker: Marker) -> Result<Option<AppData>> {
614 let length = read_length(reader, marker)?;
615 let mut bytes_read = 0;
616 let mut result = None;
617
618 match marker {
619 APP(0) => {
620 if length >= 5 {
621 let mut buffer = [0u8; 5];
622 reader.read_exact(&mut buffer)?;
623 bytes_read = buffer.len();
624
625 if buffer[0..5] == *b"JFIF\0" {
627 result = Some(AppData::Jfif);
628 } else if buffer[0..5] == *b"AVI1\0" {
630 result = Some(AppData::Avi1);
631 }
632 }
633 }
634 APP(1) => {
635 let mut buffer = vec![0u8; length];
636 reader.read_exact(&mut buffer)?;
637 bytes_read = buffer.len();
638
639 if length >= 6 && buffer[0..6] == *b"Exif\x00\x00" {
642 result = Some(AppData::Exif(buffer[6..].to_vec()));
643 }
644 else if length >= 29 && buffer[0..29] == *b"http://ns.adobe.com/xap/1.0/\0" {
647 result = Some(AppData::Xmp(buffer[29..].to_vec()));
648 }
649 }
650 APP(2) => {
651 if length > 14 {
652 let mut buffer = [0u8; 14];
653 reader.read_exact(&mut buffer)?;
654 bytes_read = buffer.len();
655
656 if buffer[0..12] == *b"ICC_PROFILE\0" {
659 let mut data = vec![0; length - bytes_read];
660 reader.read_exact(&mut data)?;
661 bytes_read += data.len();
662 result = Some(AppData::Icc(IccChunk {
663 seq_no: buffer[12],
664 num_markers: buffer[13],
665 data,
666 }));
667 }
668 }
669 }
670 APP(13) => {
671 if length >= 14 {
672 let mut buffer = [0u8; 14];
673 reader.read_exact(&mut buffer)?;
674 bytes_read = buffer.len();
675
676 if buffer[0..14] == *b"Photoshop 3.0\0" {
679 let mut data = vec![0; length - bytes_read];
680 reader.read_exact(&mut data)?;
681 bytes_read += data.len();
682 result = Some(AppData::Psir(data));
683 }
684 }
685 }
686 APP(14) => {
687 if length >= 12 {
688 let mut buffer = [0u8; 12];
689 reader.read_exact(&mut buffer)?;
690 bytes_read = buffer.len();
691
692 if buffer[0 .. 6] == *b"Adobe\0" {
694 let color_transform = match buffer[11] {
695 0 => AdobeColorTransform::Unknown,
696 1 => AdobeColorTransform::YCbCr,
697 2 => AdobeColorTransform::YCCK,
698 _ => return Err(Error::Format("invalid color transform in adobe app segment".to_owned())),
699 };
700
701 result = Some(AppData::Adobe(color_transform));
702 }
703 }
704 },
705 _ => {},
706 }
707
708 skip_bytes(reader, length - bytes_read)?;
709 Ok(result)
710}