zune_jpeg/
misc.rs

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, warn};
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 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    // check colorspace matches
314    if img.input_colorspace.num_components() > img.components.len() {
315        if img.input_colorspace == ColorSpace::YCCK {
316            // Some images may have YCCK format (from adobe app14 segment) which is supposed to be 4 components
317            // but only 3 components, see issue https://github.com/etemesi254/zune-image/issues/275
318            // So this is the behaviour of other decoders
319            // - stb_image: Treats it as YCbCr image
320            // - libjpeg_turbo: Does not know how to parse YCCK images (transform 2 app14) so treats
321            // it as YCbCr
322            // So I will match that to match existing ones
323            warn!("Treating YCCK colorspace as YCbCr as component length does not match");
324            img.input_colorspace = ColorSpace::YCbCr
325        } else {
326            let msg = format!(
327                " Expected {} number of components but found {}",
328                img.input_colorspace.num_components(),
329                img.components.len()
330            );
331
332            return Err(DecodeErrors::Format(msg));
333        }
334    }
335    Ok(())
336}
337
338///Calculate number of fill bytes added to the end of a JPEG image
339/// to fill the image
340///
341/// JPEG usually inserts padding bytes if the image width cannot be evenly divided into
342/// 8 , 16 or 32 chunks depending on the sub sampling ratio. So given a sub-sampling ratio,
343/// and the actual width, this calculates the padded bytes that were added to the image
344///
345///  # Params
346/// -actual_width: Actual width of the image
347/// -sub_sample: Sub sampling factor of the image
348///
349/// # Returns
350/// The padded width, this is how long the width is for a particular image
351pub fn calculate_padded_width(actual_width: usize, sub_sample: SampleRatios) -> usize {
352    match sub_sample {
353        SampleRatios::None | SampleRatios::V => {
354            // None+V sends one MCU row, so that's a simple calculation
355            ((actual_width + 7) / 8) * 8
356        }
357        SampleRatios::H | SampleRatios::HV => {
358            // sends two rows, width can be expanded by up to 15 more bytes
359            ((actual_width + 15) / 16) * 16
360        }
361        SampleRatios::Generic(h, _) => {
362            ((actual_width + ((h * 8).saturating_sub(1))) / (h * 8)) * (h * 8)
363        }
364    }
365}
366
367// https://www.loc.gov/preservation/digital/formats/fdd/fdd000063.shtml
368// "Avery Lee, writing in the rec.video.desktop newsgroup in 2001, commented that "MJPEG, or at
369//  least the MJPEG in AVIs having the MJPG fourcc, is restricted JPEG with a fixed -- and
370//  *omitted* -- Huffman table. The JPEG must be YCbCr colorspace, it must be 4:2:2, and it must
371//  use basic Huffman encoding, not arithmetic or progressive.... You can indeed extract the
372//  MJPEG frames and decode them with a regular JPEG decoder, but you have to prepend the DHT
373//  segment to them, or else the decoder won't have any idea how to decompress the data.
374//  The exact table necessary is given in the OpenDML spec.""
375pub fn fill_default_mjpeg_tables(
376    is_progressive: bool, dc_huffman_tables: &mut [Option<HuffmanTable>],
377    ac_huffman_tables: &mut [Option<HuffmanTable>]
378) {
379    // Section K.3.3
380    trace!("Filling with default mjpeg tables");
381
382    if dc_huffman_tables[0].is_none() {
383        // Table K.3
384        dc_huffman_tables[0] = Some(
385            HuffmanTable::new_unfilled(
386                &[
387                    0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
388                    0x00, 0x00, 0x00, 0x00
389                ],
390                &[
391                    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B
392                ],
393                true,
394                is_progressive
395            )
396            .unwrap()
397        );
398    }
399    if dc_huffman_tables[1].is_none() {
400        // Table K.4
401        dc_huffman_tables[1] = Some(
402            HuffmanTable::new_unfilled(
403                &[
404                    0x00, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00,
405                    0x00, 0x00, 0x00, 0x00
406                ],
407                &[
408                    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B
409                ],
410                true,
411                is_progressive
412            )
413            .unwrap()
414        );
415    }
416    if ac_huffman_tables[0].is_none() {
417        // Table K.5
418        ac_huffman_tables[0] = Some(
419            HuffmanTable::new_unfilled(
420                &[
421                    0x00, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04,
422                    0x00, 0x00, 0x01, 0x7D
423                ],
424                &[
425                    0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13,
426                    0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08, 0x23, 0x42,
427                    0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A,
428                    0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35,
429                    0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A,
430                    0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67,
431                    0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x83, 0x84,
432                    0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
433                    0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3,
434                    0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
435                    0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1,
436                    0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4,
437                    0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA
438                ],
439                false,
440                is_progressive
441            )
442            .unwrap()
443        );
444    }
445    if ac_huffman_tables[1].is_none() {
446        // Table K.6
447        ac_huffman_tables[1] = Some(
448            HuffmanTable::new_unfilled(
449                &[
450                    0x00, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04,
451                    0x00, 0x01, 0x02, 0x77
452                ],
453                &[
454                    0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51,
455                    0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1,
456                    0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, 0x24,
457                    0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A,
458                    0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
459                    0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66,
460                    0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82,
461                    0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96,
462                    0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA,
463                    0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5,
464                    0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9,
465                    0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4,
466                    0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA
467                ],
468                false,
469                is_progressive
470            )
471            .unwrap()
472        );
473    }
474}