1#![allow(dead_code)]
11
12use alloc::format;
13use core::cmp::max;
14use core::fmt;
15use core::num::NonZeroU32;
16
17use zune_core::bytestream::ZByteReaderTrait;
18use zune_core::colorspace::ColorSpace;
19use zune_core::log::{trace, warn};
20
21use crate::components::{ComponentID, SampleRatios};
22use crate::errors::DecodeErrors;
23use crate::huffman::HuffmanTable;
24use crate::JpegDecoder;
25
26pub const START_OF_FRAME_BASE: u16 = 0xffc0;
29
30pub const START_OF_FRAME_EXT_SEQ: u16 = 0xffc1;
33
34pub const START_OF_FRAME_PROG_DCT: u16 = 0xffc2;
37
38pub const START_OF_FRAME_LOS_SEQ: u16 = 0xffc3;
41
42pub const START_OF_FRAME_EXT_AR: u16 = 0xffc9;
45
46pub const START_OF_FRAME_PROG_DCT_AR: u16 = 0xffca;
49
50pub const START_OF_FRAME_LOS_SEQ_AR: u16 = 0xffcb;
53
54#[rustfmt::skip]
58pub const UN_ZIGZAG: [usize; 64 + 16] = [
59 0, 1, 8, 16, 9, 2, 3, 10,
60 17, 24, 32, 25, 18, 11, 4, 5,
61 12, 19, 26, 33, 40, 48, 41, 34,
62 27, 20, 13, 6, 7, 14, 21, 28,
63 35, 42, 49, 56, 57, 50, 43, 36,
64 29, 22, 15, 23, 30, 37, 44, 51,
65 58, 59, 52, 45, 38, 31, 39, 46,
66 53, 60, 61, 54, 47, 55, 62, 63,
67 63, 63, 63, 63, 63, 63, 63, 63,
69 63, 63, 63, 63, 63, 63, 63, 63
70];
71
72#[repr(align(16))]
74#[derive(Clone)]
75
76pub struct Aligned16<T: ?Sized>(pub T);
77
78impl<T> Default for Aligned16<T>
79where
80 T: Default
81{
82 fn default() -> Self {
83 Aligned16(T::default())
84 }
85}
86
87#[repr(align(32))]
89#[derive(Clone)]
90pub struct Aligned32<T: ?Sized>(pub T);
91
92impl<T> Default for Aligned32<T>
93where
94 T: Default
95{
96 fn default() -> Self {
97 Aligned32(T::default())
98 }
99}
100
101#[derive(Eq, PartialEq, Copy, Clone)]
105#[allow(clippy::upper_case_acronyms)]
106pub enum SOFMarkers {
107 BaselineDct,
109 ExtendedSequentialHuffman,
111 ProgressiveDctHuffman,
113 LosslessHuffman,
115 ExtendedSequentialDctArithmetic,
117 ProgressiveDctArithmetic,
119 LosslessArithmetic
121}
122
123impl Default for SOFMarkers {
124 fn default() -> Self {
125 Self::BaselineDct
126 }
127}
128
129impl SOFMarkers {
130 pub fn is_sequential_dct(self) -> bool {
133 matches!(
134 self,
135 Self::BaselineDct
136 | Self::ExtendedSequentialHuffman
137 | Self::ExtendedSequentialDctArithmetic
138 )
139 }
140
141 pub fn is_lossless(self) -> bool {
144 matches!(self, Self::LosslessHuffman | Self::LosslessArithmetic)
145 }
146
147 pub fn is_progressive(self) -> bool {
150 matches!(
151 self,
152 Self::ProgressiveDctHuffman | Self::ProgressiveDctArithmetic
153 )
154 }
155
156 pub fn from_int(int: u16) -> Option<SOFMarkers> {
159 match int {
160 START_OF_FRAME_BASE => Some(Self::BaselineDct),
161 START_OF_FRAME_PROG_DCT => Some(Self::ProgressiveDctHuffman),
162 START_OF_FRAME_PROG_DCT_AR => Some(Self::ProgressiveDctArithmetic),
163 START_OF_FRAME_LOS_SEQ => Some(Self::LosslessHuffman),
164 START_OF_FRAME_LOS_SEQ_AR => Some(Self::LosslessArithmetic),
165 START_OF_FRAME_EXT_SEQ => Some(Self::ExtendedSequentialHuffman),
166 START_OF_FRAME_EXT_AR => Some(Self::ExtendedSequentialDctArithmetic),
167 _ => None
168 }
169 }
170}
171
172impl fmt::Debug for SOFMarkers {
173 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
174 match &self {
175 Self::BaselineDct => write!(f, "Baseline DCT"),
176 Self::ExtendedSequentialHuffman => {
177 write!(f, "Extended sequential DCT, Huffman Coding")
178 }
179 Self::ProgressiveDctHuffman => write!(f, "Progressive DCT,Huffman Encoding"),
180 Self::LosslessHuffman => write!(f, "Lossless (sequential) Huffman encoding"),
181 Self::ExtendedSequentialDctArithmetic => {
182 write!(f, "Extended sequential DCT, arithmetic coding")
183 }
184 Self::ProgressiveDctArithmetic => write!(f, "Progressive DCT, arithmetic coding"),
185 Self::LosslessArithmetic => write!(f, "Lossless (sequential) arithmetic coding")
186 }
187 }
188}
189
190pub(crate) fn setup_component_params<T: ZByteReaderTrait>(
195 img: &mut JpegDecoder<T>
196) -> Result<(), DecodeErrors> {
197 let img_width = img.width();
198 let img_height = img.height();
199
200 if img.components.len() == 3 && img.input_colorspace == ColorSpace::CMYK {
210 img.input_colorspace = ColorSpace::RGB;
211 }
212
213 for component in &mut img.components {
214 img.h_max = max(img.h_max, component.horizontal_sample);
217 img.v_max = max(img.v_max, component.vertical_sample);
219 img.mcu_width = img.h_max * 8;
220 img.mcu_height = img.v_max * 8;
221 img.mcu_x = usize::from(img.info.width).div_ceil(img.mcu_width);
223 img.mcu_y = usize::from(img.info.height).div_ceil(img.mcu_height);
225
226 if img.h_max != 1 || img.v_max != 1 {
227 img.is_interleaved = true;
230 }
231 let qt_table = *img.qt_tables[component.quantization_table_number as usize]
233 .as_ref()
234 .ok_or_else(|| {
235 DecodeErrors::DqtError(format!(
236 "No quantization table for component {:?}",
237 component.component_id
238 ))
239 })?;
240
241 let x = (usize::from(img_width) * component.horizontal_sample + img.h_max - 1) / img.h_max;
242 let y = (usize::from(img_height) * component.horizontal_sample + img.h_max - 1) / img.v_max;
243 component.x = x;
244 component.w2 = img.mcu_x * component.horizontal_sample * 8;
245 component.y = y;
247 component.quantization_table = qt_table;
248 component.width_stride *= img.mcu_x * 8;
250 }
251 {
252 let mut handle_that_annoying_bug = false;
269
270 if let Some(y_component) = img
271 .components
272 .iter()
273 .find(|c| c.component_id == ComponentID::Y)
274 {
275 if y_component.horizontal_sample == 2 || y_component.vertical_sample == 2 {
276 handle_that_annoying_bug = true;
277 }
278 }
279 if handle_that_annoying_bug {
280 for comp in &mut img.components {
281 if (comp.component_id != ComponentID::Y)
282 && (comp.horizontal_sample != 1 || comp.vertical_sample != 1)
283 {
284 comp.fix_an_annoying_bug = 2;
285 }
286 }
287 }
288 }
289
290 if img.is_mjpeg {
291 fill_default_mjpeg_tables(
292 img.is_progressive,
293 &mut img.dc_huffman_tables,
294 &mut img.ac_huffman_tables
295 );
296 }
297
298 if img.input_colorspace.num_components() > img.components.len() {
300 if img.input_colorspace == ColorSpace::YCCK {
301 warn!("Treating YCCK colorspace as YCbCr as component length does not match");
309 img.input_colorspace = ColorSpace::YCbCr
310 } else {
311 if !img.options.strict_mode() {
320 warn!(
321 "Expected {} number of components but found {}",
322 img.input_colorspace.num_components(),
323 img.components.len()
324 );
325 warn!("Defaulting to multisample to decode");
326
327 if img.components.len() > 0 {
331 img.input_colorspace = ColorSpace::MultiBand(
332 NonZeroU32::new(img.components.len() as u32).unwrap()
333 );
334 }
335 } else {
336 let msg = format!(
337 "Expected {} number of components but found {}",
338 img.input_colorspace.num_components(),
339 img.components.len()
340 );
341
342 return Err(DecodeErrors::Format(msg));
343 }
344 }
345 }
346 Ok(())
347}
348
349pub fn calculate_padded_width(actual_width: usize, sub_sample: SampleRatios) -> usize {
363 match sub_sample {
364 SampleRatios::None | SampleRatios::V => {
365 ((actual_width + 7) / 8) * 8
367 }
368 SampleRatios::H | SampleRatios::HV => {
369 ((actual_width + 15) / 16) * 16
371 }
372 SampleRatios::Generic(h, _) => {
373 ((actual_width + ((h * 8).saturating_sub(1))) / (h * 8)) * (h * 8)
374 }
375 }
376}
377
378pub fn fill_default_mjpeg_tables(
387 is_progressive: bool, dc_huffman_tables: &mut [Option<HuffmanTable>],
388 ac_huffman_tables: &mut [Option<HuffmanTable>]
389) {
390 trace!("Filling with default mjpeg tables");
392
393 if dc_huffman_tables[0].is_none() {
394 dc_huffman_tables[0] = Some(
396 HuffmanTable::new_unfilled(
397 &[
398 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
399 0x00, 0x00, 0x00, 0x00
400 ],
401 &[
402 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B
403 ],
404 true,
405 is_progressive
406 )
407 .unwrap()
408 );
409 }
410 if dc_huffman_tables[1].is_none() {
411 dc_huffman_tables[1] = Some(
413 HuffmanTable::new_unfilled(
414 &[
415 0x00, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00,
416 0x00, 0x00, 0x00, 0x00
417 ],
418 &[
419 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B
420 ],
421 true,
422 is_progressive
423 )
424 .unwrap()
425 );
426 }
427 if ac_huffman_tables[0].is_none() {
428 ac_huffman_tables[0] = Some(
430 HuffmanTable::new_unfilled(
431 &[
432 0x00, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04,
433 0x00, 0x00, 0x01, 0x7D
434 ],
435 &[
436 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13,
437 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08, 0x23, 0x42,
438 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A,
439 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35,
440 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A,
441 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67,
442 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x83, 0x84,
443 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
444 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3,
445 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
446 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1,
447 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4,
448 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA
449 ],
450 false,
451 is_progressive
452 )
453 .unwrap()
454 );
455 }
456 if ac_huffman_tables[1].is_none() {
457 ac_huffman_tables[1] = Some(
459 HuffmanTable::new_unfilled(
460 &[
461 0x00, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04,
462 0x00, 0x01, 0x02, 0x77
463 ],
464 &[
465 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51,
466 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1,
467 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, 0x24,
468 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A,
469 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
470 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66,
471 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82,
472 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96,
473 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA,
474 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5,
475 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9,
476 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4,
477 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA
478 ],
479 false,
480 is_progressive
481 )
482 .unwrap()
483 );
484 }
485}