Analysis of JPEG principle and debugging of its decoder
1, Experimental purpose
Master the basic principle of JPEG codec system. Preliminarily master the implementation of complex data compression algorithm, and be able to output the corresponding data according to the needs of theoretical analysis.
2, Experimental content
(1) Experimental principle
1. JPEG file introduction and format
(1) Introduction to JPEG
JPEG (Joint Photographic Experts Group), a joint image experts group, is a standard for continuous tone still image compression. The joint coding methods of predictive coding (DPCM), discrete cosine transform (DCT) and entropy coding are mainly used. It belongs to lossy compression format, which can compress the image in a small storage space, which will damage the image data to a certain extent.
(2) JPEG file format
-
SOI: Start of Image; Tag code: 2 bytes, fixed value: 0xFFD8
-
APP0: Application, Application, reserved flag 0; Tag code: 2 bytes, fixed value: 0xFFE0
Contains 9 specific fields:- ① Data length 2 bytes ① ~ ⑨ total length of 9 fields
- ② Identifier 5-byte fixed value 0x4A46494600, i.e. string "JFIF0"
- ③ The 2 bytes of version number are usually 0x0102, indicating the version number of JFIF is 1.2
- ④ The density units of X and Y are 1 byte. There are only three values available:
0: No unit; 1: Points / inch; 2: Points / cm - ⑤ The value range of 2 bytes of pixel density in X direction is unknown
- ⑥ The value range of 2 bytes of pixel density in Y direction is unknown
- ⑦ The number of thumbnail horizontal pixels is 1 byte, and the value range is unknown
- ⑧ The number of vertical pixels of thumbnail is 1 byte, and the value range is unknown
- ⑨ Thumbnail RGB bitmap length may be a multiple of 3 thumbnail RGB bitmap data
-
DQT: Define Quantization Table; Tag code: 2 bytes, fixed value: 0xFFDB
Contains 9 specific fields:- ① Data length is the total length of 2-byte field ① and multiple fields ②
- ② Quantization table data length - 2 bytes
- a) Precision and quantization table ID 1 byte
High 4 bits: precision, only two optional values 0:8 bits; 1: 16 bit
Lower 4 bits: quantization table ID, with a value range of 0 ~ 3 - b) Table entry (64) × (precision + 1) byte
For example, a quantization table with 8-bit accuracy has a table item length of 64 × (0 + 1) = 64 bytes
In this marking segment, field ② can appear repeatedly, indicating multiple quantization tables, but it can only appear 4 times at most
- a) Precision and quantization table ID 1 byte
-
SOF0:Start of Frame; Mark code: 2 bytes; Fixed value: 0xFFC0
Contains 9 specific fields:- ① Data length 2 bytes ① ~ ⑥ total length of six fields
- ② The precision is 1 byte, and the number of bits of each data sample is usually 8 bits. General software does not support 12 bits and 16 bits
- ③ Image height 2 bytes image height (unit: pixel)
- ④ Image width 2 bytes image width (unit: pixel)
- ⑤ The number of color components is 1 byte, and there are only 3 values. 1: grayscale image; 3: YCrCb or YIQ; 4: CMYK and YCrCb are used in JFIF, so the number of color components here is always 3
- ⑥ Color component information number of color components × 3 bytes (usually 9 bytes)
- a) Color component ID 1 byte
- b) Horizontal / vertical sampling factor 1 byte
High 4 bits: horizontal sampling factor
Lower 4 bits: vertical sampling factor - c) The ID of the quantization table used by the current component of the quantization table 1 byte
-
DHT: Define Huffman Table, which defines Huffman table; Mark code: 2 bytes; Fixed value: 0xFFC4
Contains 2 specific fields:- ① Data length 2 bytes
- ② huffman table data length - 2 bytes
Table ID and table type 1 byte
High 4 bits: type, only two values are optional
0: DC; 1: AC AC low 4 bits: Huffman meter ID,
Note that the DC table and the AC table are coded separately
The number of codewords with different bits is 16 bytes
② the number of characters in the code segment can be different from that in the code segment (1 byte), and it can only appear in the code segment (1 byte).
-
SOS: Start of Scan, scan start: 12 bytes; Mark code: 2 bytes; Fixed value: 0xFFDA
Contains 2 specific fields:- ① The data length is 2 bytes. The total length of the two fields ① ~ ④
- ② The number of color components 1 byte should be the same as the value of field ⑤ in SOF, that is: 1: gray image is; 3: YCrCb or YIQ; 4: CMYK.
- ③ Color component information
- a) Color component ID 1 byte
- b) DC / AC coefficient table No. 1 byte
High 4 bits: Huffman tree number used for DC component
Lower 4 digits: Huffman tree number used for AC component
- ④ Compressed image data
- a) Spectrum selection start 1 byte fixed value 0x00
- b) Spectrum selection end 1 byte fixed value 0x3F
- c) 1 byte of spectrum selection is always 00 in basic JPEG
-
EOI: End of Image: 2 bytes; Tag code: 2 bytes, fixed value: 0xFFD9
2. JPEG encoding process
The process of JPEG encoding is shown in the figure below, and decoding is the inverse process of encoding.
(2) Program implementation
1. Read file
enum std_markers { DQT = 0xDB, /* Define Quantization Table */ SOF = 0xC0, /* Start of Frame (size information) */ DHT = 0xC4, /* Huffman Table */ SOI = 0xD8, /* Start of Image */ SOS = 0xDA, /* Start of Scan */ RST = 0xD0, /* Reset Marker d0 -> .. */ RST7 = 0xD7, /* Reset Marker .. -> d7 */ EOI = 0xD9, /* End of Image */ DRI = 0xDD, /* Define Restart Interval */ APP0 = 0xE0, };
Parsing Segment Marker
static int parse_SOS(struct jdec_private *priv, const unsigned char *stream) { unsigned int i, cid, table; unsigned int nr_components = stream[2]; #if TRACE fprintf(p_trace,"> SOS marker\n"); fflush(p_trace); #endif #if SANITY_CHECK if (nr_components != 3) snprintf(error_string, sizeof(error_string),"We only support YCbCr image\n"); #endif stream += 3; for (i=0;i<nr_components;i++) { cid = *stream++; table = *stream++; #if SANITY_CHECK if ((table&0xf)>=4) snprintf(error_string, sizeof(error_string),"We do not support more than 2 AC Huffman table\n"); if ((table>>4)>=4) snprintf(error_string, sizeof(error_string),"We do not support more than 2 DC Huffman table\n"); if (cid != priv->component_infos[i].cid) snprintf(error_string, sizeof(error_string),"SOS cid order (%d:%d) isn't compatible with the SOF marker (%d:%d)\n", i, cid, i, priv->component_infos[i].cid); #if TRACE fprintf(p_trace,"ComponentId:%d tableAC:%d tableDC:%d\n", cid, table&0xf, table>>4); fflush(p_trace); #endif #endif priv->component_infos[i].AC_table = &priv->HTAC[table&0xf]; priv->component_infos[i].DC_table = &priv->HTDC[table>>4]; } priv->stream = stream+3; #if TRACE fprintf(p_trace,"< SOS marker\n"); fflush(p_trace); #endif return 0; }
2. Resolve DQT
- Get the length of the quantization table (may contain multiple quantization tables)
- Get the accuracy of the quantization table
- Get and check the serial number of the quantization table (only 0-3)
- Get the contents of the quantization table (64 data)
static int parse_DQT(struct jdec_private *priv, const unsigned char *stream) { int qi; float *table; const unsigned char *dqt_block_end; FILE* DQTfile; #if TRACE fprintf(p_trace,"> DQT marker\n"); fflush(p_trace); #endif dqt_block_end = stream + be16_to_cpu(stream); stream += 2; /* Skip length */ while (stream < dqt_block_end) { qi = *stream++; #if SANITY_CHECK if (qi>>4) snprintf(error_string, sizeof(error_string),"16 bits quantization table is not supported\n"); if (qi>4) snprintf(error_string, sizeof(error_string),"No more 4 quantization table is supported (got %d)\n", qi); #endif table = priv->Q_tables[qi]; build_quantization_table(table, stream); stream += 64; } #if TRACE fprintf(p_trace,"< DQT marker\n"); fflush(p_trace); //************************************************ DQTfile = fopen("DQTfile.txt", "a"); fputs("Quantitative table\n", DQTfile); for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { fprintf(DQTfile, "%f ", *table); table++; } fputs("\n", DQTfile); } //************************************************ #endif return 0; }
Zig zag sorting
static const unsigned char zigzag[64] = { 0, 1, 5, 6, 14, 15, 27, 28, 2, 4, 7, 13, 16, 26, 29, 42, 3, 8, 12, 17, 25, 30, 41, 43, 9, 11, 18, 24, 31, 40, 44, 53, 10, 19, 23, 32, 39, 45, 52, 54, 20, 22, 33, 38, 46, 51, 55, 60, 21, 34, 37, 47, 50, 56, 59, 61, 35, 36, 48, 49, 57, 58, 62, 63 };
static void build_quantization_table(float *qtable, const unsigned char *ref_table) { /* Taken from libjpeg. Copyright Independent JPEG Group's LLM idct. * For float AA&N IDCT method, divisors are equal to quantization * coefficients scaled by scalefactor[row]*scalefactor[col], where * scalefactor[0] = 1 * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 * We apply a further scale factor of 8. * What's actually stored is 1/divisor so that the inner loop can * use a multiplication rather than a division. */ int i, j; static const double aanscalefactor[8] = { 1.0, 1.387039845, 1.306562965, 1.175875602, 1.0, 0.785694958, 0.541196100, 0.275899379 }; const unsigned char *zz = zigzag; for (i=0; i<8; i++) { for (j=0; j<8; j++) { *qtable++ = ref_table[*zz++] * aanscalefactor[i] * aanscalefactor[j]; } } }
3. Resolve SOF0
- Get the number of bits, length, width and color components of each sample
- Get the ID, horizontal sampling factor, vertical sampling factor and quantization table of each color component
Serial number (corresponding to the serial number in DQT)
static int parse_SOF(struct jdec_private *priv, const unsigned char *stream) { int i, width, height, nr_components, cid, sampling_factor; int Q_table; struct component *c; #if TRACE fprintf(p_trace,"> SOF marker\n"); fflush(p_trace); #endif print_SOF(stream); height = be16_to_cpu(stream+3); width = be16_to_cpu(stream+5); nr_components = stream[7]; #if SANITY_CHECK if (stream[2] != 8) snprintf(error_string, sizeof(error_string),"Precision other than 8 is not supported\n"); if (width>JPEG_MAX_WIDTH || height>JPEG_MAX_HEIGHT) snprintf(error_string, sizeof(error_string),"Width and Height (%dx%d) seems suspicious\n", width, height); if (nr_components != 3) snprintf(error_string, sizeof(error_string),"We only support YUV images\n"); if (height%16) snprintf(error_string, sizeof(error_string),"Height need to be a multiple of 16 (current height is %d)\n", height); if (width%16) snprintf(error_string, sizeof(error_string),"Width need to be a multiple of 16 (current Width is %d)\n", width); #endif stream += 8; for (i=0; i<nr_components; i++) { cid = *stream++; sampling_factor = *stream++; Q_table = *stream++; c = &priv->component_infos[i]; #if SANITY_CHECK c->cid = cid; if (Q_table >= COMPONENTS) snprintf(error_string, sizeof(error_string),"Bad Quantization table index (got %d, max allowed %d)\n", Q_table, COMPONENTS-1); #endif c->Vfactor = sampling_factor&0xf; c->Hfactor = sampling_factor>>4; c->Q_table = priv->Q_tables[Q_table]; #if TRACE fprintf(p_trace,"Component:%d factor:%dx%d Quantization table:%d\n", cid, c->Hfactor, c->Hfactor, Q_table ); fflush(p_trace); #endif } priv->width = width; priv->height = height; #if TRACE fprintf(p_trace,"< SOF marker\n"); fflush(p_trace); #endif return 0; }
static void print_SOF(const unsigned char *stream) { int width, height, nr_components, precision; #if TRACE const char *nr_components_to_string[] = { "????", "Grayscale", "????", "YCbCr", "CYMK" }; #endif precision = stream[2]; height = be16_to_cpu(stream+3); width = be16_to_cpu(stream+5); nr_components = stream[7]; #if TRACE fprintf(p_trace,"> SOF marker\n"); fprintf(p_trace,"Size:%dx%d nr_components:%d (%s) precision:%d\n", width, height, nr_components, nr_components_to_string[nr_components], precision); fflush(p_trace); #endif }
4. Parsing DHT
- Get the type (AC, DC) and serial number of Huffman table
- Reconstruct Huffman table from data
static int parse_DHT(struct jdec_private *priv, const unsigned char *stream) { unsigned int count, i; unsigned char huff_bits[17]; int length, index; FILE* HuffFile; HuffFile = fopen("huffmanFile.txt", "a"); length = be16_to_cpu(stream) - 2; stream += 2; /* Skip length */ #if TRACE fprintf(p_trace,"> DHT marker (length=%d)\n", length); fflush(p_trace); #endif while (length>0) { index = *stream++; /* We need to calculate the number of bytes 'vals' will takes */ huff_bits[0] = 0; count = 0; for (i=1; i<17; i++) { huff_bits[i] = *stream++; count += huff_bits[i]; } #if SANITY_CHECK if (count >= HUFFMAN_BITS_SIZE) snprintf(error_string, sizeof(error_string),"No more than %d bytes is allowed to describe a huffman table", HUFFMAN_BITS_SIZE); if ( (index &0xf) >= HUFFMAN_TABLES) snprintf(error_string, sizeof(error_string),"No more than %d Huffman tables is supported (got %d)\n", HUFFMAN_TABLES, index&0xf); #if TRACE fprintf(p_trace,"Huffman table %s[%d] length=%d\n", (index&0xf0)? "AC" : "DC", index & 0xf, count);//What table number does the index stand for fflush(p_trace); //***************************************************************************************************** fprintf(HuffFile, "Huffman table %s[%d] length=%d\r\n", (index & 0xf0) ? "AC" : "DC", index & 0xf, count); fflush(HuffFile); //***************************************************************************************************** #endif #endif if (index & 0xf0 ) build_huffman_table(huff_bits, stream, &priv->HTAC[index&0xf]); else build_huffman_table(huff_bits, stream, &priv->HTDC[index&0xf]); length -= 1; length -= 16; length -= count; stream += count; } #if TRACE fprintf(p_trace,"< DHT marker\n"); fflush(p_trace); #endif return 0; }
5. Parse SOS
- Get the serial number of Huffman table used to analyze the DC and AC values of each color component (corresponding to the serial number in DHT)
static int parse_SOS(struct jdec_private *priv, const unsigned char *stream) { unsigned int i, cid, table; unsigned int nr_components = stream[2]; #if TRACE fprintf(p_trace,"> SOS marker\n"); fflush(p_trace); #endif #if SANITY_CHECK if (nr_components != 3) snprintf(error_string, sizeof(error_string),"We only support YCbCr image\n"); #endif stream += 3; for (i=0;i<nr_components;i++) { cid = *stream++; table = *stream++; #if SANITY_CHECK if ((table&0xf)>=4) snprintf(error_string, sizeof(error_string),"We do not support more than 2 AC Huffman table\n"); if ((table>>4)>=4) snprintf(error_string, sizeof(error_string),"We do not support more than 2 DC Huffman table\n"); if (cid != priv->component_infos[i].cid) snprintf(error_string, sizeof(error_string),"SOS cid order (%d:%d) isn't compatible with the SOF marker (%d:%d)\n", i, cid, i, priv->component_infos[i].cid); #if TRACE fprintf(p_trace,"ComponentId:%d tableAC:%d tableDC:%d\n", cid, table&0xf, table>>4); fflush(p_trace); #endif #endif priv->component_infos[i].AC_table = &priv->HTAC[table&0xf]; priv->component_infos[i].DC_table = &priv->HTDC[table>>4]; } priv->stream = stream+3; #if TRACE fprintf(p_trace,"< SOS marker\n"); fflush(p_trace); #endif return 0; }
6,MCU
- The size of MCU is calculated according to the horizontal and vertical sampling factors of each component, and the number of 8 * 8 macroblocks in each MCU is obtained
- Huffman decoding is performed on each macroblock to obtain DCT coefficients
- Perform IDCT on DCT coefficients of each macroblock to obtain Y, Cb and Cr
- When Segment Marker RST is encountered, clear the previous DC DCT coefficient
- All MCU are decoded and decoding is finished
- Convert Y, Cb and Cr into the required color space and save it.
static void decode_MCU_1x1_3planes(struct jdec_private *priv) { // Y process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y, 8); // Cb process_Huffman_data_unit(priv, cCb); IDCT(&priv->component_infos[cCb], priv->Cb, 8); // Cr process_Huffman_data_unit(priv, cCr); IDCT(&priv->component_infos[cCr], priv->Cr, 8); } /* * Decode a 1x1 directly in 1 color */ static void decode_MCU_1x1_1plane(struct jdec_private *priv) { // Y process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y, 8); // Cb process_Huffman_data_unit(priv, cCb); IDCT(&priv->component_infos[cCb], priv->Cb, 8); // Cr process_Huffman_data_unit(priv, cCr); IDCT(&priv->component_infos[cCr], priv->Cr, 8); } /* * Decode a 2x1 * .-------. * | 1 | 2 | * `-------' */ static void decode_MCU_2x1_3planes(struct jdec_private *priv) { // Y process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y, 16); process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y+8, 16); // Cb process_Huffman_data_unit(priv, cCb); IDCT(&priv->component_infos[cCb], priv->Cb, 8); // Cr process_Huffman_data_unit(priv, cCr); IDCT(&priv->component_infos[cCr], priv->Cr, 8); } /* * Decode a 2x1 * .-------. * | 1 | 2 | * `-------' */ static void decode_MCU_2x1_1plane(struct jdec_private *priv) { // Y process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y, 16); process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y+8, 16); // Cb process_Huffman_data_unit(priv, cCb); // Cr process_Huffman_data_unit(priv, cCr); } /* * Decode a 2x2 * .-------. * | 1 | 2 | * |---+---| * | 3 | 4 | * `-------' */ static void decode_MCU_2x2_3planes(struct jdec_private *priv) { // Y process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y, 16); process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y+8, 16); process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y+64*2, 16); process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y+64*2+8, 16); // Cb process_Huffman_data_unit(priv, cCb); IDCT(&priv->component_infos[cCb], priv->Cb, 8); // Cr process_Huffman_data_unit(priv, cCr); IDCT(&priv->component_infos[cCr], priv->Cr, 8); } /* * Decode a 2x2 directly in GREY format (8bits) * .-------. * | 1 | 2 | * |---+---| * | 3 | 4 | * `-------' */ static void decode_MCU_2x2_1plane(struct jdec_private *priv) { // Y process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y, 16); process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y+8, 16); process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y+64*2, 16); process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y+64*2+8, 16); // Cb process_Huffman_data_unit(priv, cCb); // Cr process_Huffman_data_unit(priv, cCr); } /* * Decode a 1x2 mcu * .---. * | 1 | * |---| * | 2 | * `---' */ static void decode_MCU_1x2_3planes(struct jdec_private *priv) { // Y process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y, 8); process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y+64, 8); // Cb process_Huffman_data_unit(priv, cCb); IDCT(&priv->component_infos[cCb], priv->Cb, 8); // Cr process_Huffman_data_unit(priv, cCr); IDCT(&priv->component_infos[cCr], priv->Cr, 8); } /* * Decode a 1x2 mcu * .---. * | 1 | * |---| * | 2 | * `---' */ static void decode_MCU_1x2_1plane(struct jdec_private *priv) { // Y process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y, 8); process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y+64, 8); // Cb process_Huffman_data_unit(priv, cCb); // Cr process_Huffman_data_unit(priv, cCr); }
7,tinyjpeg.c complete procedure
/* * Small jpeg decoder library * * Copyright (c) 2006, Luc Saillard <luc@saillard.org> * All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * - Neither the name of the author nor the names of its contributors may be * used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "stdint.h" #include <errno.h> #include "tinyjpeg.h" #include "tinyjpeg-internal.h" #define snprintf _snprintf enum std_markers { DQT = 0xDB, /* Define Quantization Table */ SOF = 0xC0, /* Start of Frame (size information) */ DHT = 0xC4, /* Huffman Table */ SOI = 0xD8, /* Start of Image */ SOS = 0xDA, /* Start of Scan */ RST = 0xD0, /* Reset Marker d0 -> .. */ RST7 = 0xD7, /* Reset Marker .. -> d7 */ EOI = 0xD9, /* End of Image */ DRI = 0xDD, /* Define Restart Interval */ APP0 = 0xE0, }; #define cY 0 #define cCb 1 #define cCr 2 #define BLACK_Y 0 #define BLACK_U 127 #define BLACK_V 127 // #if DEBUG // #define trace(fmt, args...) do { \ // fprintf(stderr, fmt, ## args); \ // fflush(stderr); \ // } while(0) // #else // #define trace(fmt, args...) do { } while (0) // #endif // #define error(fmt, args...) do { \ // snprintf(error_string, sizeof(error_string), fmt, ## args); \ // return -1; \ // } while(0) // #if DEBUG // #define trace #if 0 static char *print_bits(unsigned int value, char *bitstr) { int i, j; i=31; while (i>0) { if (value & (1UL<<i)) break; i--; } j=0; while (i>=0) { bitstr[j++] = (value & (1UL<<i))?'1':'0'; i--; } bitstr[j] = 0; return bitstr; } static void print_next_16bytes(int offset, const unsigned char *stream) { #if TRACE fprintf(p_trace,"%4.4x: %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", offset, stream[0], stream[1], stream[2], stream[3], stream[4], stream[5], stream[6], stream[7], stream[8], stream[9], stream[10], stream[11], stream[12], stream[13], stream[14], stream[15]); fflush(p_trace); #endif } #endif /* Global variable to return the last snprintf found while deconding */ //static char error_string[256]; static const unsigned char zigzag[64] = { 0, 1, 5, 6, 14, 15, 27, 28, 2, 4, 7, 13, 16, 26, 29, 42, 3, 8, 12, 17, 25, 30, 41, 43, 9, 11, 18, 24, 31, 40, 44, 53, 10, 19, 23, 32, 39, 45, 52, 54, 20, 22, 33, 38, 46, 51, 55, 60, 21, 34, 37, 47, 50, 56, 59, 61, 35, 36, 48, 49, 57, 58, 62, 63 }; /* Set up the standard Huffman tables (cf. JPEG standard section K.3) */ /* IMPORTANT: these are only valid for 8-bit data precision! */ static const unsigned char bits_dc_luminance[17] = { 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 }; static const unsigned char val_dc_luminance[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; static const unsigned char bits_dc_chrominance[17] = { 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 }; static const unsigned char val_dc_chrominance[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; static const unsigned char bits_ac_luminance[17] = { 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d }; static const unsigned char val_ac_luminance[] = { 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa }; static const unsigned char bits_ac_chrominance[17] = { 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 }; static const unsigned char val_ac_chrominance[] = { 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa }; /* * 4 functions to manage the stream * * fill_nbits: put at least nbits in the reservoir of bits. * But convert any 0xff,0x00 into 0xff * get_nbits: read nbits from the stream, and put it in result, * bits is removed from the stream and the reservoir is filled * automaticaly. The result is signed according to the number of * bits. * look_nbits: read nbits from the stream without marking as read. * skip_nbits: read nbits from the stream but do not return the result. * * stream: current pointer in the jpeg data (read bytes per bytes) * nbits_in_reservoir: number of bits filled into the reservoir * reservoir: register that contains bits information. Only nbits_in_reservoir * is valid. * nbits_in_reservoir * <-- 17 bits --> * Ex: 0000 0000 1010 0000 1111 0000 <== reservoir * ^ * bit 1 * To get two bits from this example * result = (reservoir >> 15) & 3 * */ #define fill_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted) do { \ while (nbits_in_reservoir<nbits_wanted) \ { \ unsigned char c; \ if (stream >= priv->stream_end) \ longjmp(priv->jump_state, -EIO); \ c = *stream++; \ reservoir <<= 8; \ if (c == 0xff && *stream == 0x00) \ stream++; \ reservoir |= c; \ nbits_in_reservoir+=8; \ } \ } while(0); /* Signed version !!!! */ #define get_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted,result) do { \ fill_nbits(reservoir,nbits_in_reservoir,stream,(nbits_wanted)); \ result = ((reservoir)>>(nbits_in_reservoir-(nbits_wanted))); \ nbits_in_reservoir -= (nbits_wanted); \ reservoir &= ((1U<<nbits_in_reservoir)-1); \ if ((unsigned int)result < (1UL<<((nbits_wanted)-1))) \ result += (0xFFFFFFFFUL<<(nbits_wanted))+1; \ } while(0); #define look_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted,result) do { \ fill_nbits(reservoir,nbits_in_reservoir,stream,(nbits_wanted)); \ result = ((reservoir)>>(nbits_in_reservoir-(nbits_wanted))); \ } while(0); /* To speed up the decoding, we assume that the reservoir have enough bit * slow version: * #define skip_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted) do { \ * fill_nbits(reservoir,nbits_in_reservoir,stream,(nbits_wanted)); \ * nbits_in_reservoir -= (nbits_wanted); \ * reservoir &= ((1U<<nbits_in_reservoir)-1); \ * } while(0); */ #define skip_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted) do { \ nbits_in_reservoir -= (nbits_wanted); \ reservoir &= ((1U<<nbits_in_reservoir)-1); \ } while(0); #define be16_to_cpu(x) (((x)[0]<<8)|(x)[1]) static void resync(struct jdec_private *priv); /** * Get the next (valid) huffman code in the stream. * * To speedup the procedure, we look HUFFMAN_HASH_NBITS bits and the code is * lower than HUFFMAN_HASH_NBITS we have automaticaly the length of the code * and the value by using two lookup table. * Else if the value is not found, just search (linear) into an array for each * bits is the code is present. * * If the code is not present for any reason, -1 is return. */ static int get_next_huffman_code(struct jdec_private *priv, struct huffman_table *huffman_table) { int value, hcode; unsigned int extra_nbits, nbits; uint16_t *slowtable; look_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, HUFFMAN_HASH_NBITS, hcode); value = huffman_table->lookup[hcode]; if (__likely(value >= 0)) { unsigned int code_size = huffman_table->code_size[value]; skip_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, code_size); return value; } /* Decode more bits each time ... */ for (extra_nbits=0; extra_nbits<16-HUFFMAN_HASH_NBITS; extra_nbits++) { nbits = HUFFMAN_HASH_NBITS + 1 + extra_nbits; look_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, nbits, hcode); slowtable = huffman_table->slowtable[extra_nbits]; /* Search if the code is in this array */ while (slowtable[0]) { if (slowtable[0] == hcode) { skip_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, nbits); return slowtable[1]; } slowtable+=2; } } return 0; } /** * * Decode a single block that contains the DCT coefficients. * The table coefficients is already dezigzaged at the end of the operation. * */ static void process_Huffman_data_unit(struct jdec_private *priv, int component) { unsigned char j; unsigned int huff_code; unsigned char size_val, count_0; struct component *c = &priv->component_infos[component]; short int DCT[64]; /* Initialize the DCT coef table */ memset(DCT, 0, sizeof(DCT)); /* DC coefficient decoding */ huff_code = get_next_huffman_code(priv, c->DC_table); //trace("+ %x\n", huff_code); if (huff_code) { get_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, huff_code, DCT[0]); DCT[0] += c->previous_DC; c->previous_DC = DCT[0]; } else { DCT[0] = c->previous_DC; } /* AC coefficient decoding */ j = 1; while (j<64) { huff_code = get_next_huffman_code(priv, c->AC_table); //trace("- %x\n", huff_code); size_val = huff_code & 0xF; count_0 = huff_code >> 4; if (size_val == 0) { /* RLE */ if (count_0 == 0) break; /* EOB found, go out */ else if (count_0 == 0xF) j += 16; /* skip 16 zeros */ } else { j += count_0; /* skip count_0 zeroes */ if (__unlikely(j >= 64)) { snprintf(error_string, sizeof(error_string), "Bad huffman data (buffer overflow)"); break; } get_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, size_val, DCT[j]); j++; } } for (j = 0; j < 64; j++) c->DCT[j] = DCT[zigzag[j]]; } /* * Takes two array of bits, and build the huffman table for size, and code * * lookup will return the symbol if the code is less or equal than HUFFMAN_HASH_NBITS. * code_size will be used to known how many bits this symbol is encoded. * slowtable will be used when the first lookup didn't give the result. */ static void build_huffman_table(const unsigned char *bits, const unsigned char *vals, struct huffman_table *table) { unsigned int i, j, code, code_size, val, nbits; unsigned char huffsize[HUFFMAN_BITS_SIZE+1], *hz; unsigned int huffcode[HUFFMAN_BITS_SIZE+1], *hc; int next_free_entry; /* * Build a temp array * huffsize[X] => numbers of bits to write vals[X] */ hz = huffsize; for (i=1; i<=16; i++) { for (j=1; j<=bits[i]; j++) *hz++ = i; } *hz = 0; memset(table->lookup, 0xff, sizeof(table->lookup)); for (i=0; i<(16-HUFFMAN_HASH_NBITS); i++) table->slowtable[i][0] = 0; /* Build a temp array * huffcode[X] => code used to write vals[X] */ code = 0; hc = huffcode; hz = huffsize; nbits = *hz; while (*hz) { while (*hz == nbits) { *hc++ = code++; hz++; } code <<= 1; nbits++; } /* * Build the lookup table, and the slowtable if needed. */ next_free_entry = -1; for (i=0; huffsize[i]; i++) { val = vals[i]; code = huffcode[i]; code_size = huffsize[i]; #if TRACE fprintf(p_trace,"val=%2.2x code=%8.8x codesize=%2.2d\n", val, code, code_size); fflush(p_trace); #endif table->code_size[val] = code_size; if (code_size <= HUFFMAN_HASH_NBITS) { /* * Good: val can be put in the lookup table, so fill all value of this * column with value val */ int repeat = 1UL<<(HUFFMAN_HASH_NBITS - code_size); code <<= HUFFMAN_HASH_NBITS - code_size; while ( repeat-- ) table->lookup[code++] = val; } else { /* Perhaps sorting the array will be an optimization */ uint16_t *slowtable = table->slowtable[code_size-HUFFMAN_HASH_NBITS-1]; while(slowtable[0]) slowtable+=2; slowtable[0] = code; slowtable[1] = val; slowtable[2] = 0; /* TODO: NEED TO CHECK FOR AN OVERFLOW OF THE TABLE */ } } } static void build_default_huffman_tables(struct jdec_private *priv) { if ( (priv->flags & TINYJPEG_FLAGS_MJPEG_TABLE) && priv->default_huffman_table_initialized) return; build_huffman_table(bits_dc_luminance, val_dc_luminance, &priv->HTDC[0]); build_huffman_table(bits_ac_luminance, val_ac_luminance, &priv->HTAC[0]); build_huffman_table(bits_dc_chrominance, val_dc_chrominance, &priv->HTDC[1]); build_huffman_table(bits_ac_chrominance, val_ac_chrominance, &priv->HTAC[1]); priv->default_huffman_table_initialized = 1; } /******************************************************************************* * * Colorspace conversion routine * * * Note: * YCbCr is defined per CCIR 601-1, except that Cb and Cr are * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5. * The conversion equations to be implemented are therefore * R = Y + 1.40200 * Cr * G = Y - 0.34414 * Cb - 0.71414 * Cr * B = Y + 1.77200 * Cb * ******************************************************************************/ static unsigned char clamp(int i) { if (i<0) return 0; else if (i>255) return 255; else return i; } /** * YCrCb -> YUV420P (1x1) * .---. * | 1 | * `---' */ static void YCrCB_to_YUV420P_1x1(struct jdec_private *priv) { const unsigned char *s, *y; unsigned char *p; int i,j; p = priv->plane[0]; y = priv->Y; for (i=0; i<8; i++) { memcpy(p, y, 8); p+=priv->width; y+=8; } p = priv->plane[1]; s = priv->Cb; for (i=0; i<8; i+=2) { for (j=0; j<8; j+=2, s+=2) *p++ = *s; s += 8; /* Skip one line */ p += priv->width/2 - 4; } p = priv->plane[2]; s = priv->Cr; for (i=0; i<8; i+=2) { for (j=0; j<8; j+=2, s+=2) *p++ = *s; s += 8; /* Skip one line */ p += priv->width/2 - 4; } } /** * YCrCb -> YUV420P (2x1) * .-------. * | 1 | 2 | * `-------' */ static void YCrCB_to_YUV420P_2x1(struct jdec_private *priv) { unsigned char *p; const unsigned char *s, *y1; unsigned int i; p = priv->plane[0]; y1 = priv->Y; for (i=0; i<8; i++) { memcpy(p, y1, 16); p += priv->width; y1 += 16; } p = priv->plane[1]; s = priv->Cb; for (i=0; i<8; i+=2) { memcpy(p, s, 8); s += 16; /* Skip one line */ p += priv->width/2; } p = priv->plane[2]; s = priv->Cr; for (i=0; i<8; i+=2) { memcpy(p, s, 8); s += 16; /* Skip one line */ p += priv->width/2; } } /** * YCrCb -> YUV420P (1x2) * .---. * | 1 | * |---| * | 2 | * `---' */ static void YCrCB_to_YUV420P_1x2(struct jdec_private *priv) { const unsigned char *s, *y; unsigned char *p; int i,j; p = priv->plane[0]; y = priv->Y; for (i=0; i<16; i++) { memcpy(p, y, 8); p+=priv->width; y+=8; } p = priv->plane[1]; s = priv->Cb; for (i=0; i<8; i++) { for (j=0; j<8; j+=2, s+=2) *p++ = *s; p += priv->width/2 - 4; } p = priv->plane[2]; s = priv->Cr; for (i=0; i<8; i++) { for (j=0; j<8; j+=2, s+=2) *p++ = *s; p += priv->width/2 - 4; } } /** * YCrCb -> YUV420P (2x2) * .-------. * | 1 | 2 | * |---+---| * | 3 | 4 | * `-------' */ static void YCrCB_to_YUV420P_2x2(struct jdec_private *priv) { unsigned char *p; const unsigned char *s, *y1; unsigned int i; p = priv->plane[0]; y1 = priv->Y; for (i=0; i<16; i++) { memcpy(p, y1, 16); p += priv->width; y1 += 16; } p = priv->plane[1]; s = priv->Cb; for (i=0; i<8; i++) { memcpy(p, s, 8); s += 8; p += priv->width/2; } p = priv->plane[2]; s = priv->Cr; for (i=0; i<8; i++) { memcpy(p, s, 8); s += 8; p += priv->width/2; } } /** * YCrCb -> RGB24 (1x1) * .---. * | 1 | * `---' */ static void YCrCB_to_RGB24_1x1(struct jdec_private *priv) { const unsigned char *Y, *Cb, *Cr; unsigned char *p; int i,j; int offset_to_next_row; #define SCALEBITS 10 #define ONE_HALF (1UL << (SCALEBITS-1)) #define FIX(x) ((int)((x) * (1UL<<SCALEBITS) + 0.5)) p = priv->plane[0]; Y = priv->Y; Cb = priv->Cb; Cr = priv->Cr; offset_to_next_row = priv->width*3 - 8*3; for (i=0; i<8; i++) { for (j=0; j<8; j++) { int y, cb, cr; int add_r, add_g, add_b; int r, g , b; y = (*Y++) << SCALEBITS; cb = *Cb++ - 128; cr = *Cr++ - 128; add_r = FIX(1.40200) * cr + ONE_HALF; add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF; add_b = FIX(1.77200) * cb + ONE_HALF; r = (y + add_r) >> SCALEBITS; *p++ = clamp(r); g = (y + add_g) >> SCALEBITS; *p++ = clamp(g); b = (y + add_b) >> SCALEBITS; *p++ = clamp(b); } p += offset_to_next_row; } #undef SCALEBITS #undef ONE_HALF #undef FIX } /** * YCrCb -> BGR24 (1x1) * .---. * | 1 | * `---' */ static void YCrCB_to_BGR24_1x1(struct jdec_private *priv) { const unsigned char *Y, *Cb, *Cr; unsigned char *p; int i,j; int offset_to_next_row; #define SCALEBITS 10 #define ONE_HALF (1UL << (SCALEBITS-1)) #define FIX(x) ((int)((x) * (1UL<<SCALEBITS) + 0.5)) p = priv->plane[0]; Y = priv->Y; Cb = priv->Cb; Cr = priv->Cr; offset_to_next_row = priv->width*3 - 8*3; for (i=0; i<8; i++) { for (j=0; j<8; j++) { int y, cb, cr; int add_r, add_g, add_b; int r, g , b; y = (*Y++) << SCALEBITS; cb = *Cb++ - 128; cr = *Cr++ - 128; add_r = FIX(1.40200) * cr + ONE_HALF; add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF; add_b = FIX(1.77200) * cb + ONE_HALF; b = (y + add_b) >> SCALEBITS; *p++ = clamp(b); g = (y + add_g) >> SCALEBITS; *p++ = clamp(g); r = (y + add_r) >> SCALEBITS; *p++ = clamp(r); } p += offset_to_next_row; } #undef SCALEBITS #undef ONE_HALF #undef FIX } /** * YCrCb -> RGB24 (2x1) * .-------. * | 1 | 2 | * `-------' */ static void YCrCB_to_RGB24_2x1(struct jdec_private *priv) { const unsigned char *Y, *Cb, *Cr; unsigned char *p; int i,j; int offset_to_next_row; #define SCALEBITS 10 #define ONE_HALF (1UL << (SCALEBITS-1)) #define FIX(x) ((int)((x) * (1UL<<SCALEBITS) + 0.5)) p = priv->plane[0]; Y = priv->Y; Cb = priv->Cb; Cr = priv->Cr; offset_to_next_row = priv->width*3 - 16*3; for (i=0; i<8; i++) { for (j=0; j<8; j++) { int y, cb, cr; int add_r, add_g, add_b; int r, g , b; y = (*Y++) << SCALEBITS; cb = *Cb++ - 128; cr = *Cr++ - 128; add_r = FIX(1.40200) * cr + ONE_HALF; add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF; add_b = FIX(1.77200) * cb + ONE_HALF; r = (y + add_r) >> SCALEBITS; *p++ = clamp(r); g = (y + add_g) >> SCALEBITS; *p++ = clamp(g); b = (y + add_b) >> SCALEBITS; *p++ = clamp(b); y = (*Y++) << SCALEBITS; r = (y + add_r) >> SCALEBITS; *p++ = clamp(r); g = (y + add_g) >> SCALEBITS; *p++ = clamp(g); b = (y + add_b) >> SCALEBITS; *p++ = clamp(b); } p += offset_to_next_row; } #undef SCALEBITS #undef ONE_HALF #undef FIX } /* * YCrCb -> BGR24 (2x1) * .-------. * | 1 | 2 | * `-------' */ static void YCrCB_to_BGR24_2x1(struct jdec_private *priv) { const unsigned char *Y, *Cb, *Cr; unsigned char *p; int i,j; int offset_to_next_row; #define SCALEBITS 10 #define ONE_HALF (1UL << (SCALEBITS-1)) #define FIX(x) ((int)((x) * (1UL<<SCALEBITS) + 0.5)) p = priv->plane[0]; Y = priv->Y; Cb = priv->Cb; Cr = priv->Cr; offset_to_next_row = priv->width*3 - 16*3; for (i=0; i<8; i++) { for (j=0; j<8; j++) { int y, cb, cr; int add_r, add_g, add_b; int r, g , b; cb = *Cb++ - 128; cr = *Cr++ - 128; add_r = FIX(1.40200) * cr + ONE_HALF; add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF; add_b = FIX(1.77200) * cb + ONE_HALF; y = (*Y++) << SCALEBITS; b = (y + add_b) >> SCALEBITS; *p++ = clamp(b); g = (y + add_g) >> SCALEBITS; *p++ = clamp(g); r = (y + add_r) >> SCALEBITS; *p++ = clamp(r); y = (*Y++) << SCALEBITS; b = (y + add_b) >> SCALEBITS; *p++ = clamp(b); g = (y + add_g) >> SCALEBITS; *p++ = clamp(g); r = (y + add_r) >> SCALEBITS; *p++ = clamp(r); } p += offset_to_next_row; } #undef SCALEBITS #undef ONE_HALF #undef FIX } /** * YCrCb -> RGB24 (1x2) * .---. * | 1 | * |---| * | 2 | * `---' */ static void YCrCB_to_RGB24_1x2(struct jdec_private *priv) { const unsigned char *Y, *Cb, *Cr; unsigned char *p, *p2; int i,j; int offset_to_next_row; #define SCALEBITS 10 #define ONE_HALF (1UL << (SCALEBITS-1)) #define FIX(x) ((int)((x) * (1UL<<SCALEBITS) + 0.5)) p = priv->plane[0]; p2 = priv->plane[0] + priv->width*3; Y = priv->Y; Cb = priv->Cb; Cr = priv->Cr; offset_to_next_row = 2*priv->width*3 - 8*3; for (i=0; i<8; i++) { for (j=0; j<8; j++) { int y, cb, cr; int add_r, add_g, add_b; int r, g , b; cb = *Cb++ - 128; cr = *Cr++ - 128; add_r = FIX(1.40200) * cr + ONE_HALF; add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF; add_b = FIX(1.77200) * cb + ONE_HALF; y = (*Y++) << SCALEBITS; r = (y + add_r) >> SCALEBITS; *p++ = clamp(r); g = (y + add_g) >> SCALEBITS; *p++ = clamp(g); b = (y + add_b) >> SCALEBITS; *p++ = clamp(b); y = (Y[8-1]) << SCALEBITS; r = (y + add_r) >> SCALEBITS; *p2++ = clamp(r); g = (y + add_g) >> SCALEBITS; *p2++ = clamp(g); b = (y + add_b) >> SCALEBITS; *p2++ = clamp(b); } Y += 8; p += offset_to_next_row; p2 += offset_to_next_row; } #undef SCALEBITS #undef ONE_HALF #undef FIX } /* * YCrCb -> BGR24 (1x2) * .---. * | 1 | * |---| * | 2 | * `---' */ static void YCrCB_to_BGR24_1x2(struct jdec_private *priv) { const unsigned char *Y, *Cb, *Cr; unsigned char *p, *p2; int i,j; int offset_to_next_row; #define SCALEBITS 10 #define ONE_HALF (1UL << (SCALEBITS-1)) #define FIX(x) ((int)((x) * (1UL<<SCALEBITS) + 0.5)) p = priv->plane[0]; p2 = priv->plane[0] + priv->width*3; Y = priv->Y; Cb = priv->Cb; Cr = priv->Cr; offset_to_next_row = 2*priv->width*3 - 8*3; for (i=0; i<8; i++) { for (j=0; j<8; j++) { int y, cb, cr; int add_r, add_g, add_b; int r, g , b; cb = *Cb++ - 128; cr = *Cr++ - 128; add_r = FIX(1.40200) * cr + ONE_HALF; add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF; add_b = FIX(1.77200) * cb + ONE_HALF; y = (*Y++) << SCALEBITS; b = (y + add_b) >> SCALEBITS; *p++ = clamp(b); g = (y + add_g) >> SCALEBITS; *p++ = clamp(g); r = (y + add_r) >> SCALEBITS; *p++ = clamp(r); y = (Y[8-1]) << SCALEBITS; b = (y + add_b) >> SCALEBITS; *p2++ = clamp(b); g = (y + add_g) >> SCALEBITS; *p2++ = clamp(g); r = (y + add_r) >> SCALEBITS; *p2++ = clamp(r); } Y += 8; p += offset_to_next_row; p2 += offset_to_next_row; } #undef SCALEBITS #undef ONE_HALF #undef FIX } /** * YCrCb -> RGB24 (2x2) * .-------. * | 1 | 2 | * |---+---| * | 3 | 4 | * `-------' */ static void YCrCB_to_RGB24_2x2(struct jdec_private *priv) { const unsigned char *Y, *Cb, *Cr; unsigned char *p, *p2; int i,j; int offset_to_next_row; #define SCALEBITS 10 #define ONE_HALF (1UL << (SCALEBITS-1)) #define FIX(x) ((int)((x) * (1UL<<SCALEBITS) + 0.5)) p = priv->plane[0]; p2 = priv->plane[0] + priv->width*3; Y = priv->Y; Cb = priv->Cb; Cr = priv->Cr; offset_to_next_row = (priv->width*3*2) - 16*3; for (i=0; i<8; i++) { for (j=0; j<8; j++) { int y, cb, cr; int add_r, add_g, add_b; int r, g , b; cb = *Cb++ - 128; cr = *Cr++ - 128; add_r = FIX(1.40200) * cr + ONE_HALF; add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF; add_b = FIX(1.77200) * cb + ONE_HALF; y = (*Y++) << SCALEBITS; r = (y + add_r) >> SCALEBITS; *p++ = clamp(r); g = (y + add_g) >> SCALEBITS; *p++ = clamp(g); b = (y + add_b) >> SCALEBITS; *p++ = clamp(b); y = (*Y++) << SCALEBITS; r = (y + add_r) >> SCALEBITS; *p++ = clamp(r); g = (y + add_g) >> SCALEBITS; *p++ = clamp(g); b = (y + add_b) >> SCALEBITS; *p++ = clamp(b); y = (Y[16-2]) << SCALEBITS; r = (y + add_r) >> SCALEBITS; *p2++ = clamp(r); g = (y + add_g) >> SCALEBITS; *p2++ = clamp(g); b = (y + add_b) >> SCALEBITS; *p2++ = clamp(b); y = (Y[16-1]) << SCALEBITS; r = (y + add_r) >> SCALEBITS; *p2++ = clamp(r); g = (y + add_g) >> SCALEBITS; *p2++ = clamp(g); b = (y + add_b) >> SCALEBITS; *p2++ = clamp(b); } Y += 16; p += offset_to_next_row; p2 += offset_to_next_row; } #undef SCALEBITS #undef ONE_HALF #undef FIX } /* * YCrCb -> BGR24 (2x2) * .-------. * | 1 | 2 | * |---+---| * | 3 | 4 | * `-------' */ static void YCrCB_to_BGR24_2x2(struct jdec_private *priv) { const unsigned char *Y, *Cb, *Cr; unsigned char *p, *p2; int i,j; int offset_to_next_row; #define SCALEBITS 10 #define ONE_HALF (1UL << (SCALEBITS-1)) #define FIX(x) ((int)((x) * (1UL<<SCALEBITS) + 0.5)) p = priv->plane[0]; p2 = priv->plane[0] + priv->width*3; Y = priv->Y; Cb = priv->Cb; Cr = priv->Cr; offset_to_next_row = (priv->width*3*2) - 16*3; for (i=0; i<8; i++) { for (j=0; j<8; j++) { int y, cb, cr; int add_r, add_g, add_b; int r, g , b; cb = *Cb++ - 128; cr = *Cr++ - 128; add_r = FIX(1.40200) * cr + ONE_HALF; add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF; add_b = FIX(1.77200) * cb + ONE_HALF; y = (*Y++) << SCALEBITS; b = (y + add_b) >> SCALEBITS; *p++ = clamp(b); g = (y + add_g) >> SCALEBITS; *p++ = clamp(g); r = (y + add_r) >> SCALEBITS; *p++ = clamp(r); y = (*Y++) << SCALEBITS; b = (y + add_b) >> SCALEBITS; *p++ = clamp(b); g = (y + add_g) >> SCALEBITS; *p++ = clamp(g); r = (y + add_r) >> SCALEBITS; *p++ = clamp(r); y = (Y[16-2]) << SCALEBITS; b = (y + add_b) >> SCALEBITS; *p2++ = clamp(b); g = (y + add_g) >> SCALEBITS; *p2++ = clamp(g); r = (y + add_r) >> SCALEBITS; *p2++ = clamp(r); y = (Y[16-1]) << SCALEBITS; b = (y + add_b) >> SCALEBITS; *p2++ = clamp(b); g = (y + add_g) >> SCALEBITS; *p2++ = clamp(g); r = (y + add_r) >> SCALEBITS; *p2++ = clamp(r); } Y += 16; p += offset_to_next_row; p2 += offset_to_next_row; } #undef SCALEBITS #undef ONE_HALF #undef FIX } /** * YCrCb -> Grey (1x1) * .---. * | 1 | * `---' */ static void YCrCB_to_Grey_1x1(struct jdec_private *priv) { const unsigned char *y; unsigned char *p; unsigned int i; int offset_to_next_row; p = priv->plane[0]; y = priv->Y; offset_to_next_row = priv->width; for (i=0; i<8; i++) { memcpy(p, y, 8); y+=8; p += offset_to_next_row; } } /** * YCrCb -> Grey (2x1) * .-------. * | 1 | 2 | * `-------' */ static void YCrCB_to_Grey_2x1(struct jdec_private *priv) { const unsigned char *y; unsigned char *p; unsigned int i; p = priv->plane[0]; y = priv->Y; for (i=0; i<8; i++) { memcpy(p, y, 16); y += 16; p += priv->width; } } /** * YCrCb -> Grey (1x2) * .---. * | 1 | * |---| * | 2 | * `---' */ static void YCrCB_to_Grey_1x2(struct jdec_private *priv) { const unsigned char *y; unsigned char *p; unsigned int i; p = priv->plane[0]; y = priv->Y; for (i=0; i<16; i++) { memcpy(p, y, 8); y += 8; p += priv->width; } } /** * YCrCb -> Grey (2x2) * .-------. * | 1 | 2 | * |---+---| * | 3 | 4 | * `-------' */ static void YCrCB_to_Grey_2x2(struct jdec_private *priv) { const unsigned char *y; unsigned char *p; unsigned int i; p = priv->plane[0]; y = priv->Y; for (i=0; i<16; i++) { memcpy(p, y, 16); y += 16; p += priv->width; } } /* * Decode all the 3 components for 1x1 */ static void decode_MCU_1x1_3planes(struct jdec_private *priv) { // Y process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y, 8); // Cb process_Huffman_data_unit(priv, cCb); IDCT(&priv->component_infos[cCb], priv->Cb, 8); // Cr process_Huffman_data_unit(priv, cCr); IDCT(&priv->component_infos[cCr], priv->Cr, 8); } /* * Decode a 1x1 directly in 1 color */ static void decode_MCU_1x1_1plane(struct jdec_private *priv) { // Y process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y, 8); // Cb process_Huffman_data_unit(priv, cCb); IDCT(&priv->component_infos[cCb], priv->Cb, 8); // Cr process_Huffman_data_unit(priv, cCr); IDCT(&priv->component_infos[cCr], priv->Cr, 8); } /* * Decode a 2x1 * .-------. * | 1 | 2 | * `-------' */ static void decode_MCU_2x1_3planes(struct jdec_private *priv) { // Y process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y, 16); process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y+8, 16); // Cb process_Huffman_data_unit(priv, cCb); IDCT(&priv->component_infos[cCb], priv->Cb, 8); // Cr process_Huffman_data_unit(priv, cCr); IDCT(&priv->component_infos[cCr], priv->Cr, 8); } /* * Decode a 2x1 * .-------. * | 1 | 2 | * `-------' */ static void decode_MCU_2x1_1plane(struct jdec_private *priv) { // Y process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y, 16); process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y+8, 16); // Cb process_Huffman_data_unit(priv, cCb); // Cr process_Huffman_data_unit(priv, cCr); } /* * Decode a 2x2 * .-------. * | 1 | 2 | * |---+---| * | 3 | 4 | * `-------' */ static void decode_MCU_2x2_3planes(struct jdec_private *priv) { // Y process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y, 16); process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y+8, 16); process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y+64*2, 16); process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y+64*2+8, 16); // Cb process_Huffman_data_unit(priv, cCb); IDCT(&priv->component_infos[cCb], priv->Cb, 8); // Cr process_Huffman_data_unit(priv, cCr); IDCT(&priv->component_infos[cCr], priv->Cr, 8); } /* * Decode a 2x2 directly in GREY format (8bits) * .-------. * | 1 | 2 | * |---+---| * | 3 | 4 | * `-------' */ static void decode_MCU_2x2_1plane(struct jdec_private *priv) { // Y process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y, 16); process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y+8, 16); process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y+64*2, 16); process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y+64*2+8, 16); // Cb process_Huffman_data_unit(priv, cCb); // Cr process_Huffman_data_unit(priv, cCr); } /* * Decode a 1x2 mcu * .---. * | 1 | * |---| * | 2 | * `---' */ static void decode_MCU_1x2_3planes(struct jdec_private *priv) { // Y process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y, 8); process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y+64, 8); // Cb process_Huffman_data_unit(priv, cCb); IDCT(&priv->component_infos[cCb], priv->Cb, 8); // Cr process_Huffman_data_unit(priv, cCr); IDCT(&priv->component_infos[cCr], priv->Cr, 8); } /* * Decode a 1x2 mcu * .---. * | 1 | * |---| * | 2 | * `---' */ static void decode_MCU_1x2_1plane(struct jdec_private *priv) { // Y process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y, 8); process_Huffman_data_unit(priv, cY); IDCT(&priv->component_infos[cY], priv->Y+64, 8); // Cb process_Huffman_data_unit(priv, cCb); // Cr process_Huffman_data_unit(priv, cCr); } static void print_SOF(const unsigned char *stream) { int width, height, nr_components, precision; #if TRACE const char *nr_components_to_string[] = { "????", "Grayscale", "????", "YCbCr", "CYMK" }; #endif precision = stream[2]; height = be16_to_cpu(stream+3); width = be16_to_cpu(stream+5); nr_components = stream[7]; #if TRACE fprintf(p_trace,"> SOF marker\n"); fprintf(p_trace,"Size:%dx%d nr_components:%d (%s) precision:%d\n", width, height, nr_components, nr_components_to_string[nr_components], precision); fflush(p_trace); #endif } /******************************************************************************* * * JPEG/JFIF Parsing functions * * Note: only a small subset of the jpeg file format is supported. No markers, * nor progressive stream is supported. * ******************************************************************************/ static void build_quantization_table(float *qtable, const unsigned char *ref_table) { /* Taken from libjpeg. Copyright Independent JPEG Group's LLM idct. * For float AA&N IDCT method, divisors are equal to quantization * coefficients scaled by scalefactor[row]*scalefactor[col], where * scalefactor[0] = 1 * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 * We apply a further scale factor of 8. * What's actually stored is 1/divisor so that the inner loop can * use a multiplication rather than a division. */ int i, j; static const double aanscalefactor[8] = { 1.0, 1.387039845, 1.306562965, 1.175875602, 1.0, 0.785694958, 0.541196100, 0.275899379 }; const unsigned char *zz = zigzag; for (i=0; i<8; i++) { for (j=0; j<8; j++) { *qtable++ = ref_table[*zz++] * aanscalefactor[i] * aanscalefactor[j]; } } } static int parse_DQT(struct jdec_private *priv, const unsigned char *stream) { int qi; float *table; const unsigned char *dqt_block_end; FILE* DQTfile; #if TRACE fprintf(p_trace,"> DQT marker\n"); fflush(p_trace); #endif dqt_block_end = stream + be16_to_cpu(stream); stream += 2; /* Skip length */ while (stream < dqt_block_end) { qi = *stream++; #if SANITY_CHECK if (qi>>4) snprintf(error_string, sizeof(error_string),"16 bits quantization table is not supported\n"); if (qi>4) snprintf(error_string, sizeof(error_string),"No more 4 quantization table is supported (got %d)\n", qi); #endif table = priv->Q_tables[qi]; build_quantization_table(table, stream); stream += 64; } #if TRACE fprintf(p_trace,"< DQT marker\n"); fflush(p_trace); //************************************************ DQTfile = fopen("DQTfile.txt", "a"); fputs("Quantization table \ n", DQTfile); for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { fprintf(DQTfile, "%f ", *table); table++; } fputs("\n", DQTfile); } //************************************************ #endif return 0; } static int parse_SOF(struct jdec_private *priv, const unsigned char *stream) { int i, width, height, nr_components, cid, sampling_factor; int Q_table; struct component *c; #if TRACE fprintf(p_trace,"> SOF marker\n"); fflush(p_trace); #endif print_SOF(stream); height = be16_to_cpu(stream+3); width = be16_to_cpu(stream+5); nr_components = stream[7]; #if SANITY_CHECK if (stream[2] != 8) snprintf(error_string, sizeof(error_string),"Precision other than 8 is not supported\n"); if (width>JPEG_MAX_WIDTH || height>JPEG_MAX_HEIGHT) snprintf(error_string, sizeof(error_string),"Width and Height (%dx%d) seems suspicious\n", width, height); if (nr_components != 3) snprintf(error_string, sizeof(error_string),"We only support YUV images\n"); if (height%16) snprintf(error_string, sizeof(error_string),"Height need to be a multiple of 16 (current height is %d)\n", height); if (width%16) snprintf(error_string, sizeof(error_string),"Width need to be a multiple of 16 (current Width is %d)\n", width); #endif stream += 8; for (i=0; i<nr_components; i++) { cid = *stream++; sampling_factor = *stream++; Q_table = *stream++; c = &priv->component_infos[i]; #if SANITY_CHECK c->cid = cid; if (Q_table >= COMPONENTS) snprintf(error_string, sizeof(error_string),"Bad Quantization table index (got %d, max allowed %d)\n", Q_table, COMPONENTS-1); #endif c->Vfactor = sampling_factor&0xf; c->Hfactor = sampling_factor>>4; c->Q_table = priv->Q_tables[Q_table]; #if TRACE fprintf(p_trace,"Component:%d factor:%dx%d Quantization table:%d\n", cid, c->Hfactor, c->Hfactor, Q_table ); fflush(p_trace); #endif } priv->width = width; priv->height = height; #if TRACE fprintf(p_trace,"< SOF marker\n"); fflush(p_trace); #endif return 0; } static int parse_SOS(struct jdec_private *priv, const unsigned char *stream) { unsigned int i, cid, table; unsigned int nr_components = stream[2]; #if TRACE fprintf(p_trace,"> SOS marker\n"); fflush(p_trace); #endif #if SANITY_CHECK if (nr_components != 3) snprintf(error_string, sizeof(error_string),"We only support YCbCr image\n"); #endif stream += 3; for (i=0;i<nr_components;i++) { cid = *stream++; table = *stream++; #if SANITY_CHECK if ((table&0xf)>=4) snprintf(error_string, sizeof(error_string),"We do not support more than 2 AC Huffman table\n"); if ((table>>4)>=4) snprintf(error_string, sizeof(error_string),"We do not support more than 2 DC Huffman table\n"); if (cid != priv->component_infos[i].cid) snprintf(error_string, sizeof(error_string),"SOS cid order (%d:%d) isn't compatible with the SOF marker (%d:%d)\n", i, cid, i, priv->component_infos[i].cid); #if TRACE fprintf(p_trace,"ComponentId:%d tableAC:%d tableDC:%d\n", cid, table&0xf, table>>4); fflush(p_trace); #endif #endif priv->component_infos[i].AC_table = &priv->HTAC[table&0xf]; priv->component_infos[i].DC_table = &priv->HTDC[table>>4]; } priv->stream = stream+3; #if TRACE fprintf(p_trace,"< SOS marker\n"); fflush(p_trace); #endif return 0; } static int parse_DHT(struct jdec_private *priv, const unsigned char *stream) { unsigned int count, i; unsigned char huff_bits[17]; int length, index; FILE* HuffFile; HuffFile = fopen("huffmanFile.txt", "a"); length = be16_to_cpu(stream) - 2; stream += 2; /* Skip length */ #if TRACE fprintf(p_trace,"> DHT marker (length=%d)\n", length); fflush(p_trace); #endif while (length>0) { index = *stream++; /* We need to calculate the number of bytes 'vals' will takes */ huff_bits[0] = 0; count = 0; for (i=1; i<17; i++) { huff_bits[i] = *stream++; count += huff_bits[i]; } #if SANITY_CHECK if (count >= HUFFMAN_BITS_SIZE) snprintf(error_string, sizeof(error_string),"No more than %d bytes is allowed to describe a huffman table", HUFFMAN_BITS_SIZE); if ( (index &0xf) >= HUFFMAN_TABLES) snprintf(error_string, sizeof(error_string),"No more than %d Huffman tables is supported (got %d)\n", HUFFMAN_TABLES, index&0xf); #if TRACE fprintf(p_trace,"Huffman table %s[%d] length=%d\n", (index&0xf0)? "AC" : "DC", index & 0xf, count);//What table number does the index stand for fflush(p_trace); //***************************************************************************************************** fprintf(HuffFile, "Huffman table %s[%d] length=%d\r\n", (index & 0xf0) ? "AC" : "DC", index & 0xf, count); fflush(HuffFile); //***************************************************************************************************** #endif #endif if (index & 0xf0 ) build_huffman_table(huff_bits, stream, &priv->HTAC[index&0xf]); else build_huffman_table(huff_bits, stream, &priv->HTDC[index&0xf]); length -= 1; length -= 16; length -= count; stream += count; } #if TRACE fprintf(p_trace,"< DHT marker\n"); fflush(p_trace); #endif return 0; } static int parse_DRI(struct jdec_private *priv, const unsigned char *stream) { unsigned int length; #if TRACE fprintf(p_trace,"> DRI marker\n"); fflush(p_trace); #endif length = be16_to_cpu(stream); #if SANITY_CHECK if (length != 4) snprintf(error_string, sizeof(error_string),"Length of DRI marker need to be 4\n"); #endif priv->restart_interval = be16_to_cpu(stream+2); #if TRACE fprintf(p_trace,"Restart interval = %d\n", priv->restart_interval); fprintf(p_trace,"< DRI marker\n"); fflush(p_trace); #endif return 0; } static void resync(struct jdec_private *priv) { int i; /* Init DC coefficients */ for (i=0; i<COMPONENTS; i++) priv->component_infos[i].previous_DC = 0; priv->reservoir = 0; priv->nbits_in_reservoir = 0; if (priv->restart_interval > 0) priv->restarts_to_go = priv->restart_interval; else priv->restarts_to_go = -1; } static int find_next_rst_marker(struct jdec_private *priv) { int rst_marker_found = 0; int marker; const unsigned char *stream = priv->stream; /* Parse marker */ while (!rst_marker_found) { while (*stream++ != 0xff) { if (stream >= priv->stream_end) snprintf(error_string, sizeof(error_string),"EOF while search for a RST marker."); } /* Skip any padding ff byte (this is normal) */ while (*stream == 0xff) stream++; marker = *stream++; if ((RST+priv->last_rst_marker_seen) == marker) rst_marker_found = 1; else if (marker >= RST && marker <= RST7) snprintf(error_string, sizeof(error_string),"Wrong Reset marker found, abording"); else if (marker == EOI) return 0; } #if TRACE fprintf(p_trace,"RST Marker %d found at offset %d\n", priv->last_rst_marker_seen, stream - priv->stream_begin); fflush(p_trace); #endif priv->stream = stream; priv->last_rst_marker_seen++; priv->last_rst_marker_seen &= 7; return 0; } static int parse_JFIF(struct jdec_private *priv, const unsigned char *stream) { int chuck_len; int marker; int sos_marker_found = 0; int dht_marker_found = 0; const unsigned char *next_chunck; /* Parse marker */ while (!sos_marker_found) { if (*stream++ != 0xff) goto bogus_jpeg_format; /* Skip any padding ff byte (this is normal) */ while (*stream == 0xff) stream++; marker = *stream++; chuck_len = be16_to_cpu(stream); next_chunck = stream + chuck_len; switch (marker) { case SOF: if (parse_SOF(priv, stream) < 0) return -1; break; case DQT: if (parse_DQT(priv, stream) < 0) return -1; break; case SOS: if (parse_SOS(priv, stream) < 0) return -1; sos_marker_found = 1; break; case DHT: if (parse_DHT(priv, stream) < 0) return -1; dht_marker_found = 1; break; case DRI: if (parse_DRI(priv, stream) < 0) return -1; break; default: #if TRACE fprintf(p_trace,"> Unknown marker %2.2x\n", marker); fflush(p_trace); #endif break; } stream = next_chunck; } if (!dht_marker_found) { #if TRACE fprintf(p_trace,"No Huffman table loaded, using the default one\n"); fflush(p_trace); #endif build_default_huffman_tables(priv); } #ifdef SANITY_CHECK if ( (priv->component_infos[cY].Hfactor < priv->component_infos[cCb].Hfactor) || (priv->component_infos[cY].Hfactor < priv->component_infos[cCr].Hfactor)) snprintf(error_string, sizeof(error_string),"Horizontal sampling factor for Y should be greater than horitontal sampling factor for Cb or Cr\n"); if ( (priv->component_infos[cY].Vfactor < priv->component_infos[cCb].Vfactor) || (priv->component_infos[cY].Vfactor < priv->component_infos[cCr].Vfactor)) snprintf(error_string, sizeof(error_string),"Vertical sampling factor for Y should be greater than vertical sampling factor for Cb or Cr\n"); if ( (priv->component_infos[cCb].Hfactor!=1) || (priv->component_infos[cCr].Hfactor!=1) || (priv->component_infos[cCb].Vfactor!=1) || (priv->component_infos[cCr].Vfactor!=1)) snprintf(error_string, sizeof(error_string),"Sampling other than 1x1 for Cr and Cb is not supported"); #endif return 0; bogus_jpeg_format: #if TRACE fprintf(p_trace,"Bogus jpeg format\n"); fflush(p_trace); #endif return -1; } /******************************************************************************* * * Functions exported of the library. * * Note: Some applications can access directly to internal pointer of the * structure. It's is not recommended, but if you have many images to * uncompress with the same parameters, some functions can be called to speedup * the decoding. * ******************************************************************************/ /** * Allocate a new tinyjpeg decoder object. * * Before calling any other functions, an object need to be called. */ struct jdec_private *tinyjpeg_init(void) { struct jdec_private *priv; priv = (struct jdec_private *)calloc(1, sizeof(struct jdec_private)); if (priv == NULL) return NULL; return priv; } /** * Free a tinyjpeg object. * * No others function can be called after this one. */ void tinyjpeg_free(struct jdec_private *priv) { int i; for (i=0; i<COMPONENTS; i++) { if (priv->components[i]) free(priv->components[i]); priv->components[i] = NULL; } free(priv); } /** * Initialize the tinyjpeg object and prepare the decoding of the stream. * * Check if the jpeg can be decoded with this jpeg decoder. * Fill some table used for preprocessing. */ int tinyjpeg_parse_header(struct jdec_private *priv, const unsigned char *buf, unsigned int size) { int ret; /* Identify the file */ if ((buf[0] != 0xFF) || (buf[1] != SOI)) snprintf(error_string, sizeof(error_string),"Not a JPG file ?\n"); priv->stream_begin = buf+2; priv->stream_length = size-2; priv->stream_end = priv->stream_begin + priv->stream_length; ret = parse_JFIF(priv, priv->stream_begin); return ret; } static const decode_MCU_fct decode_mcu_3comp_table[4] = { decode_MCU_1x1_3planes, decode_MCU_1x2_3planes, decode_MCU_2x1_3planes, decode_MCU_2x2_3planes, }; static const decode_MCU_fct decode_mcu_1comp_table[4] = { decode_MCU_1x1_1plane, decode_MCU_1x2_1plane, decode_MCU_2x1_1plane, decode_MCU_2x2_1plane, }; static const convert_colorspace_fct convert_colorspace_yuv420p[4] = { YCrCB_to_YUV420P_1x1, YCrCB_to_YUV420P_1x2, YCrCB_to_YUV420P_2x1, YCrCB_to_YUV420P_2x2, }; static const convert_colorspace_fct convert_colorspace_rgb24[4] = { YCrCB_to_RGB24_1x1, YCrCB_to_RGB24_1x2, YCrCB_to_RGB24_2x1, YCrCB_to_RGB24_2x2, }; static const convert_colorspace_fct convert_colorspace_bgr24[4] = { YCrCB_to_BGR24_1x1, YCrCB_to_BGR24_1x2, YCrCB_to_BGR24_2x1, YCrCB_to_BGR24_2x2, }; static const convert_colorspace_fct convert_colorspace_grey[4] = { YCrCB_to_Grey_1x1, YCrCB_to_Grey_1x2, YCrCB_to_Grey_2x1, YCrCB_to_Grey_2x2, }; /** * Decode and convert the jpeg image into @pixfmt@ image * * Note: components will be automaticaly allocated if no memory is attached. */ int tinyjpeg_decode(struct jdec_private *priv, int pixfmt) { unsigned int x, y, xstride_by_mcu, ystride_by_mcu; unsigned int bytes_per_blocklines[3], bytes_per_mcu[3]; decode_MCU_fct decode_MCU; const decode_MCU_fct *decode_mcu_table; const convert_colorspace_fct *colorspace_array_conv; convert_colorspace_fct convert_to_pixfmt; if (setjmp(priv->jump_state)) return -1; /* To keep gcc happy initialize some array */ bytes_per_mcu[1] = 0; bytes_per_mcu[2] = 0; bytes_per_blocklines[1] = 0; bytes_per_blocklines[2] = 0; decode_mcu_table = decode_mcu_3comp_table; switch (pixfmt) { case TINYJPEG_FMT_YUV420P: colorspace_array_conv = convert_colorspace_yuv420p; if (priv->components[0] == NULL) priv->components[0] = (uint8_t *)malloc(priv->width * priv->height); if (priv->components[1] == NULL) priv->components[1] = (uint8_t *)malloc(priv->width * priv->height/4); if (priv->components[2] == NULL) priv->components[2] = (uint8_t *)malloc(priv->width * priv->height/4); bytes_per_blocklines[0] = priv->width; bytes_per_blocklines[1] = priv->width/4; bytes_per_blocklines[2] = priv->width/4; bytes_per_mcu[0] = 8; bytes_per_mcu[1] = 4; bytes_per_mcu[2] = 4; break; case TINYJPEG_FMT_RGB24: colorspace_array_conv = convert_colorspace_rgb24; if (priv->components[0] == NULL) priv->components[0] = (uint8_t *)malloc(priv->width * priv->height * 3); bytes_per_blocklines[0] = priv->width * 3; bytes_per_mcu[0] = 3*8; break; case TINYJPEG_FMT_BGR24: colorspace_array_conv = convert_colorspace_bgr24; if (priv->components[0] == NULL) priv->components[0] = (uint8_t *)malloc(priv->width * priv->height * 3); bytes_per_blocklines[0] = priv->width * 3; bytes_per_mcu[0] = 3*8; break; case TINYJPEG_FMT_GREY: decode_mcu_table = decode_mcu_1comp_table; colorspace_array_conv = convert_colorspace_grey; if (priv->components[0] == NULL) priv->components[0] = (uint8_t *)malloc(priv->width * priv->height); bytes_per_blocklines[0] = priv->width; bytes_per_mcu[0] = 8; break; default: #if TRACE fprintf(p_trace,"Bad pixel format\n"); fflush(p_trace); #endif return -1; } xstride_by_mcu = ystride_by_mcu = 8; if ((priv->component_infos[cY].Hfactor | priv->component_infos[cY].Vfactor) == 1) { decode_MCU = decode_mcu_table[0]; convert_to_pixfmt = colorspace_array_conv[0]; #if TRACE fprintf(p_trace,"Use decode 1x1 sampling\n"); fflush(p_trace); #endif } else if (priv->component_infos[cY].Hfactor == 1) { decode_MCU = decode_mcu_table[1]; convert_to_pixfmt = colorspace_array_conv[1]; ystride_by_mcu = 16; #if TRACE fprintf(p_trace,"Use decode 1x2 sampling (not supported)\n"); fflush(p_trace); #endif } else if (priv->component_infos[cY].Vfactor == 2) { decode_MCU = decode_mcu_table[3]; convert_to_pixfmt = colorspace_array_conv[3]; xstride_by_mcu = 16; ystride_by_mcu = 16; #if TRACE fprintf(p_trace,"Use decode 2x2 sampling\n"); fflush(p_trace); #endif } else { decode_MCU = decode_mcu_table[2]; convert_to_pixfmt = colorspace_array_conv[2]; xstride_by_mcu = 16; #if TRACE fprintf(p_trace,"Use decode 2x1 sampling\n"); fflush(p_trace); #endif } resync(priv); /* Don't forget to that block can be either 8 or 16 lines */ bytes_per_blocklines[0] *= ystride_by_mcu; bytes_per_blocklines[1] *= ystride_by_mcu; bytes_per_blocklines[2] *= ystride_by_mcu; bytes_per_mcu[0] *= xstride_by_mcu/8; bytes_per_mcu[1] *= xstride_by_mcu/8; bytes_per_mcu[2] *= xstride_by_mcu/8; /* Just the decode the image by macroblock (size is 8x8, 8x16, or 16x16) */ for (y=0; y < priv->height/ystride_by_mcu; y++) { //trace("Decoding row %d\n", y); priv->plane[0] = priv->components[0] + (y * bytes_per_blocklines[0]); priv->plane[1] = priv->components[1] + (y * bytes_per_blocklines[1]); priv->plane[2] = priv->components[2] + (y * bytes_per_blocklines[2]); for (x=0; x < priv->width; x+=xstride_by_mcu) { decode_MCU(priv); convert_to_pixfmt(priv); priv->plane[0] += bytes_per_mcu[0]; priv->plane[1] += bytes_per_mcu[1]; priv->plane[2] += bytes_per_mcu[2]; if (priv->restarts_to_go>0) { priv->restarts_to_go--; if (priv->restarts_to_go == 0) { priv->stream -= (priv->nbits_in_reservoir/8); resync(priv); if (find_next_rst_marker(priv) < 0) return -1; } } } } #if TRACE fprintf(p_trace,"Input file size: %d\n", priv->stream_length+2); fprintf(p_trace,"Input bytes actually read: %d\n", priv->stream - priv->stream_begin + 2); fflush(p_trace); #endif xstride_by_mcu = ystride_by_mcu = 8;//Initialize to the case where the width and height of MCU are 8, i.e. 444 if ((priv->component_infos[cY].Hfactor | priv->component_infos[cY].Vfactor) == 1) {//If both the vertical and horizontal sampling factors of the y component are 1 decode_MCU = decode_mcu_table[0];//Then each MCU includes a Y component convert_to_pixfmt = colorspace_array_conv[0]; #if TRACE fprintf(p_trace, "Use decode 1x1 sampling\n"); fflush(p_trace); #endif } else if (priv->component_infos[cY].Hfactor == 1) {//If the horizontal sampling factor of y component is 1 and the vertical is not equal to him, it is 2 decode_MCU = decode_mcu_table[1];//Each MCU includes 2 Y components convert_to_pixfmt = colorspace_array_conv[1]; ystride_by_mcu = 16;//MCU size 8 * 16 #if TRACE fprintf(p_trace, "Use decode 1x2 sampling (not supported)\n"); fflush(p_trace); #endif } else if (priv->component_infos[cY].Vfactor == 2) {//If horizontal is 2, vertical is 2 decode_MCU = decode_mcu_table[3];//Each MCU includes 4 Y components convert_to_pixfmt = colorspace_array_conv[3]; xstride_by_mcu = 16; ystride_by_mcu = 16;//MCU size 16 * 16 #if TRACE fprintf(p_trace, "Use decode 2x2 sampling\n"); fflush(p_trace); #endif } else {//If horizontal is 2, vertical is 1 decode_MCU = decode_mcu_table[2];//Each MCU includes 2 Y components convert_to_pixfmt = colorspace_array_conv[2]; xstride_by_mcu = 16;//MCU size 16 * 8 #if TRACE fprintf(p_trace, "Use decode 2x1 sampling\n"); fflush(p_trace); #endif } return 0; } const char *tinyjpeg_get_errorstring(struct jdec_private *priv) { /* FIXME: the snprintf string must be store in the context */ priv = priv; return error_string; } void tinyjpeg_get_size(struct jdec_private *priv, unsigned int *width, unsigned int *height) { *width = priv->width; *height = priv->height; } int tinyjpeg_get_components(struct jdec_private *priv, unsigned char **components) { int i; for (i=0; priv->components[i] && i<COMPONENTS; i++) components[i] = priv->components[i]; return 0; } int tinyjpeg_set_components(struct jdec_private *priv, unsigned char **components, unsigned int ncomponents) { unsigned int i; if (ncomponents > COMPONENTS) ncomponents = COMPONENTS; for (i=0; i<ncomponents; i++) priv->components[i] = components[i]; return 0; } int tinyjpeg_set_flags(struct jdec_private *priv, int flags) { int oldflags = priv->flags; priv->flags = flags; return oldflags; }
8,tinyjpeg-internal.h header file declaration
/* * Small jpeg decoder library (Internal header) * * Copyright (c) 2006, Luc Saillard <luc@saillard.org> * All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * - Neither the name of the author nor the names of its contributors may be * used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #ifndef __TINYJPEG_INTERNAL_H_ #define __TINYJPEG_INTERNAL_H_ #include <setjmp.h> #define SANITY_CHECK 1 struct jdec_private; #define HUFFMAN_BITS_SIZE 256 #define HUFFMAN_HASH_NBITS 9 #define HUFFMAN_HASH_SIZE (1UL<<HUFFMAN_HASH_NBITS) #define HUFFMAN_HASH_MASK (HUFFMAN_HASH_SIZE-1) #define HUFFMAN_TABLES 4 #define COMPONENTS 3 #define JPEG_MAX_WIDTH 2048 #define JPEG_MAX_HEIGHT 2048 struct huffman_table { /* Fast look up table, using HUFFMAN_HASH_NBITS bits we can have directly the symbol, * if the symbol is <0, then we need to look into the tree table */ short int lookup[HUFFMAN_HASH_SIZE]; /* code size: give the number of bits of a symbol is encoded */ unsigned char code_size[HUFFMAN_HASH_SIZE]; /* some place to store value that is not encoded in the lookup table * FIXME: Calculate if 256 value is enough to store all values */ uint16_t slowtable[16-HUFFMAN_HASH_NBITS][256]; }; struct component { unsigned int Hfactor; unsigned int Vfactor; float *Q_table; /* Pointer to the quantisation table to use */ struct huffman_table *AC_table; struct huffman_table *DC_table; short int previous_DC; /* Previous DC coefficient */ short int DCT[64]; /* DCT coef */ #if SANITY_CHECK unsigned int cid; #endif }; typedef void (*decode_MCU_fct) (struct jdec_private *priv); typedef void (*convert_colorspace_fct) (struct jdec_private *priv); struct jdec_private { /* Public variables */ uint8_t *components[COMPONENTS]; unsigned int width, height; /* Size of the image */ unsigned int flags; /* Private variables */ const unsigned char *stream_begin, *stream_end; unsigned int stream_length; const unsigned char *stream; /* Pointer to the current stream */ unsigned int reservoir, nbits_in_reservoir; struct component component_infos[COMPONENTS]; float Q_tables[COMPONENTS][64]; /* quantization tables */ struct huffman_table HTDC[HUFFMAN_TABLES]; /* DC huffman tables */ struct huffman_table HTAC[HUFFMAN_TABLES]; /* AC huffman tables */ int default_huffman_table_initialized; int restart_interval; int restarts_to_go; /* MCUs left in this restart interval */ int last_rst_marker_seen; /* Rst marker is incremented each time */ /* Temp space used after the IDCT to store each components */ uint8_t Y[64*4], Cr[64], Cb[64]; jmp_buf jump_state; /* Internal Pointer use for colorspace conversion, do not modify it !!! */ uint8_t *plane[COMPONENTS]; }; #if defined(__GNUC__) && (__GNUC__ > 3) && defined(__OPTIMIZE__) #define __likely(x) __builtin_expect(!!(x), 1) #define __unlikely(x) __builtin_expect(!!(x), 0) #else #define __likely(x) (x) #define __unlikely(x) (x) #endif #define IDCT tinyjpeg_idct_float void tinyjpeg_idct_float (struct component *compptr, uint8_t *output_buf, int stride); #endif
3, Experimental results
Task 1
Save the output file of the decoded JPEG file as a YUV file that can be viewed by YUVViewer
- test.yuv
Task 2
Output all quantization matrices and all HUFFMAN code tables in txt file