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