/* * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ // jpgd.cpp - C++ class for JPEG decompression. // Public domain, Rich Geldreich <[email protected]> // Alex Evans: Linear memory allocator (taken from jpge.h). // v1.04, May. 19, 2012: Code tweaks to fix VS2008 static code analysis warnings (all looked harmless) // // Supports progressive and baseline sequential JPEG image files, and the most common chroma subsampling factors: Y, H1V1, H2V1, H1V2, and H2V2. // // Chroma upsampling quality: H2V2 is upsampled in the frequency domain, H2V1 and H1V2 are upsampled using point sampling. // Chroma upsampling reference: "Fast Scheme for Image Size Change in the Compressed Domain" // http://vision.ai.uiuc.edu/~dugad/research/dct/index.html #include <memory.h> #include <stdlib.h> #include <stdio.h> #include <setjmp.h> #include <stdint.h> #include "tvgJpgd.h" #ifdef _MSC_VER #pragma warning (disable : 4611) // warning C4611: interaction between '_setjmp' and C++ object destruction is non-portable #define JPGD_NORETURN … #elif defined(__GNUC__) #define JPGD_NORETURN … #else #define JPGD_NORETURN #endif /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ // Set to 1 to enable freq. domain chroma upsampling on images using H2V2 subsampling (0=faster nearest neighbor sampling). // This is slower, but results in higher quality on images with highly saturated colors. #define JPGD_SUPPORT_FREQ_DOMAIN_UPSAMPLING … #define JPGD_ASSERT(x) … #define JPGD_MAX(a,b) … #define JPGD_MIN(a,b) … jpgd_quant_t; jpgd_block_t; // Success/failure error codes. enum jpgd_status { … }; enum { … }; // Input stream interface. // Derive from this class to read input data from sources other than files or memory. Set m_eof_flag to true when no more data is available. // The decoder is rather greedy: it will keep on calling this method until its internal input buffer is full, or until the EOF flag is set. // It the input stream contains data after the JPEG stream's EOI (end of image) marker it will probably be pulled into the internal buffer. // Call the get_total_bytes_read() method to determine the actual size of the JPEG stream after successful decoding. struct jpeg_decoder_stream { … }; // stdio FILE stream class. class jpeg_decoder_file_stream : public jpeg_decoder_stream { … }; // Memory stream class. class jpeg_decoder_mem_stream : public jpeg_decoder_stream { … }; class jpeg_decoder { … }; // DCT coefficients are stored in this sequence. static int g_ZAG[64] = …; enum JPEG_MARKER { … }; enum JPEG_SUBSAMPLING { … }; #define CONST_BITS … #define PASS1_BITS … #define SCALEDONE … #define DESCALE(x,n) … #define DESCALE_ZEROSHIFT(x,n) … #define MULTIPLY(var, cnst) … #define CLAMP(i) … #define FIX_0_298631336 … #define FIX_0_390180644 … #define FIX_0_541196100 … #define FIX_0_765366865 … #define FIX_0_899976223 … #define FIX_1_175875602 … #define FIX_1_501321110 … #define FIX_1_847759065 … #define FIX_1_961570560 … #define FIX_2_053119869 … #define FIX_2_562915447 … #define FIX_3_072711026 … // Compiler creates a fast path 1D IDCT for X non-zero columns template <int NONZERO_COLS> struct Row { … }; template <> struct Row<0> { … }; template <> struct Row<1> { … }; // Compiler creates a fast path 1D IDCT for X non-zero rows template <int NONZERO_ROWS> struct Col { … }; template <> struct Col<1> { … }; static const uint8_t s_idct_row_table[] = …; static const uint8_t s_idct_col_table[] = …; void idct(const jpgd_block_t* pSrc_ptr, uint8_t* pDst_ptr, int block_max_zag) { … } void idct_4x4(const jpgd_block_t* pSrc_ptr, uint8_t* pDst_ptr) { … } // Retrieve one character from the input stream. inline uint32_t jpeg_decoder::get_char() { … } // Same as previous method, except can indicate if the character is a pad character or not. inline uint32_t jpeg_decoder::get_char(bool *pPadding_flag) { … } // Inserts a previously retrieved character back into the input buffer. inline void jpeg_decoder::stuff_char(uint8_t q) { … } // Retrieves one character from the input stream, but does not read past markers. Will continue to return 0xFF when a marker is encountered. inline uint8_t jpeg_decoder::get_octet() { … } // Retrieves a variable number of bits from the input stream. Does not recognize markers. inline uint32_t jpeg_decoder::get_bits(int num_bits) { … } // Retrieves a variable number of bits from the input stream. Markers will not be read into the input bit buffer. Instead, an infinite number of all 1's will be returned when a marker is encountered. inline uint32_t jpeg_decoder::get_bits_no_markers(int num_bits) { … } // Decodes a Huffman encoded symbol. inline int jpeg_decoder::huff_decode(huff_tables *pH) { … } // Decodes a Huffman encoded symbol. inline int jpeg_decoder::huff_decode(huff_tables *pH, int& extra_bits) { … } // Tables and macro used to fully decode the DPCM differences. static const int s_extend_test[16] = …; static const unsigned int s_extend_offset[16] = …; // The logical AND's in this macro are to shut up static code analysis (aren't really necessary - couldn't find another way to do this) #define JPGD_HUFF_EXTEND(x, s) … // Clamps a value between 0-255. inline uint8_t jpeg_decoder::clamp(int i) { … } namespace DCT_Upsample { struct Matrix44 { … }; const int FRACT_BITS = …; const int SCALE = …; Temp_Type; #define D(i) … #define F(i) … // Any decent C++ compiler will optimize this at compile time to a 0, or an array access. #define AT(c, r) … // NUM_ROWS/NUM_COLS = # of non-zero rows/cols in input matrix template<int NUM_ROWS, int NUM_COLS> struct P_Q { … }; template<int NUM_ROWS, int NUM_COLS> struct R_S { … }; } // end namespace DCT_Upsample // Unconditionally frees all allocated m_blocks. void jpeg_decoder::free_all_blocks() { … } // This method handles all errors. It will never return. // It could easily be changed to use C++ exceptions. JPGD_NORETURN void jpeg_decoder::stop_decoding(jpgd_status status) { … } void *jpeg_decoder::alloc(size_t nSize, bool zero) { … } void jpeg_decoder::word_clear(void *p, uint16_t c, uint32_t n) { … } // Refill the input buffer. // This method will sit in a loop until (A) the buffer is full or (B) // the stream's read() method reports and end of file condition. void jpeg_decoder::prep_in_buffer() { … } // Read a Huffman code table. void jpeg_decoder::read_dht_marker() { … } // Read a quantization table. void jpeg_decoder::read_dqt_marker() { … } // Read the start of frame (SOF) marker. void jpeg_decoder::read_sof_marker() { … } // Used to skip unrecognized markers. void jpeg_decoder::skip_variable_marker() { … } // Read a define restart interval (DRI) marker. void jpeg_decoder::read_dri_marker() { … } // Read a start of scan (SOS) marker. void jpeg_decoder::read_sos_marker() { … } // Finds the next marker. int jpeg_decoder::next_marker() { … } // Process markers. Returns when an SOFx, SOI, EOI, or SOS marker is // encountered. int jpeg_decoder::process_markers() { … } // Finds the start of image (SOI) marker. // This code is rather defensive: it only checks the first 512 bytes to avoid // false positives. void jpeg_decoder::locate_soi_marker() { … } // Find a start of frame (SOF) marker. void jpeg_decoder::locate_sof_marker() { … } // Find a start of scan (SOS) marker. int jpeg_decoder::locate_sos_marker() { … } // Reset everything to default/uninitialized state. void jpeg_decoder::init(jpeg_decoder_stream *pStream) { … } #define SCALEBITS … #define ONE_HALF … #define FIX(x) … // Create a few tables that allow us to quickly convert YCbCr to RGB. void jpeg_decoder::create_look_ups() { … } // This method throws back into the stream any bytes that where read // into the bit buffer during initial marker scanning. void jpeg_decoder::fix_in_buffer() { … } void jpeg_decoder::transform_mcu(int mcu_row) { … } static const uint8_t s_max_rc[64] = …; void jpeg_decoder::transform_mcu_expand(int mcu_row) { … } // Loads and dequantizes the next row of (already decoded) coefficients. // Progressive images only. void jpeg_decoder::load_next_row() { … } // Restart interval processing. void jpeg_decoder::process_restart() { … } static inline int dequantize_ac(int c, int q) { … } // Decodes and dequantizes the next row of coefficients. void jpeg_decoder::decode_next_row() { … } // YCbCr H1V1 (1x1:1:1, 3 m_blocks per MCU) to RGB void jpeg_decoder::H1V1Convert() { … } // YCbCr H2V1 (2x1:1:1, 4 m_blocks per MCU) to RGB void jpeg_decoder::H2V1Convert() { … } // YCbCr H2V1 (1x2:1:1, 4 m_blocks per MCU) to RGB void jpeg_decoder::H1V2Convert() { … } // YCbCr H2V2 (2x2:1:1, 6 m_blocks per MCU) to RGB void jpeg_decoder::H2V2Convert() { … } // Y (1 block per MCU) to 8-bit grayscale void jpeg_decoder::gray_convert() { … } void jpeg_decoder::expanded_convert() { … } // Find end of image (EOI) marker, so we can return to the user the exact size of the input stream. void jpeg_decoder::find_eoi() { … } int jpeg_decoder::decode(const void** pScan_line, uint32_t* pScan_line_len) { … } // Creates the tables needed for efficient Huffman decoding. void jpeg_decoder::make_huff_table(int index, huff_tables *pH) { … } // Verifies the quantization tables needed for this scan are available. void jpeg_decoder::check_quant_tables() { … } // Verifies that all the Huffman tables needed for this scan are available. void jpeg_decoder::check_huff_tables() { … } // Determines the component order inside each MCU. // Also calcs how many MCU's are on each row, etc. void jpeg_decoder::calc_mcu_block_order() { … } // Starts a new scan. int jpeg_decoder::init_scan() { … } // Starts a frame. Determines if the number of components or sampling factors // are supported. void jpeg_decoder::init_frame() { … } // The coeff_buf series of methods originally stored the coefficients // into a "virtual" file which was located in EMS, XMS, or a disk file. A cache // was used to make this process more efficient. Now, we can store the entire // thing in RAM. jpeg_decoder::coeff_buf* jpeg_decoder::coeff_buf_open(int block_num_x, int block_num_y, int block_len_x, int block_len_y) { … } inline jpgd_block_t *jpeg_decoder::coeff_buf_getp(coeff_buf *cb, int block_x, int block_y) { … } // The following methods decode the various types of m_blocks encountered // in progressively encoded images. void jpeg_decoder::decode_block_dc_first(jpeg_decoder *pD, int component_id, int block_x, int block_y) { … } void jpeg_decoder::decode_block_dc_refine(jpeg_decoder *pD, int component_id, int block_x, int block_y) { … } void jpeg_decoder::decode_block_ac_first(jpeg_decoder *pD, int component_id, int block_x, int block_y) { … } void jpeg_decoder::decode_block_ac_refine(jpeg_decoder *pD, int component_id, int block_x, int block_y) { … } // Decode a scan in a progressively encoded image. void jpeg_decoder::decode_scan(pDecode_block_func decode_block_func) { … } // Decode a progressively encoded image. void jpeg_decoder::init_progressive() { … } void jpeg_decoder::init_sequential() { … } void jpeg_decoder::decode_start() { … } void jpeg_decoder::decode_init(jpeg_decoder_stream *pStream) { … } jpeg_decoder::jpeg_decoder(jpeg_decoder_stream *pStream) { … } int jpeg_decoder::begin_decoding() { … } jpeg_decoder::~jpeg_decoder() { … } void jpeg_decoder_file_stream::close() { … } jpeg_decoder_file_stream::~jpeg_decoder_file_stream() { … } bool jpeg_decoder_file_stream::open(const char *Pfilename) { … } int jpeg_decoder_file_stream::read(uint8_t *pBuf, int max_bytes_to_read, bool *pEOF_flag) { … } bool jpeg_decoder_mem_stream::open(const uint8_t *pSrc_data, uint32_t size) { … } int jpeg_decoder_mem_stream::read(uint8_t *pBuf, int max_bytes_to_read, bool *pEOF_flag) { … } /************************************************************************/ /* External Class Implementation */ /************************************************************************/ jpeg_decoder* jpgdHeader(const char* data, int size, int* width, int* height) { … } jpeg_decoder* jpgdHeader(const char* filename, int* width, int* height) { … } void jpgdDelete(jpeg_decoder* decoder) { … } unsigned char* jpgdDecompress(jpeg_decoder* decoder) { … }