1use crate::error::{Error, Result, UnsupportedFeature};
2use crate::huffman::{HuffmanTable, HuffmanTableClass};
3use crate::marker::Marker;
4use crate::marker::Marker::*;
5use crate::{read_u8, read_u16_from_be};
6use alloc::borrow::ToOwned;
7use alloc::vec::Vec;
8use alloc::{format, vec};
9use core::ops::{self, Range};
10use std::io::{self, Read};
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)]
20pub enum EntropyCoding {
21 Huffman,
23 Arithmetic,
25}
26
27#[derive(Clone, Copy, Debug, PartialEq)]
29pub enum CodingProcess {
30 DctSequential,
32 DctProgressive,
34 Lossless,
36}
37
38#[derive(Clone, Copy, Debug, PartialEq)]
40pub enum Predictor {
41 NoPrediction,
42 Ra,
43 Rb,
44 Rc,
45 RaRbRc1, RaRbRc2, RaRbRc3, RaRb, }
50
51#[derive(Clone)]
53pub struct FrameInfo {
54 pub is_baseline: bool,
56 pub is_differential: bool,
58 pub coding_process: CodingProcess,
60 pub entropy_coding: EntropyCoding,
62 pub precision: u8,
64 pub image_size: Dimensions,
66 pub output_size: Dimensions,
68 pub mcu_size: Dimensions,
70 pub components: Vec<Component>,
72}
73
74#[derive(Debug)]
75pub struct ScanInfo {
76 pub component_indices: Vec<usize>,
77 pub dc_table_indices: Vec<usize>,
78 pub ac_table_indices: Vec<usize>,
79
80 pub spectral_selection: Range<u8>,
81 pub predictor_selection: Predictor, pub successive_approximation_high: u8,
83 pub successive_approximation_low: u8,
84 pub point_transform: u8, }
86
87#[derive(Clone, Debug)]
89pub struct Component {
90 pub identifier: u8,
92 pub horizontal_sampling_factor: u8,
94 pub vertical_sampling_factor: u8,
96 pub quantization_table_index: usize,
98 pub dct_scale: usize,
100 pub size: Dimensions,
102 pub block_size: Dimensions,
104}
105
106#[derive(Debug)]
107pub enum AppData {
108 Adobe(AdobeColorTransform),
109 Jfif,
110 Avi1,
111 Icc(IccChunk),
112 Exif(Vec<u8>),
113 Xmp(Vec<u8>),
114 Psir(Vec<u8>),
115}
116
117#[allow(clippy::upper_case_acronyms)]
119#[derive(Clone, Copy, Debug, PartialEq)]
120pub enum AdobeColorTransform {
121 Unknown,
123 YCbCr,
124 YCCK,
126}
127#[derive(Debug)]
128pub struct IccChunk {
129 pub num_markers: u8,
130 pub seq_no: u8,
131 pub data: Vec<u8>,
132}
133
134impl FrameInfo {
135 pub(crate) fn update_idct_size(&mut self, idct_size: usize) -> Result<()> {
136 for component in &mut self.components {
137 component.dct_scale = idct_size;
138 }
139
140 update_component_sizes(self.image_size, &mut self.components)?;
141
142 self.output_size = Dimensions {
143 width: (self.image_size.width as f32 * idct_size as f32 / 8.0).ceil() as u16,
144 height: (self.image_size.height as f32 * idct_size as f32 / 8.0).ceil() as u16,
145 };
146
147 Ok(())
148 }
149}
150
151fn read_length<R: Read>(reader: &mut R, marker: Marker) -> Result<usize> {
152 assert!(marker.has_length());
153
154 let length = usize::from(read_u16_from_be(reader)?);
156
157 if length < 2 {
158 return Err(Error::Format(format!(
159 "encountered {:?} with invalid length {}",
160 marker, length
161 )));
162 }
163
164 Ok(length - 2)
165}
166
167fn skip_bytes<R: Read>(reader: &mut R, length: usize) -> Result<()> {
168 let length = length as u64;
169 let to_skip = &mut reader.by_ref().take(length);
170 let copied = io::copy(to_skip, &mut io::sink())?;
171 if copied < length {
172 Err(Error::Io(io::ErrorKind::UnexpectedEof.into()))
173 } else {
174 Ok(())
175 }
176}
177
178pub fn parse_sof<R: Read>(reader: &mut R, marker: Marker) -> Result<FrameInfo> {
180 let length = read_length(reader, marker)?;
181
182 if length <= 6 {
183 return Err(Error::Format("invalid length in SOF".to_owned()));
184 }
185
186 let is_baseline = marker == SOF(0);
187 let is_differential = match marker {
188 SOF(0..=3) | SOF(9..=11) => false,
189 SOF(5..=7) | SOF(13..=15) => true,
190 _ => panic!(),
191 };
192 let coding_process = match marker {
193 SOF(0) | SOF(1) | SOF(5) | SOF(9) | SOF(13) => CodingProcess::DctSequential,
194 SOF(2) | SOF(6) | SOF(10) | SOF(14) => CodingProcess::DctProgressive,
195 SOF(3) | SOF(7) | SOF(11) | SOF(15) => CodingProcess::Lossless,
196 _ => panic!(),
197 };
198 let entropy_coding = match marker {
199 SOF(0..=3) | SOF(5..=7) => EntropyCoding::Huffman,
200 SOF(9..=11) | SOF(13..=15) => EntropyCoding::Arithmetic,
201 _ => panic!(),
202 };
203
204 let precision = read_u8(reader)?;
205
206 match precision {
207 8 => {}
208 12 => {
209 if is_baseline {
210 return Err(Error::Format(
211 "12 bit sample precision is not allowed in baseline".to_owned(),
212 ));
213 }
214 }
215 _ => {
216 if coding_process != CodingProcess::Lossless || precision > 16 {
217 return Err(Error::Format(format!(
218 "invalid precision {} in frame header",
219 precision
220 )));
221 }
222 }
223 }
224
225 let height = read_u16_from_be(reader)?;
226 let width = read_u16_from_be(reader)?;
227
228 if height == 0 {
232 return Err(Error::Unsupported(UnsupportedFeature::DNL));
233 }
234
235 if width == 0 {
236 return Err(Error::Format("zero width in frame header".to_owned()));
237 }
238
239 let component_count = read_u8(reader)?;
240
241 if component_count == 0 {
242 return Err(Error::Format(
243 "zero component count in frame header".to_owned(),
244 ));
245 }
246 if coding_process == CodingProcess::DctProgressive && component_count > 4 {
247 return Err(Error::Format(
248 "progressive frame with more than 4 components".to_owned(),
249 ));
250 }
251
252 if length != 6 + 3 * component_count as usize {
253 return Err(Error::Format("invalid length in SOF".to_owned()));
254 }
255
256 let mut components: Vec<Component> = Vec::with_capacity(component_count as usize);
257
258 for _ in 0..component_count {
259 let identifier = read_u8(reader)?;
260
261 if components.iter().any(|c| c.identifier == identifier) {
263 return Err(Error::Format(format!(
264 "duplicate frame component identifier {}",
265 identifier
266 )));
267 }
268
269 let byte = read_u8(reader)?;
270 let horizontal_sampling_factor = byte >> 4;
271 let vertical_sampling_factor = byte & 0x0f;
272
273 if horizontal_sampling_factor == 0 || horizontal_sampling_factor > 4 {
274 return Err(Error::Format(format!(
275 "invalid horizontal sampling factor {}",
276 horizontal_sampling_factor
277 )));
278 }
279 if vertical_sampling_factor == 0 || vertical_sampling_factor > 4 {
280 return Err(Error::Format(format!(
281 "invalid vertical sampling factor {}",
282 vertical_sampling_factor
283 )));
284 }
285
286 let quantization_table_index = read_u8(reader)?;
287
288 if quantization_table_index > 3
289 || (coding_process == CodingProcess::Lossless && quantization_table_index != 0)
290 {
291 return Err(Error::Format(format!(
292 "invalid quantization table index {}",
293 quantization_table_index
294 )));
295 }
296
297 components.push(Component {
298 identifier,
299 horizontal_sampling_factor,
300 vertical_sampling_factor,
301 quantization_table_index: quantization_table_index as usize,
302 dct_scale: 8,
303 size: Dimensions {
304 width: 0,
305 height: 0,
306 },
307 block_size: Dimensions {
308 width: 0,
309 height: 0,
310 },
311 });
312 }
313
314 let mcu_size = update_component_sizes(Dimensions { width, height }, &mut components)?;
315
316 Ok(FrameInfo {
317 is_baseline,
318 is_differential,
319 coding_process,
320 entropy_coding,
321 precision,
322 image_size: Dimensions { width, height },
323 output_size: Dimensions { width, height },
324 mcu_size,
325 components,
326 })
327}
328
329fn ceil_div(x: u32, y: u32) -> Result<u16> {
331 if x == 0 || y == 0 {
332 return Err(Error::Format("invalid dimensions".to_owned()));
335 }
336 Ok((1 + ((x - 1) / y)) as u16)
337}
338
339fn update_component_sizes(size: Dimensions, components: &mut [Component]) -> Result<Dimensions> {
340 let h_max = components
341 .iter()
342 .map(|c| c.horizontal_sampling_factor)
343 .max()
344 .unwrap() as u32;
345 let v_max = components
346 .iter()
347 .map(|c| c.vertical_sampling_factor)
348 .max()
349 .unwrap() as u32;
350
351 let mcu_size = Dimensions {
352 width: ceil_div(size.width as u32, h_max * 8)?,
353 height: ceil_div(size.height as u32, v_max * 8)?,
354 };
355
356 for component in components {
357 component.size.width = ceil_div(
358 size.width as u32
359 * component.horizontal_sampling_factor as u32
360 * component.dct_scale as u32,
361 h_max * 8,
362 )?;
363 component.size.height = ceil_div(
364 size.height as u32
365 * component.vertical_sampling_factor as u32
366 * component.dct_scale as u32,
367 v_max * 8,
368 )?;
369
370 component.block_size.width = mcu_size.width * component.horizontal_sampling_factor as u16;
371 component.block_size.height = mcu_size.height * component.vertical_sampling_factor as u16;
372 }
373
374 Ok(mcu_size)
375}
376
377#[test]
378fn test_update_component_sizes() {
379 let mut components = [Component {
380 identifier: 1,
381 horizontal_sampling_factor: 2,
382 vertical_sampling_factor: 2,
383 quantization_table_index: 0,
384 dct_scale: 8,
385 size: Dimensions {
386 width: 0,
387 height: 0,
388 },
389 block_size: Dimensions {
390 width: 0,
391 height: 0,
392 },
393 }];
394 let mcu = update_component_sizes(
395 Dimensions {
396 width: 800,
397 height: 280,
398 },
399 &mut components,
400 )
401 .unwrap();
402 assert_eq!(
403 mcu,
404 Dimensions {
405 width: 50,
406 height: 18
407 }
408 );
409 assert_eq!(
410 components[0].block_size,
411 Dimensions {
412 width: 100,
413 height: 36
414 }
415 );
416 assert_eq!(
417 components[0].size,
418 Dimensions {
419 width: 800,
420 height: 280
421 }
422 );
423}
424
425pub fn parse_sos<R: Read>(reader: &mut R, frame: &FrameInfo) -> Result<ScanInfo> {
427 let length = read_length(reader, SOS)?;
428 if 0 == length {
429 return Err(Error::Format("zero length in SOS".to_owned()));
430 }
431
432 let component_count = read_u8(reader)?;
433
434 if component_count == 0 || component_count > 4 {
435 return Err(Error::Format(format!(
436 "invalid component count {} in scan header",
437 component_count
438 )));
439 }
440
441 if length != 4 + 2 * component_count as usize {
442 return Err(Error::Format("invalid length in SOS".to_owned()));
443 }
444
445 let mut component_indices = Vec::with_capacity(component_count as usize);
446 let mut dc_table_indices = Vec::with_capacity(component_count as usize);
447 let mut ac_table_indices = Vec::with_capacity(component_count as usize);
448
449 for _ in 0..component_count {
450 let identifier = read_u8(reader)?;
451
452 let component_index = match frame
453 .components
454 .iter()
455 .position(|c| c.identifier == identifier)
456 {
457 Some(value) => value,
458 None => {
459 return Err(Error::Format(format!(
460 "scan component identifier {} does not match any of the component identifiers defined in the frame",
461 identifier
462 )));
463 }
464 };
465
466 if component_indices.contains(&component_index) {
468 return Err(Error::Format(format!(
469 "duplicate scan component identifier {}",
470 identifier
471 )));
472 }
473
474 if component_index < *component_indices.iter().max().unwrap_or(&0) {
476 return Err(Error::Format(
477 "the scan component order does not follow the order in the frame header".to_owned(),
478 ));
479 }
480
481 let byte = read_u8(reader)?;
482 let dc_table_index = byte >> 4;
483 let ac_table_index = byte & 0x0f;
484
485 if dc_table_index > 3 || (frame.is_baseline && dc_table_index > 1) {
486 return Err(Error::Format(format!(
487 "invalid dc table index {}",
488 dc_table_index
489 )));
490 }
491 if ac_table_index > 3 || (frame.is_baseline && ac_table_index > 1) {
492 return Err(Error::Format(format!(
493 "invalid ac table index {}",
494 ac_table_index
495 )));
496 }
497
498 component_indices.push(component_index);
499 dc_table_indices.push(dc_table_index as usize);
500 ac_table_indices.push(ac_table_index as usize);
501 }
502
503 let blocks_per_mcu = component_indices
504 .iter()
505 .map(|&i| {
506 frame.components[i].horizontal_sampling_factor as u32
507 * frame.components[i].vertical_sampling_factor as u32
508 })
509 .fold(0, ops::Add::add);
510
511 if component_count > 1 && blocks_per_mcu > 10 {
512 return Err(Error::Format(
513 "scan with more than one component and more than 10 blocks per MCU".to_owned(),
514 ));
515 }
516
517 let spectral_selection_start = read_u8(reader)?;
519 let mut spectral_selection_end = read_u8(reader)?;
521
522 let byte = read_u8(reader)?;
523 let successive_approximation_high = byte >> 4;
524 let successive_approximation_low = byte & 0x0f;
525
526 let predictor_selection;
529 let point_transform = successive_approximation_low;
530
531 if point_transform >= frame.precision {
532 return Err(Error::Format(
533 "invalid point transform, must be less than the frame precision".to_owned(),
534 ));
535 }
536
537 if frame.coding_process == CodingProcess::DctProgressive {
538 predictor_selection = Predictor::NoPrediction;
539 if spectral_selection_end > 63
540 || spectral_selection_start > spectral_selection_end
541 || (spectral_selection_start == 0 && spectral_selection_end != 0)
542 {
543 return Err(Error::Format(format!(
544 "invalid spectral selection parameters: ss={}, se={}",
545 spectral_selection_start, spectral_selection_end
546 )));
547 }
548 if spectral_selection_start != 0 && component_count != 1 {
549 return Err(Error::Format(
550 "spectral selection scan with AC coefficients can't have more than one component"
551 .to_owned(),
552 ));
553 }
554
555 if successive_approximation_high > 13 || successive_approximation_low > 13 {
556 return Err(Error::Format(format!(
557 "invalid successive approximation parameters: ah={}, al={}",
558 successive_approximation_high, successive_approximation_low
559 )));
560 }
561
562 if successive_approximation_high != 0
566 && successive_approximation_high != successive_approximation_low + 1
567 {
568 return Err(Error::Format(
569 "successive approximation scan with more than one bit of improvement".to_owned(),
570 ));
571 }
572 } else if frame.coding_process == CodingProcess::Lossless {
573 if spectral_selection_end != 0 {
574 return Err(Error::Format(
575 "spectral selection end shall be zero in lossless scan".to_owned(),
576 ));
577 }
578 if successive_approximation_high != 0 {
579 return Err(Error::Format(
580 "successive approximation high shall be zero in lossless scan".to_owned(),
581 ));
582 }
583 predictor_selection = match spectral_selection_start {
584 0 => Predictor::NoPrediction,
585 1 => Predictor::Ra,
586 2 => Predictor::Rb,
587 3 => Predictor::Rc,
588 4 => Predictor::RaRbRc1,
589 5 => Predictor::RaRbRc2,
590 6 => Predictor::RaRbRc3,
591 7 => Predictor::RaRb,
592 _ => {
593 return Err(Error::Format(format!(
594 "invalid predictor selection value: {}",
595 spectral_selection_start
596 )));
597 }
598 };
599 } else {
600 predictor_selection = Predictor::NoPrediction;
601 if spectral_selection_end == 0 {
602 spectral_selection_end = 63;
603 }
604 if spectral_selection_start != 0 || spectral_selection_end != 63 {
605 return Err(Error::Format(
606 "spectral selection is not allowed in non-progressive scan".to_owned(),
607 ));
608 }
609 if successive_approximation_high != 0 || successive_approximation_low != 0 {
610 return Err(Error::Format(
611 "successive approximation is not allowed in non-progressive scan".to_owned(),
612 ));
613 }
614 }
615
616 Ok(ScanInfo {
617 component_indices,
618 dc_table_indices,
619 ac_table_indices,
620 spectral_selection: Range {
621 start: spectral_selection_start,
622 end: spectral_selection_end + 1,
623 },
624 predictor_selection,
625 successive_approximation_high,
626 successive_approximation_low,
627 point_transform,
628 })
629}
630
631pub fn parse_dqt<R: Read>(reader: &mut R) -> Result<[Option<[u16; 64]>; 4]> {
633 let mut length = read_length(reader, DQT)?;
634 let mut tables = [None; 4];
635
636 while length > 0 {
638 let byte = read_u8(reader)?;
639 let precision = (byte >> 4) as usize;
640 let index = (byte & 0x0f) as usize;
641
642 if precision > 1 {
651 return Err(Error::Format(format!(
652 "invalid precision {} in DQT",
653 precision
654 )));
655 }
656 if index > 3 {
657 return Err(Error::Format(format!(
658 "invalid destination identifier {} in DQT",
659 index
660 )));
661 }
662 if length < 65 + 64 * precision {
663 return Err(Error::Format("invalid length in DQT".to_owned()));
664 }
665
666 let mut table = [0u16; 64];
667
668 for item in table.iter_mut() {
669 *item = match precision {
670 0 => u16::from(read_u8(reader)?),
671 1 => read_u16_from_be(reader)?,
672 _ => unreachable!(),
673 };
674 }
675
676 if table.contains(&0) {
677 return Err(Error::Format(
678 "quantization table contains element with a zero value".to_owned(),
679 ));
680 }
681
682 tables[index] = Some(table);
683 length -= 65 + 64 * precision;
684 }
685
686 Ok(tables)
687}
688
689#[allow(clippy::type_complexity)]
691pub fn parse_dht<R: Read>(
692 reader: &mut R,
693 is_baseline: Option<bool>,
694) -> Result<(Vec<Option<HuffmanTable>>, Vec<Option<HuffmanTable>>)> {
695 let mut length = read_length(reader, DHT)?;
696 let mut dc_tables = vec![None, None, None, None];
697 let mut ac_tables = vec![None, None, None, None];
698
699 while length > 17 {
701 let byte = read_u8(reader)?;
702 let class = byte >> 4;
703 let index = (byte & 0x0f) as usize;
704
705 if class != 0 && class != 1 {
706 return Err(Error::Format(format!("invalid class {} in DHT", class)));
707 }
708 if is_baseline == Some(true) && index > 1 {
709 return Err(Error::Format(
710 "a maximum of two huffman tables per class are allowed in baseline".to_owned(),
711 ));
712 }
713 if index > 3 {
714 return Err(Error::Format(format!(
715 "invalid destination identifier {} in DHT",
716 index
717 )));
718 }
719
720 let mut counts = [0u8; 16];
721 reader.read_exact(&mut counts)?;
722
723 let size = counts
724 .iter()
725 .map(|&val| val as usize)
726 .fold(0, ops::Add::add);
727
728 if size == 0 {
729 return Err(Error::Format(
730 "encountered table with zero length in DHT".to_owned(),
731 ));
732 } else if size > 256 {
733 return Err(Error::Format(
734 "encountered table with excessive length in DHT".to_owned(),
735 ));
736 } else if size > length - 17 {
737 return Err(Error::Format("invalid length in DHT".to_owned()));
738 }
739
740 let mut values = vec![0u8; size];
741 reader.read_exact(&mut values)?;
742
743 match class {
744 0 => {
745 dc_tables[index] = Some(HuffmanTable::new(&counts, &values, HuffmanTableClass::DC)?)
746 }
747 1 => {
748 ac_tables[index] = Some(HuffmanTable::new(&counts, &values, HuffmanTableClass::AC)?)
749 }
750 _ => unreachable!(),
751 }
752
753 length -= 17 + size;
754 }
755
756 if length != 0 {
757 return Err(Error::Format("invalid length in DHT".to_owned()));
758 }
759
760 Ok((dc_tables, ac_tables))
761}
762
763pub fn parse_dri<R: Read>(reader: &mut R) -> Result<u16> {
765 let length = read_length(reader, DRI)?;
766
767 if length != 2 {
768 return Err(Error::Format("DRI with invalid length".to_owned()));
769 }
770
771 Ok(read_u16_from_be(reader)?)
772}
773
774pub fn parse_com<R: Read>(reader: &mut R) -> Result<Vec<u8>> {
776 let length = read_length(reader, COM)?;
777 let mut buffer = vec![0u8; length];
778
779 reader.read_exact(&mut buffer)?;
780
781 Ok(buffer)
782}
783
784pub fn parse_app<R: Read>(reader: &mut R, marker: Marker) -> Result<Option<AppData>> {
786 let length = read_length(reader, marker)?;
787 let mut bytes_read = 0;
788 let mut result = None;
789
790 match marker {
791 APP(0) => {
792 if length >= 5 {
793 let mut buffer = [0u8; 5];
794 reader.read_exact(&mut buffer)?;
795 bytes_read = buffer.len();
796
797 if buffer[0..5] == *b"JFIF\0" {
799 result = Some(AppData::Jfif);
800 } else if buffer[0..5] == *b"AVI1\0" {
802 result = Some(AppData::Avi1);
803 }
804 }
805 }
806 APP(1) => {
807 let mut buffer = vec![0u8; length];
808 reader.read_exact(&mut buffer)?;
809 bytes_read = buffer.len();
810
811 if length >= 6 && buffer[0..6] == *b"Exif\x00\x00" {
814 result = Some(AppData::Exif(buffer[6..].to_vec()));
815 }
816 else if length >= 29 && buffer[0..29] == *b"http://ns.adobe.com/xap/1.0/\0" {
819 result = Some(AppData::Xmp(buffer[29..].to_vec()));
820 }
821 }
822 APP(2) => {
823 if length > 14 {
824 let mut buffer = [0u8; 14];
825 reader.read_exact(&mut buffer)?;
826 bytes_read = buffer.len();
827
828 if buffer[0..12] == *b"ICC_PROFILE\0" {
831 let mut data = vec![0; length - bytes_read];
832 reader.read_exact(&mut data)?;
833 bytes_read += data.len();
834 result = Some(AppData::Icc(IccChunk {
835 seq_no: buffer[12],
836 num_markers: buffer[13],
837 data,
838 }));
839 }
840 }
841 }
842 APP(13) => {
843 if length >= 14 {
844 let mut buffer = [0u8; 14];
845 reader.read_exact(&mut buffer)?;
846 bytes_read = buffer.len();
847
848 if buffer[0..14] == *b"Photoshop 3.0\0" {
851 let mut data = vec![0; length - bytes_read];
852 reader.read_exact(&mut data)?;
853 bytes_read += data.len();
854 result = Some(AppData::Psir(data));
855 }
856 }
857 }
858 APP(14) => {
859 if length >= 12 {
860 let mut buffer = [0u8; 12];
861 reader.read_exact(&mut buffer)?;
862 bytes_read = buffer.len();
863
864 if buffer[0..6] == *b"Adobe\0" {
866 let color_transform = match buffer[11] {
867 0 => AdobeColorTransform::Unknown,
868 1 => AdobeColorTransform::YCbCr,
869 2 => AdobeColorTransform::YCCK,
870 _ => {
871 return Err(Error::Format(
872 "invalid color transform in adobe app segment".to_owned(),
873 ));
874 }
875 };
876
877 result = Some(AppData::Adobe(color_transform));
878 }
879 }
880 }
881 _ => {}
882 }
883
884 skip_bytes(reader, length - bytes_read)?;
885 Ok(result)
886}