1/*
2 * Copyright (c) 2023.
3 *
4 * This software is free software;
5 *
6 * You can redistribute it or modify it under terms of the MIT, Apache License or Zlib license
7 */
8
9//!Miscellaneous stuff
10#![allow(dead_code)]
11
12use alloc::format;
13use core::cmp::max;
14use core::fmt;
15
16use zune_core::bytestream::{ZByteReader, ZReaderTrait};
17use zune_core::colorspace::ColorSpace;
18use zune_core::log::trace;
19
20use crate::components::{ComponentID, SampleRatios};
21use crate::errors::DecodeErrors;
22use crate::huffman::HuffmanTable;
23use crate::JpegDecoder;
24
25/// Start of baseline DCT Huffman coding
26
27pub const START_OF_FRAME_BASE: u16 = 0xffc0;
28
29/// Start of another frame
30
31pub const START_OF_FRAME_EXT_SEQ: u16 = 0xffc1;
32
33/// Start of progressive DCT encoding
34
35pub const START_OF_FRAME_PROG_DCT: u16 = 0xffc2;
36
37/// Start of Lossless sequential Huffman coding
38
39pub const START_OF_FRAME_LOS_SEQ: u16 = 0xffc3;
40
41/// Start of extended sequential DCT arithmetic coding
42
43pub const START_OF_FRAME_EXT_AR: u16 = 0xffc9;
44
45/// Start of Progressive DCT arithmetic coding
46
47pub const START_OF_FRAME_PROG_DCT_AR: u16 = 0xffca;
48
49/// Start of Lossless sequential Arithmetic coding
50
51pub const START_OF_FRAME_LOS_SEQ_AR: u16 = 0xffcb;
52
53/// Undo run length encoding of coefficients by placing them in natural order
54#[rustfmt::skip]
55pub const UN_ZIGZAG: [usize; 64 + 16] = [
56 0, 1, 8, 16, 9, 2, 3, 10,
57 17, 24, 32, 25, 18, 11, 4, 5,
58 12, 19, 26, 33, 40, 48, 41, 34,
59 27, 20, 13, 6, 7, 14, 21, 28,
60 35, 42, 49, 56, 57, 50, 43, 36,
61 29, 22, 15, 23, 30, 37, 44, 51,
62 58, 59, 52, 45, 38, 31, 39, 46,
63 53, 60, 61, 54, 47, 55, 62, 63,
64 // Prevent overflowing
65 63, 63, 63, 63, 63, 63, 63, 63,
66 63, 63, 63, 63, 63, 63, 63, 63
67];
68
69/// Align data to a 16 byte boundary
70#[repr(align(16))]
71#[derive(Clone)]
72
73pub struct Aligned16<T: ?Sized>(pub T);
74
75impl<T> Default for Aligned16<T>
76where
77 T: Default
78{
79 fn default() -> Self {
80 Aligned16(T::default())
81 }
82}
83
84/// Align data to a 32 byte boundary
85#[repr(align(32))]
86#[derive(Clone)]
87pub struct Aligned32<T: ?Sized>(pub T);
88
89impl<T> Default for Aligned32<T>
90where
91 T: Default
92{
93 fn default() -> Self {
94 Aligned32(T::default())
95 }
96}
97
98/// Markers that identify different Start of Image markers
99/// They identify the type of encoding and whether the file use lossy(DCT) or
100/// lossless compression and whether we use Huffman or arithmetic coding schemes
101#[derive(Eq, PartialEq, Copy, Clone)]
102#[allow(clippy::upper_case_acronyms)]
103pub enum SOFMarkers {
104 /// Baseline DCT markers
105 BaselineDct,
106 /// SOF_1 Extended sequential DCT,Huffman coding
107 ExtendedSequentialHuffman,
108 /// Progressive DCT, Huffman coding
109 ProgressiveDctHuffman,
110 /// Lossless (sequential), huffman coding,
111 LosslessHuffman,
112 /// Extended sequential DEC, arithmetic coding
113 ExtendedSequentialDctArithmetic,
114 /// Progressive DCT, arithmetic coding,
115 ProgressiveDctArithmetic,
116 /// Lossless ( sequential), arithmetic coding
117 LosslessArithmetic
118}
119
120impl Default for SOFMarkers {
121 fn default() -> Self {
122 Self::BaselineDct
123 }
124}
125
126impl SOFMarkers {
127 /// Check if a certain marker is sequential DCT or not
128
129 pub fn is_sequential_dct(self) -> bool {
130 matches!(
131 self,
132 Self::BaselineDct
133 | Self::ExtendedSequentialHuffman
134 | Self::ExtendedSequentialDctArithmetic
135 )
136 }
137
138 /// Check if a marker is a Lossles type or not
139
140 pub fn is_lossless(self) -> bool {
141 matches!(self, Self::LosslessHuffman | Self::LosslessArithmetic)
142 }
143
144 /// Check whether a marker is a progressive marker or not
145
146 pub fn is_progressive(self) -> bool {
147 matches!(
148 self,
149 Self::ProgressiveDctHuffman | Self::ProgressiveDctArithmetic
150 )
151 }
152
153 /// Create a marker from an integer
154
155 pub fn from_int(int: u16) -> Option<SOFMarkers> {
156 match int {
157 START_OF_FRAME_BASE => Some(Self::BaselineDct),
158 START_OF_FRAME_PROG_DCT => Some(Self::ProgressiveDctHuffman),
159 START_OF_FRAME_PROG_DCT_AR => Some(Self::ProgressiveDctArithmetic),
160 START_OF_FRAME_LOS_SEQ => Some(Self::LosslessHuffman),
161 START_OF_FRAME_LOS_SEQ_AR => Some(Self::LosslessArithmetic),
162 START_OF_FRAME_EXT_SEQ => Some(Self::ExtendedSequentialHuffman),
163 START_OF_FRAME_EXT_AR => Some(Self::ExtendedSequentialDctArithmetic),
164 _ => None
165 }
166 }
167}
168
169impl fmt::Debug for SOFMarkers {
170 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
171 match &self {
172 Self::BaselineDct => write!(f, "Baseline DCT"),
173 Self::ExtendedSequentialHuffman => {
174 write!(f, "Extended sequential DCT, Huffman Coding")
175 }
176 Self::ProgressiveDctHuffman => write!(f, "Progressive DCT,Huffman Encoding"),
177 Self::LosslessHuffman => write!(f, "Lossless (sequential) Huffman encoding"),
178 Self::ExtendedSequentialDctArithmetic => {
179 write!(f, "Extended sequential DCT, arithmetic coding")
180 }
181 Self::ProgressiveDctArithmetic => write!(f, "Progressive DCT, arithmetic coding"),
182 Self::LosslessArithmetic => write!(f, "Lossless (sequential) arithmetic coding")
183 }
184 }
185}
186
187/// Read `buf.len()*2` data from the underlying `u8` buffer and convert it into
188/// u16, and store it into `buf`
189///
190/// # Arguments
191/// - reader: A mutable reference to the underlying reader.
192/// - buf: A mutable reference to a slice containing u16's
193#[inline]
194pub fn read_u16_into<T>(reader: &mut ZByteReader<T>, buf: &mut [u16]) -> Result<(), DecodeErrors>
195where
196 T: ZReaderTrait
197{
198 for i: &mut u16 in buf {
199 *i = reader.get_u16_be_err()?;
200 }
201
202 Ok(())
203}
204
205/// Set up component parameters.
206///
207/// This modifies the components in place setting up details needed by other
208/// parts fo the decoder.
209pub(crate) fn setup_component_params<T: ZReaderTrait>(
210 img: &mut JpegDecoder<T>
211) -> Result<(), DecodeErrors> {
212 let img_width = img.width();
213 let img_height = img.height();
214
215 // in case of adobe app14 being present, zero may indicate
216 // either CMYK if components are 4 or RGB if components are 3,
217 // see https://docs.oracle.com/javase/6/docs/api/javax/imageio/metadata/doc-files/jpeg_metadata.html
218 // so since we may not know how many number of components
219 // we have when decoding app14, we have to defer that check
220 // until now.
221 //
222 // We know adobe app14 was present since it's the only one that can modify
223 // input colorspace to be CMYK
224 if img.components.len() == 3 && img.input_colorspace == ColorSpace::CMYK {
225 img.input_colorspace = ColorSpace::RGB;
226 }
227
228 for component in &mut img.components {
229 // compute interleaved image info
230 // h_max contains the maximum horizontal component
231 img.h_max = max(img.h_max, component.horizontal_sample);
232 // v_max contains the maximum vertical component
233 img.v_max = max(img.v_max, component.vertical_sample);
234 img.mcu_width = img.h_max * 8;
235 img.mcu_height = img.v_max * 8;
236 // Number of MCU's per width
237 img.mcu_x = (usize::from(img.info.width) + img.mcu_width - 1) / img.mcu_width;
238 // Number of MCU's per height
239 img.mcu_y = (usize::from(img.info.height) + img.mcu_height - 1) / img.mcu_height;
240
241 if img.h_max != 1 || img.v_max != 1 {
242 // interleaved images have horizontal and vertical sampling factors
243 // not equal to 1.
244 img.is_interleaved = true;
245 }
246 // Extract quantization tables from the arrays into components
247 let qt_table = *img.qt_tables[component.quantization_table_number as usize]
248 .as_ref()
249 .ok_or_else(|| {
250 DecodeErrors::DqtError(format!(
251 "No quantization table for component {:?}",
252 component.component_id
253 ))
254 })?;
255
256 let x = (usize::from(img_width) * component.horizontal_sample + img.h_max - 1) / img.h_max;
257 let y = (usize::from(img_height) * component.horizontal_sample + img.h_max - 1) / img.v_max;
258 component.x = x;
259 component.w2 = img.mcu_x * component.horizontal_sample * 8;
260 // probably not needed. :)
261 component.y = y;
262 component.quantization_table = qt_table;
263 // initially stride contains its horizontal sub-sampling
264 component.width_stride *= img.mcu_x * 8;
265 }
266 {
267 // Sampling factors are one thing that suck
268 // this fixes a specific problem with images like
269 //
270 // (2 2) None
271 // (2 1) H
272 // (2 1) H
273 //
274 // The images exist in the wild, the images are not meant to exist
275 // but they do, it's just an annoying horizontal sub-sampling that
276 // I don't know why it exists.
277 // But it does
278 // So we try to cope with that.
279 // I am not sure of how to explain how to fix it, but it involved a debugger
280 // and to much coke(the legal one)
281 //
282 // If this wasn't present, self.upsample_dest would have the wrong length
283 let mut handle_that_annoying_bug = false;
284
285 if let Some(y_component) = img
286 .components
287 .iter()
288 .find(|c| c.component_id == ComponentID::Y)
289 {
290 if y_component.horizontal_sample == 2 || y_component.vertical_sample == 2 {
291 handle_that_annoying_bug = true;
292 }
293 }
294 if handle_that_annoying_bug {
295 for comp in &mut img.components {
296 if (comp.component_id != ComponentID::Y)
297 && (comp.horizontal_sample != 1 || comp.vertical_sample != 1)
298 {
299 comp.fix_an_annoying_bug = 2;
300 }
301 }
302 }
303 }
304
305 if img.is_mjpeg {
306 fill_default_mjpeg_tables(
307 img.is_progressive,
308 &mut img.dc_huffman_tables,
309 &mut img.ac_huffman_tables
310 );
311 }
312
313 Ok(())
314}
315
316///Calculate number of fill bytes added to the end of a JPEG image
317/// to fill the image
318///
319/// JPEG usually inserts padding bytes if the image width cannot be evenly divided into
320/// 8 , 16 or 32 chunks depending on the sub sampling ratio. So given a sub-sampling ratio,
321/// and the actual width, this calculates the padded bytes that were added to the image
322///
323/// # Params
324/// -actual_width: Actual width of the image
325/// -sub_sample: Sub sampling factor of the image
326///
327/// # Returns
328/// The padded width, this is how long the width is for a particular image
329pub fn calculate_padded_width(actual_width: usize, sub_sample: SampleRatios) -> usize {
330 match sub_sample {
331 SampleRatios::None | SampleRatios::V => {
332 // None+V sends one MCU row, so that's a simple calculation
333 ((actual_width + 7) / 8) * 8
334 }
335 SampleRatios::H | SampleRatios::HV => {
336 // sends two rows, width can be expanded by up to 15 more bytes
337 ((actual_width + 15) / 16) * 16
338 }
339 }
340}
341
342// https://www.loc.gov/preservation/digital/formats/fdd/fdd000063.shtml
343// "Avery Lee, writing in the rec.video.desktop newsgroup in 2001, commented that "MJPEG, or at
344// least the MJPEG in AVIs having the MJPG fourcc, is restricted JPEG with a fixed -- and
345// *omitted* -- Huffman table. The JPEG must be YCbCr colorspace, it must be 4:2:2, and it must
346// use basic Huffman encoding, not arithmetic or progressive.... You can indeed extract the
347// MJPEG frames and decode them with a regular JPEG decoder, but you have to prepend the DHT
348// segment to them, or else the decoder won't have any idea how to decompress the data.
349// The exact table necessary is given in the OpenDML spec.""
350pub fn fill_default_mjpeg_tables(
351 is_progressive: bool, dc_huffman_tables: &mut [Option<HuffmanTable>],
352 ac_huffman_tables: &mut [Option<HuffmanTable>]
353) {
354 // Section K.3.3
355 trace!("Filling with default mjpeg tables");
356
357 if dc_huffman_tables[0].is_none() {
358 // Table K.3
359 dc_huffman_tables[0] = Some(
360 HuffmanTable::new_unfilled(
361 &[
362 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
363 0x00, 0x00, 0x00, 0x00
364 ],
365 &[
366 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B
367 ],
368 true,
369 is_progressive
370 )
371 .unwrap()
372 );
373 }
374 if dc_huffman_tables[1].is_none() {
375 // Table K.4
376 dc_huffman_tables[1] = Some(
377 HuffmanTable::new_unfilled(
378 &[
379 0x00, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00,
380 0x00, 0x00, 0x00, 0x00
381 ],
382 &[
383 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B
384 ],
385 true,
386 is_progressive
387 )
388 .unwrap()
389 );
390 }
391 if ac_huffman_tables[0].is_none() {
392 // Table K.5
393 ac_huffman_tables[0] = Some(
394 HuffmanTable::new_unfilled(
395 &[
396 0x00, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04,
397 0x00, 0x00, 0x01, 0x7D
398 ],
399 &[
400 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13,
401 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08, 0x23, 0x42,
402 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A,
403 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35,
404 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A,
405 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67,
406 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x83, 0x84,
407 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
408 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3,
409 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
410 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1,
411 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4,
412 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA
413 ],
414 false,
415 is_progressive
416 )
417 .unwrap()
418 );
419 }
420 if ac_huffman_tables[1].is_none() {
421 // Table K.6
422 ac_huffman_tables[1] = Some(
423 HuffmanTable::new_unfilled(
424 &[
425 0x00, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04,
426 0x00, 0x01, 0x02, 0x77
427 ],
428 &[
429 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51,
430 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1,
431 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, 0x24,
432 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A,
433 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
434 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66,
435 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82,
436 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96,
437 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA,
438 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5,
439 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9,
440 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4,
441 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA
442 ],
443 false,
444 is_progressive
445 )
446 .unwrap()
447 );
448 }
449}
450