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