当前位置:网站首页>Experiment 5 JPEG
Experiment 5 JPEG
2022-07-23 07:58:00 【Myster_ KID】
JPEG Coding and decoding principle and code implementation
List of articles
JPEG(Joint Photographic Experts Group) Is the abbreviation of the joint imaging expert group . The organization started from 1986 In, it officially began to formulate the compression and coding standard of still digital images , This standard applies to 1992 Officially adopted in , be called JPEG standard .JPEG It is the first international standard for digital image compression , It is not only suitable for still image compression , Yes Intra frame compression of TV image sequences is also often used JPEG Algorithm , therefore JPEG It is a general standard with a wide range of applications .
One 、JPEG The principle of encoding and decoding
The basic block diagram of encoding and decoding is :
Coding principle
JPEG The standard itself does not specify a specific color space , Just encode the components of each color separately . In order to reduce the correlation between components , Reduce data redundancy , Usually RGB Convert color space to YUV To encode each component .
[ Y U V ] = [ 0.257 0.504 0.098 − 0.148 − 0.291 0.439 0.439 − 0.368 − 0.071 ] × [ R G B ] + [ 16 128 128 ] \begin{bmatrix} Y \\ U \\ V \end{bmatrix}= \begin{bmatrix} 0.257 & 0.504 & 0.098 \\ -0.148 & -0.291 & 0.439 \\ 0.439 & -0.368 & -0.071 \end{bmatrix} \times \begin{bmatrix} R \\ G \\ B \end{bmatrix} + \begin{bmatrix} 16 \\ 128 \\ 128 \end{bmatrix} ⎣⎡YUV⎦⎤=⎣⎡0.257−0.1480.4390.504−0.291−0.3680.0980.439−0.071⎦⎤×⎣⎡RGB⎦⎤+⎣⎡16128128⎦⎤
[ R G B ] = [ 1.164 − 0.002 1.596 1.164 − 0.391 − 0.813 1.164 2.018 − 0.001 ] × [ Y − 16 U − 128 V − 128 ] \begin{bmatrix} R \\ G \\ B \end{bmatrix}= \begin{bmatrix} 1.164 & -0.002 & 1.596 \\ 1.164 & -0.391 & -0.813 \\ 1.164 & 2.018 & -0.001 \end{bmatrix} \times \begin{bmatrix} Y-16 \\ U-128 \\ V-128 \end{bmatrix} ⎣⎡RGB⎦⎤=⎣⎡1.1641.1641.164−0.002−0.3912.0181.596−0.813−0.001⎦⎤×⎣⎡Y−16U−128V−128⎦⎤
1. Level offset The zero bias level moves down
The function of this step is , The average brightness of image content is high , take 0 The level moves to the middle , The average brightness decreases , Easy DCT After transformation and quantization, the DC coefficient is greatly reduced , This reduces the amount of data .
First pair 8×8 The zero bias level of the image block is shifted downward (Level Offset), That is, the gray level is 2 n 2^n 2n The pixel , By subtracting 2 n − 1 2^{n-1} 2n−1, Change an unsigned integer to a signed number , Change its value range to [ − 2 n − 1 , 2 n − 1 − 1 ] [-2^{n-1},2^{n-1}-1] [−2n−1,2n−1−1], The probability of occurrence of a number with a large absolute value is greatly reduced , Improve coding efficiency .
2. 8x8 DCT
This step is mainly used to remove the correlation between image data , It is convenient for the quantization process to remove the spatial redundancy of image data .DCT It is a lossless transformation , Also cannot compress the image , The purpose of this is to prepare for the next step of quantification .
Divide the image into 8×8 Image block of ; For width ( high ) No 8 An integer multiple of the image , Fill with image edge pixels , So as not to change the spectrum distribution . Then, for each sub block DCT(Discrete Cosine Transform, Discrete cosine transform ), To achieve energy concentration and decorrelation , Easy to remove spatial redundancy , Improve coding efficiency . What needs special emphasis is ,DCT It is a lossless transformation , Also cannot compress the image , The purpose of this is to prepare for the next step of quantification .
F ( u , v ) = C f ( x , y ) C T = C f ( x , y ) C − 1 F(u, v)=Cf(x,y)C^T=Cf(x,y)C^{-1} F(u,v)=Cf(x,y)CT=Cf(x,y)C−1
among , C C C yes 8 × 8 8\times8 8×8 Of DCT Transform two-dimensional kernel matrix , f ( x , y ) f ( x , y ) f(x,y) It's raw data .
because DCT Transformation is an orthogonal transformation , There are C T = C − 1 C^T=C^{-1} CT=C−1
3. Uniform scalar quantization Uniform nominal quantization
The quantizer is mainly a matrix quantization designed by using the characteristics of human vision DCT coefficient , Reduce visual redundancy . take DCT Temporary results after transformation , Divide by the respective quantization steps and round to the nearest , Get the quantization coefficient .JPEG The system specifies the quantization tables of luminance component and chrominance component respectively , The quantization step of chrominance component is larger than that of luminance component . In the quantification step ,JPEG Medium flat type (Midtread) Uniform quantizer .
actually JPEG Compression coding algorithm , There are not many parts that can be adjusted :DCT、 The two main steps of entropy coding are completely determined , In fact, only quantification can be adjusted , Quantification is also natural JPEG The core of compression coding algorithm . Besides , Quantization is the only step in the coding process that will introduce error and compression .
JPEG The standard adopts medium flat uniform quantification , Because human eyes are much more sensitive to low-frequency components than high-frequency components , And the sensitivity to brightness is much higher than chromaticity , Therefore, the standard has designed 2 A quantitative table ( brightness 、 One color difference ), Quantize the low frequency , High frequency rough quantization , Brightness quantization , Color difference rough quantization , To reduce visual redundancy .
The quantization matrix is not fixed , It can be adjusted according to different quality requirements .
4. DC Coefficient differential coding
We noticed that ,8×8 Like a block passing DCT Later obtained DC The coefficient has two characteristics : First, the value of the coefficient is large ; Second, adjacent image blocks DC The coefficient difference is not big ( There is redundancy ). According to this feature ,JPEG The standard adopts DPCM( Differential pulse code modulation ), To quantify between adjacent image blocks DC Coefficient Difference value DIFF Encoding .
D I F F k = D C k − D C k − 1 DIFF_k=DC_k-DC_{k-1} DIFFk=DCk−DCk−1
Yes DPCM Calculated later DIFF The difference is used Huffman code , Divide them into categories , Similar to index Golomb code ( It's just Golomb It's a dollar code + Fixed length code ), That's the category ID Use standard Huffman coding , In class index uses fixed length code ( Nature code ).
5. AC coefficient Zig-Zag Scanning and run length coding
because DCT after , Most of the coefficients are concentrated in the upper left corner , That is, the low-frequency component area , So we use Zig-Zag( Zigzag ) scanning , Read out the coefficients in the order of high and low frequencies , In this way, there can be many opportunities to connect zero , To facilitate RLE(Run Length Encoding, Run length encoding ), Especially in the end , If it's all zero , give EOB (End of Block) that will do .

for example 0, -2, -1, -1, -1, 0, 0, -1, EOB Expressed as :(1, -2), (0, -1), (0, -1), (0, -1), (2, -1), EOB.
6. Huffman code
Yes DC coefficient DPCM The result and AC coefficient RLE The result of Huffman code , Category ID Adopt unary code , The intra class index is encoded by fixed length code . With DC Coefficient as an example :
For example, the difference DIFF = 3 , Corresponding category ID = 2, Intra class index = 3, Then the codeword is 100 11.
Common brightness DC、 brightness AC、 chromatic aberration DC、 chromatic aberration AC Four Huffman Encoding table .
Decoding principle
Decoding is the reverse process of encoding , Decoding system block diagram :
Two 、JPEG File format analysis
JPEG Document to segment Organization in the form of , Each of them segment With a marker Start , And each marker in 0xFF And a marker Start with the identifier of , This was followed by 2 Bytes of marker length ( It doesn't contain marker The first two bytes of ) And corresponding payload(SOI and EOI marker Only 2 Byte identifier ).
Be careful , Successive 0xFF Bytes are not marker The starting sign of , It's a special character for filling .
Besides , In the part ,0xFF If later 0x00, Then skip this byte and do not process .
common marker as follows :
| Short name | Bytes | Payload | Name | Comments |
|---|---|---|---|---|
| SOI | 0xFF, 0xD8 | none | Start Of Image | |
| SOF0 | 0xFF, 0xC0 | variable size | Start Of Frame (baseline DCT) | Indicates that this is a baseline DCT-based JPEG, and specifies the width, height, number of components, and component subsampling (e.g., 4:2:0). |
| SOF2 | 0xFF, 0xC2 | variable size | Start Of Frame (progressive DCT) | Indicates that this is a progressive DCT-based JPEG, and specifies the width, height, number of components, and component subsampling (e.g., 4:2:0). |
| DHT | 0xFF, 0xC4 | variable size | Define Huffman Table(s) | Specifies one or more Huffman tables. |
| DQT | 0xFF, 0xDB | variable size | Define Quantization Table(s) | Specifies one or more quantization tables. |
| DRI | 0xFF, 0xDD | 4 bytes | Define Restart Interval | Specifies the interval between RSTn markers, in Minimum Coded Units (MCUs). This marker is followed by two bytes indicating the fixed size so it can be treated like any other variable size segment. |
| SOS | 0xFF, 0xDA | variable size | Start Of Scan | Begins a top-to-bottom scan of the image. In baseline DCT JPEG images, there is generally a single scan. Progressive DCT JPEG images usually contain multiple scans. This marker specifies which slice of data it will contain, and is immediately followed by entropy-coded data. |
| RSTn | 0xFF, 0xDn | none | Restart | Inserted every r rr macroblocks, where r rr is the restart interval set by a DRI marker. Not used if there was no DRI marker. The low three bits of the marker code cycle in value from 0 to 7. |
| APPn | 0xFF, 0xEn | variable size | Application-specific | For example, an Exif JPEG file uses an APP1 marker to store metadata, laid out in a structure based closely on TIFF. |
| COM | 0xFF, 0xFE | variable size | Comment | Contains a text comment. |
| EOI | 0xFF, 0xD9 | none | End Of Image |
Use Synalyze it! Pro App Perform binary analysis , And for some marker Make some brief descriptions of the fields .

Experimental picture test.jpg(1024x1024)
SOI And EOI

APP0

DQT

SOF0

DHT

SOS

SOS

3、 ... and 、 Code implementation
1. Hierarchical structure
JPEG A major feature of compression coding algorithm is the idea of hierarchical structure design , The following describes the design intent of the three main structures :
struct huffman_table: Storage Huffman clock .
/* tinyjpeg-internal.h */
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: Save current 8×8 Information about decoding in the image block .
/* tinyjpeg-internal.h */
struct component
{
unsigned int Hfactor; // Horizontal sampling factor
unsigned int Vfactor; // Vertical sampling factor
float* Q_table; // Point to 8×8 Quantization table used by the block
struct huffman_table *AC_table; // Point to the AC Huffman surface
struct huffman_table *DC_table; // Point to the DC Huffman surface
short int previous_DC; // DC of the previous block DCT coefficient
short int DCT[64]; // DCT Coefficient array
#if SANITY_CHECK
unsigned int cid;
#endif
};
struct jdec_private:JPEG Data flow structure , Used to store JPEG Image width and height 、 Data stream pointer 、Huffman Code table and other contents , And includes struct huffman_table and struct component.
/* tinyjpeg-internal.h */
struct jdec_private
{
/* Public variables */
uint8_t *components[COMPONENTS]; /* Point to respectively YUV Three pointers of three components */
unsigned int width, height; /* Image width and height */
unsigned int flags;
/* Private variables */
const unsigned char *stream_begin, *stream_end;
unsigned int stream_length;
const unsigned char *stream; /* Pointer to the current data 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];
};
2. Decoding process
/* Read JPEG file , decode , And store the results */
int convert_one_image(const char *infilename, const char *outfilename, int output_format)
{
FILE *fp;
unsigned int length_of_file; // file size
unsigned int width, height; // Image width 、 high
unsigned char *buf; // buffer
struct jdec_private *jdec;
unsigned char *components[3];
/* take JPEG Read in buffer */
fp = fopen(infilename, "rb");
if (fp == NULL)
exitmessage("Cannot open filename\n");
length_of_file = filesize(fp);
buf = (unsigned char *)malloc(length_of_file + 4);
if (buf == NULL)
exitmessage("Not enough memory for loading file\n");
fread(buf, length_of_file, 1, fp);
fclose(fp);
/* Decompress it */
jdec = tinyjpeg_init(); // initialization
if (jdec == NULL)
exitmessage("Not enough memory to alloc the structure need for decompressing\n");
/* analysis JPEG The file header */
if (tinyjpeg_parse_header(jdec, buf, length_of_file)<0)
exitmessage(tinyjpeg_get_errorstring(jdec));
/* Calculate the width and height of the image */
tinyjpeg_get_size(jdec, &width, &height);
snprintf(error_string, sizeof(error_string),"Decoding JPEG image...\n");
if (tinyjpeg_decode(jdec, output_format) < 0) // Decode the actual data
exitmessage(tinyjpeg_get_errorstring(jdec));
/* * Get address for each plane (not only max 3 planes is supported), and * depending of the output mode, only some components will be filled * RGB: 1 plane, YUV420P: 3 planes, GREY: 1 plane */
tinyjpeg_get_components(jdec, components);
/* Save the output file in the specified output format */
switch (output_format)
{
case TINYJPEG_FMT_RGB24:
case TINYJPEG_FMT_BGR24:
write_tga(outfilename, output_format, width, height, components);
break;
case TINYJPEG_FMT_YUV420P:
write_yuv(outfilename, width, height, components);
break;
case TINYJPEG_FMT_GREY:
write_pgm(outfilename, width, height, components);
break;
}
/* Only called this if the buffers were allocated by tinyjpeg_decode() */
tinyjpeg_free(jdec);
/* else called just free(jdec); */
free(buf);
return 0;
}
3. Core module
analysis JPEG The file header
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)) // JPEG The document must be marked with SOI marker As the starting point , Otherwise it is not legal JPEG file
snprintf(error_string, sizeof(error_string),"Not a JPG file ?\n");
priv->stream_begin = buf+2; // Skip identifier
priv->stream_length = size-2;
priv->stream_end = priv->stream_begin + priv->stream_length;
ret = parse_JFIF(priv, priv->stream_begin); // Start parsing JPEG
return ret;
}
analysis marker identifier
/* Omit trace part */
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 == 0)
{
if (*stream++ != 0xff)
goto bogus_jpeg_format;
/* Skip any padding ff byte (this is normal) */
while (*stream == 0xff)
stream++;
marker = *stream++; // obtain 0xFF The last byte ( That is to say marker identifier )
chuck_len = be16_to_cpu(stream); // length Field
next_chunck = stream + chuck_len;
switch (marker) // Judge marker type
{
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:
break;
}
stream = next_chunck; // Analyze the next marker
}
if (!dht_marker_found) {
build_default_huffman_tables(priv);
}
return 0;
bogus_jpeg_format:
return -1;
}
analysis DQT
static int parse_DQT(struct jdec_private *priv, const unsigned char *stream)
{
int qi; // Quantification table ID
float *table; // Point to the quantification table
const unsigned char *dqt_block_end; // Point to the end of the quantification table
dqt_block_end = stream + be16_to_cpu(stream);
stream += 2; // Skip the length field
while (stream < dqt_block_end) // Check whether there is a quantification table
{
qi = *stream++; // Assign the coefficients in the quantification table to qi
table = priv->Q_tables[qi];
build_quantization_table(table, stream);
stream += 64;
}
return 0;
}
Establish a quantitative table
static void build_quantization_table(float *qtable, const unsigned char *ref_table)
{
int i, j;
static const double aanscalefactor[8] = {
1.0, 1.387039845, 1.306562965, 1.175875602,
1.0, 0.785694958, 0.541196100, 0.275899379
}; // The scaling factor
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];
}
}
}
analysis DHT
static int parse_DHT(struct jdec_private *priv, const unsigned char *stream)
{
unsigned int count, i;
unsigned char huff_bits[17]; // Code length 1~16
int length, index;
length = be16_to_cpu(stream) - 2;
stream += 2; // Skip the length field
while (length>0) {
// Check if there are any tables
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 (index & 0xf0 )
build_huffman_table(huff_bits, stream, &priv->HTAC[index&0xf]); // Establish a communication table
else
build_huffman_table(huff_bits, stream, &priv->HTDC[index&0xf]); // Establish DC meter
length -= 1;
length -= 16;
length -= count;
stream += count;
}
return 0;
}
establish Huffman clock
static void build_huffman_table(const unsigned char *bits, const unsigned char *vals, struct huffman_table *table) // bits Is the number of digital words in each digit ,val by Huffval,table For the... To be established Huffman surface
{
unsigned int i, j, code, code_size, val, nbits;
unsigned char huffsize[HUFFMAN_BITS_SIZE + 1]; // The length of each codeword
unsigned char* hz;
unsigned int huffcode[HUFFMAN_BITS_SIZE + 1]; // Every codeword
unsigned char* hc;
int next_free_entry;
/* initialization */
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;
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] != 0; i++)
{
/* obtain Huffval、 Every codeword 、 The length of each codeword */
val = vals[i];
code = huffcode[i];
code_size = huffsize[i];
table->code_size[val] = code_size; // Huffval( A weight )
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; // obtain Huffval Length lookup table
}
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 */
}
}
}
analysis SOS
static int parse_SOS(struct jdec_private *priv, const unsigned char *stream)
{
unsigned int i, cid, table;
unsigned int nr_components = stream[2]; // Number of color components
stream += 3;
for (i=0;i<nr_components;i++) {
/* Get used Huffmann Table number */
cid = *stream++;
table = *stream++;
priv->component_infos[i].AC_table = &priv->HTAC[table&0xf];
priv->component_infos[i].DC_table = &priv->HTDC[table>>4];
}
priv->stream = stream+3;
return 0;
}
analysis SOF
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;
print_SOF(stream);
height = be16_to_cpu(stream+3); // Height of the image
width = be16_to_cpu(stream+5); // The width of the image
nr_components = stream[7]; // Number of color components
stream += 8;
for (i=0; i<nr_components; i++) {
/* Analyze each component separately */
cid = *stream++; // component ID
sampling_factor = *stream++; // Sampling factor
Q_table = *stream++;
c = &priv->component_infos[i];
c->Vfactor = sampling_factor&0xf; // Vertical sampling factor
c->Hfactor = sampling_factor>>4; // Horizontal sampling factor
c->Q_table = priv->Q_tables[Q_table]; // Quantification table used
}
priv->width = width;
priv->height = height;
return 0;
}
analysis JPEG Actual data
int tinyjpeg_decode(struct jdec_private *priv, int pixfmt) // pixfmt For output format
{
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) {
/* According to different output formats MCU */
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:
return -1;
}
xstride_by_mcu = ystride_by_mcu = 8; // initialization :MCU The width and height of are 8px(4:4:4)
if ((priv->component_infos[cY].Hfactor | priv->component_infos[cY].Vfactor) == 1) {
/* level 、 The vertical sampling factors are 1 */
decode_MCU = decode_mcu_table[0]; // MCU contain 1 individual Y
convert_to_pixfmt = colorspace_array_conv[0];
} else if (priv->component_infos[cY].Hfactor == 1) {
/* The horizontal sampling factor is 1, The vertical sampling factor is 2 */
decode_MCU = decode_mcu_table[1]; // MCU contain 2 individual Y
convert_to_pixfmt = colorspace_array_conv[1];
ystride_by_mcu = 16; // MCU high 16px, wide 8px
} else if (priv->component_infos[cY].Vfactor == 2) {
/* level 、 The vertical sampling factors are 2 */
decode_MCU = decode_mcu_table[3]; // MCU contain 4 individual Y
convert_to_pixfmt = colorspace_array_conv[3];
xstride_by_mcu = 16; // MCU wide 16px
ystride_by_mcu = 16; // MCU high 16px
} else {
/* The horizontal sampling factor is 2, The vertical sampling factor is 1 */
decode_MCU = decode_mcu_table[2]; // MCU contain 2 individual Y
convert_to_pixfmt = colorspace_array_conv[2];
xstride_by_mcu = 16; // MCU wide 16px, high 8px
}
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;
/* Decode each image block (8x8 / 8x16 / 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;
}
}
}
}
return 0;
}
analysis MCU
/* * 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);
}
Output the file as .yuv Format
static void write_yuv(const char* filename, int width, int height, unsigned char** components) {
FILE* F;
char temp[1024];
snprintf(temp, 1024, "%s.Y", filename);
F = fopen(temp, "wb");
fwrite(components[0], width, height, F);
fclose(F);
snprintf(temp, 1024, "%s.U", filename);
F = fopen(temp, "wb");
fwrite(components[1], width * height / 4, 1, F);
fclose(F);
snprintf(temp, 1024, "%s.V", filename);
F = fopen(temp, "wb");
fwrite(components[2], width * height / 4, 1, F);
fclose(F);
snprintf(temp, 1024, "%s.YUV", filename);
F = fopen(temp, "wb");
fwrite(components[0], width, height, F);
fwrite(components[1], width * height / 4, 1, F);
fwrite(components[2], width * height / 4, 1, F);
fclose(F);
}
Output yuv The documents are as follows :
Output quantization matrix and Huffman clock
/* tinyjpeg.h Add */
/* Declare global variables by S.Z.Zheng */
FILE* qtabFilePtr; // Quantization table file pointer
/* End of statement */
/* tinyjpeg.c Add */
static void build_quantization_table(float *qtable, const unsigned char *ref_table)
{
...
for (i=0; i<8; i++) {
for (j=0; j<8; j++) {
/* Added by S.Z.Zheng */
fprintf(qtabFilePtr, "%-6d", ref_table[*zz]);
if (j == 7) {
fprintf(qtabFilePtr, "\n");
}
/* Addition ended */
...
}
}
fprintf(qtabFilePtr, "\n\n"); // Added by S.Z.Zheng
}
static int parse_DQT(struct jdec_private *priv, const unsigned char *stream)
{
...
while (stream < dqt_block_end) // Check whether there is a quantification table
{
...
fprintf(qtabFilePtr, "Quantisation table [%d]:\n", qi); // Quantification table ID(added by S.Z.Zheng)
build_quantization_table(table, stream);
...
}
...
}
/* loadjpeg.c Add */
int main(int argc, char *argv[])
{
...
/* Added by S.Z.Zheng */
const char* qtabFileName = "q_table.txt"; // Quantization table file name
fopen_s(&qtabFilePtr, qtabFileName, "wb"); // Open file
/* Addition ended */
...
fclose(qtabFilePtr); // Added by S.Z.Zheng
return 0;
}

Output DC、AC Images
/* tinyjpeg.h Add */
/* Declare global variables by S.Z.Zheng */
...
FILE* dcImgFilePtr; // DC Image file pointer
FILE* acImgFilePtr; // AC Image file pointer
/* End of statement */
/* tinyjpeg.c Add */
int tinyjpeg_decode(struct jdec_private* priv, int pixfmt)
{
...
/* Added by S.Z.Zheng */
unsigned char* dcImgBuff;
unsigned char* acImgBuff;
unsigned char* uvBuff = 128;
int count = 0;
/* Addition ended*/
/* Decode each image block (8x8 / 8x16 / 16x16) */
for (y = 0; y < priv->height / ystride_by_mcu; y++) {
...
for (x = 0; x < priv->width; x += xstride_by_mcu) {
decode_MCU(priv);
dcImgBuff = (unsigned char)((priv->component_infos->DCT[0] + 512.0) / 4 + 0.5); // DCT[0] by DC coefficient ;DC Coefficient range -512~512; Change to 0~255
acImgBuff = (unsigned char)(priv->component_infos->DCT[1] + 128); // selection DCT[1] As AC Of observation;+128 Convenient for observation
fwrite(&dcImgBuff, 1, 1, dcImgFilePtr);
fwrite(&acImgBuff, 1, 1, acImgFilePtr);
count++;
...
}
}
}
}
...
/* Added by S.Z.Zheng */
for (int i = 0; i < count / 4 * 2; i++) {
fwrite(&uvBuff, sizeof(unsigned char), 1, dcImgFilePtr);
fwrite(&uvBuff, sizeof(unsigned char), 1, acImgFilePtr);
}
/* Addition ended */
return 0;
}
/* loadjpeg.c Add */
int main(int argc, char *argv[]) {
...
/* Added by S.Z.Zheng */
...
const char* dcImgFileName = "test_decoded_dc.yuv"; // DC Image file name
const char* acImgFileName = "test_decoded_ac.yuv"; // AC Image file name
...
fopen_s(&dcImgFilePtr, dcImgFileName, "wb"); // open DC image file
fopen_s(&acImgFilePtr, acImgFileName, "wb"); // open AC image file
/* Addition ended */
...
/* Added by S.Z.Zheng */
...
fclose(dcImgFilePtr);
fclose(acImgFilePtr);
/* Addition Ended */
return 0;
}

边栏推荐
- pycharm中使用私钥远程连接服务器
- 自定义flink es source
- Scala when used Performance problems of contains().Exists()
- VMware virtual machine changes static IP and hostname, and uses xshell to connect
- Yolov5 post-processing code of cpu/gpu (CUDA) version
- File upload, server file name Chinese garbled file upload, server file name Chinese garbled
- 【干货原创】发现了一个好用到爆的数据分析利器
- LAN SDN technology hard core insider 6 distributed anycast gateway
- How to open the file in keil is the real path in the 109th blog of fledgling Xiao Li
- Bottom compulsory of large factory: "communication realization between application program and AMS"
猜你喜欢

开幕在即 | “万物互联,使能千行百业”2022开放原子全球开源峰会OpenAtom OpenHarmony分论坛

程序员最想干的三件事 |漫画

Kubernetes deployment strategy

VMware virtual machine changes static IP and hostname, and uses xshell to connect

Fledgling Xiao Li's 108th blog binary print

驱动页面性能优化的3个有效策略

毕业设计-----基于STM32的物联网环境检测系统

大厂底层必修:“应用程序与 AMS 的通讯实现”

6-15漏洞利用-smb-RCE远程命令执行

Mysql A left(right) join B on A.id=B.id and A.age=1与A left(right) join B on A.id=B.id where A.age=1
随机推荐
Amazon's zoox passed the safety test and applied for a test drive in California
[record of question brushing] 18. Sum of four numbers
yolov5 test. Py broken pipe error: [errno 32] broken pipe problem solving
(五)数电——公式化简法
Scala gets all files in the specified directory
Experiment III LZW
一文深入浅出理解国产开源木兰许可系列协议
Qt+VTK+PCL图片转灰度图且以灰度为Y轴显示
初出茅庐的小李第108篇博客二进制打印
6-15漏洞利用-smb-RCE远程命令执行
Understand the domestic open source Magnolia license series agreement in simple terms
实验二 YUV
yolov5 test.py BrokenPipeError: [Errno 32] Broken pipe问题解决
Worthington溶菌酶技术说明及文献参考
VMware 中搭建 SylixOS 环境
微信小程序项目实战
LAN SDN hard core technology insider 19 unite all forces that can be united
Scala Generic 泛型类详解 - T
成功解决:error: src refspec master does not match any
Why does MySQL index use b+ tree instead of jump table?