Skip to main content

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;
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
26/// Start of baseline DCT Huffman coding
27
28pub const START_OF_FRAME_BASE: u16 = 0xffc0;
29
30/// Start of another frame
31
32pub const START_OF_FRAME_EXT_SEQ: u16 = 0xffc1;
33
34/// Start of progressive DCT encoding
35
36pub const START_OF_FRAME_PROG_DCT: u16 = 0xffc2;
37
38/// Start of Lossless sequential Huffman coding
39
40pub const START_OF_FRAME_LOS_SEQ: u16 = 0xffc3;
41
42/// Start of extended sequential DCT arithmetic coding
43
44pub const START_OF_FRAME_EXT_AR: u16 = 0xffc9;
45
46/// Start of Progressive DCT arithmetic coding
47
48pub const START_OF_FRAME_PROG_DCT_AR: u16 = 0xffca;
49
50/// Start of Lossless sequential Arithmetic coding
51
52pub const START_OF_FRAME_LOS_SEQ_AR: u16 = 0xffcb;
53
54/// Undo run length encoding of coefficients by placing them in natural order
55///
56/// This is an index from position-in-bitstream to position-in-row-major-order.
57#[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    // Prevent overflowing
68    63, 63, 63, 63, 63, 63, 63, 63,
69    63, 63, 63, 63, 63, 63, 63, 63
70];
71
72/// Align data to a 16 byte boundary
73#[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/// Align data to a 32 byte boundary
88#[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/// Markers that identify different Start of Image markers
102/// They identify the type of encoding and whether the file use lossy(DCT) or
103/// lossless compression and whether we use Huffman or arithmetic coding schemes
104#[derive(Eq, PartialEq, Copy, Clone)]
105#[allow(clippy::upper_case_acronyms)]
106pub enum SOFMarkers {
107    /// Baseline DCT markers
108    BaselineDct,
109    /// SOF_1 Extended sequential DCT,Huffman coding
110    ExtendedSequentialHuffman,
111    /// Progressive DCT, Huffman coding
112    ProgressiveDctHuffman,
113    /// Lossless (sequential), huffman coding,
114    LosslessHuffman,
115    /// Extended sequential DEC, arithmetic coding
116    ExtendedSequentialDctArithmetic,
117    /// Progressive DCT, arithmetic coding,
118    ProgressiveDctArithmetic,
119    /// Lossless ( sequential), arithmetic coding
120    LosslessArithmetic
121}
122
123impl Default for SOFMarkers {
124    fn default() -> Self {
125        Self::BaselineDct
126    }
127}
128
129impl SOFMarkers {
130    /// Check if a certain marker is sequential DCT or not
131
132    pub fn is_sequential_dct(self) -> bool {
133        matches!(
134            self,
135            Self::BaselineDct
136                | Self::ExtendedSequentialHuffman
137                | Self::ExtendedSequentialDctArithmetic
138        )
139    }
140
141    /// Check if a marker is a Lossles type or not
142
143    pub fn is_lossless(self) -> bool {
144        matches!(self, Self::LosslessHuffman | Self::LosslessArithmetic)
145    }
146
147    /// Check whether a marker is a progressive marker or not
148
149    pub fn is_progressive(self) -> bool {
150        matches!(
151            self,
152            Self::ProgressiveDctHuffman | Self::ProgressiveDctArithmetic
153        )
154    }
155
156    /// Create a marker from an integer
157
158    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
190/// Set up component parameters.
191///
192/// This modifies the components in place setting up details needed by other
193/// parts fo the decoder.
194pub(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    // in case of adobe app14 being present, zero may indicate
201    // either CMYK if components are 4 or RGB if components are 3,
202    // see https://docs.oracle.com/javase/6/docs/api/javax/imageio/metadata/doc-files/jpeg_metadata.html
203    // so since we may not know how many number of components
204    // we have when decoding app14, we have to defer that check
205    // until now.
206    //
207    // We know adobe app14 was present since it's the only one that can modify
208    // input colorspace to be CMYK
209    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        // compute interleaved image info
215        // h_max contains the maximum horizontal component
216        img.h_max = max(img.h_max, component.horizontal_sample);
217        // v_max contains the maximum vertical component
218        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        // Number of MCU's per width
222        img.mcu_x = usize::from(img.info.width).div_ceil(img.mcu_width);
223        // Number of MCU's per height
224        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            // interleaved images have horizontal and vertical sampling factors
228            // not equal to 1.
229            img.is_interleaved = true;
230        }
231        // Extract quantization tables from the arrays into components
232        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        // probably not needed. :)
246        component.y = y;
247        component.quantization_table = qt_table;
248        // initially stride contains its horizontal sub-sampling
249        component.width_stride *= img.mcu_x * 8;
250    }
251    {
252        // Sampling factors are one thing that suck
253        // this fixes a specific problem with images like
254        //
255        // (2 2) None
256        // (2 1) H
257        // (2 1) H
258        //
259        // The images exist in the wild, the images are not meant to exist
260        // but they do, it's just an annoying horizontal sub-sampling that
261        // I don't know why it exists.
262        // But it does
263        // So we try to cope with that.
264        // I am not sure of how to explain how to fix it, but it involved a debugger
265        // and to much coke(the legal one)
266        //
267        // If this wasn't present, self.upsample_dest would have the wrong length
268        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    // check colorspace matches
299    if img.input_colorspace.num_components() > img.components.len() {
300        if img.input_colorspace == ColorSpace::YCCK {
301            // Some images may have YCCK format (from adobe app14 segment) which is supposed to be 4 components
302            // but only 3 components, see issue https://github.com/etemesi254/zune-image/issues/275
303            // So this is the behaviour of other decoders
304            // - stb_image: Treats it as YCbCr image
305            // - libjpeg_turbo: Does not know how to parse YCCK images (transform 2 app14) so treats
306            // it as YCbCr
307            // So I will match that to match existing ones
308            warn!("Treating YCCK colorspace as YCbCr as component length does not match");
309            img.input_colorspace = ColorSpace::YCbCr
310        } else {
311            // Note, translated this to a warning to handle valid images of the sort
312            // See https://github.com/etemesi254/zune-image/issues/288 where there
313            // was a CMYK image with two components which would be decoded to 4 components
314            // by the decoder.
315            // So with a warning that becomes supported.
316            //
317            // djpeg fails to render an image from that also probably because it does not
318            // understand the expected format.
319            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                // N/B: We do not post process the color of such, treating it as multiband
328                // is the best option since I am not aware of grayscale+alpha which is the most common
329                // two band format in jpeg.
330                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
349///Calculate number of fill bytes added to the end of a JPEG image
350/// to fill the image
351///
352/// JPEG usually inserts padding bytes if the image width cannot be evenly divided into
353/// 8 , 16 or 32 chunks depending on the sub sampling ratio. So given a sub-sampling ratio,
354/// and the actual width, this calculates the padded bytes that were added to the image
355///
356///  # Params
357/// -actual_width: Actual width of the image
358/// -sub_sample: Sub sampling factor of the image
359///
360/// # Returns
361/// The padded width, this is how long the width is for a particular image
362pub fn calculate_padded_width(actual_width: usize, sub_sample: SampleRatios) -> usize {
363    match sub_sample {
364        SampleRatios::None | SampleRatios::V => {
365            // None+V sends one MCU row, so that's a simple calculation
366            ((actual_width + 7) / 8) * 8
367        }
368        SampleRatios::H | SampleRatios::HV => {
369            // sends two rows, width can be expanded by up to 15 more bytes
370            ((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
378// https://www.loc.gov/preservation/digital/formats/fdd/fdd000063.shtml
379// "Avery Lee, writing in the rec.video.desktop newsgroup in 2001, commented that "MJPEG, or at
380//  least the MJPEG in AVIs having the MJPG fourcc, is restricted JPEG with a fixed -- and
381//  *omitted* -- Huffman table. The JPEG must be YCbCr colorspace, it must be 4:2:2, and it must
382//  use basic Huffman encoding, not arithmetic or progressive.... You can indeed extract the
383//  MJPEG frames and decode them with a regular JPEG decoder, but you have to prepend the DHT
384//  segment to them, or else the decoder won't have any idea how to decompress the data.
385//  The exact table necessary is given in the OpenDML spec.""
386pub fn fill_default_mjpeg_tables(
387    is_progressive: bool, dc_huffman_tables: &mut [Option<HuffmanTable>],
388    ac_huffman_tables: &mut [Option<HuffmanTable>]
389) {
390    // Section K.3.3
391    trace!("Filling with default mjpeg tables");
392
393    if dc_huffman_tables[0].is_none() {
394        // Table K.3
395        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        // Table K.4
412        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        // Table K.5
429        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        // Table K.6
458        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}