首页 > 其他分享 >JPEG编码协议--代码实现

JPEG编码协议--代码实现

时间:2023-05-23 11:57:19浏览次数:32  
标签:fp 编码 -- JPEG Standard write 99 int byte

    通过前面几篇的JPEG编码原理和文件格式解析,此篇通过简单的sample代码来具体介绍下JPG有损编码的简单实现,具体的说明见代码注释,改bmp2jpg.c实现了BMP图片到JPG图片的格式转换,

使用gcc ./bmp2jpg.c -std=c99 -lm编译,执行。

  1 #include <stdint.h>
  2 #include <stdlib.h>
  3 #include <stdio.h>
  4 #include <string.h>
  5 #include <math.h>
  6 
  7 const unsigned char Lum_Quantization_Tab[64]=
  8 {
  9     16, 11, 10, 16, 24, 40, 51, 61,
 10     12, 12, 14, 19, 26, 58, 60, 55,
 11     14, 13, 16, 24, 40, 57, 69, 56,
 12     14, 17, 22, 29, 51, 87, 80, 62,
 13     18, 22, 37, 56, 68,109,103, 77,
 14     24, 35, 55, 64, 81,104,113, 92,
 15     49, 64, 78, 87,103,121,120,101,
 16     72, 92, 95, 98,112,100,103, 99
 17 };
 18 
 19 const unsigned char Chroma_Quantization_Tab[64]=
 20 {
 21     17, 18, 24, 47, 99, 99, 99, 99,
 22     18, 21, 26, 66, 99, 99, 99, 99,
 23     24, 26, 56, 99, 99, 99, 99, 99,
 24     47, 66, 99, 99, 99, 99, 99, 99,
 25     99, 99, 99, 99, 99, 99, 99, 99,
 26     99, 99, 99, 99, 99, 99, 99, 99,
 27     99, 99, 99, 99, 99, 99, 99, 99,
 28     99, 99, 99, 99, 99, 99, 99, 99
 29 };
 30 
 31 const char ZigZag[64] =
 32 {
 33     0, 1, 5, 6, 14, 15, 27, 28,
 34     2, 4, 7,13, 16, 26, 29, 42,
 35     3, 8,12,17, 25, 30, 41, 43,
 36     9,11,18,24, 31, 40, 44, 53,
 37    10,19,23,32, 39, 45, 52, 54,
 38    20,22,33,38, 46, 51, 55, 60,
 39    21,34,37,47, 50, 56, 59, 61,
 40    35,36,48,49, 57, 58, 62, 63
 41 };
 42 
 43 const char Standard_DC_Lum_NRCodes[] = {0, 0, 7, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0};
 44 const char Standard_DC_Lum_Values[] = {4, 5, 3, 2, 6, 1, 0, 7, 8, 9, 10, 11};
 45 const char Standard_DC_Chroma_NRCodes[] = {0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0};
 46 const char Standard_DC_Chroma_Values[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
 47 const char Standard_AC_Lum_NRCodes[] = { 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d };
 48 const unsigned char Standard_AC_Lum_Values[] = 
 49 {
 50     0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
 51     0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
 52     0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
 53     0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
 54     0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
 55     0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
 56     0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
 57     0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
 58     0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
 59     0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
 60     0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
 61     0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
 62     0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
 63     0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
 64     0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
 65     0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
 66     0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
 67     0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
 68     0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
 69     0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
 70     0xf9, 0xfa
 71 };
 72 
 73 //-------------------------------------------------------------------------------
 74 const char Standard_AC_Chroma_NRCodes[] = { 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 };
 75 const unsigned char Standard_AC_Chroma_Values[] =
 76 {
 77     0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
 78     0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
 79     0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
 80     0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
 81     0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
 82     0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
 83     0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
 84     0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
 85     0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
 86     0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
 87     0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
 88     0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
 89     0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
 90     0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
 91     0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
 92     0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
 93     0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
 94     0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
 95     0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
 96     0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
 97     0xf9, 0xfa
 98 };
 99 
100 unsigned short picwidth, picheight;
101 unsigned char MB_YTab[64];
102 unsigned char MB_CbCrTab[64];
103 
104 typedef struct
105 {
106     int length;
107     int value;
108 }BitString;
109 BitString Y_DC_Huffman_Tab[12];
110 BitString Y_AC_Huffman_Tab[256];
111 BitString CbCr_DC_Huffman_Tab[12];
112 BitString CbCr_AC_Huffman_Tab[256];
113 
114 //bmp file structure
115 #pragma pack(push, 2)
116 typedef struct{
117     unsigned short bfType;  //"BM"
118     unsigned int   bfSize;  //文件大小
119     unsigned short bfReserved1;
120     unsigned short bfReserved2;
121     unsigned int   bfOffset; //图像数据开始偏移 
122 }BITMAPFILEHEADER;
123 
124 typedef struct{
125     unsigned int biSize;  //数据头大小
126     int biWidth;  //图片宽度
127     int biHeight; //图片高度
128     unsigned short biPlanes;   //色彩分量平面数
129     unsigned short biBitCount; //像素点所占bit数
130     unsigned int biCompression;//压缩方式
131     unsigned int biSizeImage;  //原始位图数据大小
132     int biXPelsPerMeter; //纵向分辨率
133     int biYPelsPerMeter; //横向分辨率
134     unsigned int biClrUsed;
135     unsigned int biClrImportant;
136 }BITMAPINFOHEADER;
137 #pragma pack(pop)
138 
139 int readbmp(char *path, char **ppRgb, int *pw, int *ph)
140 {
141     FILE *fp = fopen(path, "r");
142     long bmpsize;
143     char *prgb = NULL;
144     BITMAPFILEHEADER bmpFhead;
145     BITMAPINFOHEADER bmpIhead;
146     fread(&bmpFhead, 1, sizeof(bmpFhead), fp); //读取BMP图片头信息
147     if (bmpFhead.bfType != 0x4D42)
148         return -1;
149     fread(&bmpIhead, 1, sizeof(bmpIhead), fp); //读取BMP图片详细头信息
150     if (bmpIhead.biBitCount != 24 || bmpIhead.biCompression != 0)
151         return -1;
152     if ((bmpIhead.biWidth&7)!=0 || (bmpIhead.biHeight&7)!=0) //sample简化宏块处理,只支持宽高宏块对齐尺寸
153     {
154         printf("bmp %dx%d not support!\n", bmpIhead.biWidth, bmpIhead.biHeight);
155         return -1;
156     }
157     bmpsize = bmpIhead.biWidth * bmpIhead.biHeight * 3;
158     prgb = malloc(bmpsize);
159     for(int i=0; i < bmpIhead.biHeight; i++)
160     {//数据存储方式是从左到右,从下到上,小端序
161         if (bmpIhead.biWidth != fread(prgb + (bmpIhead.biHeight-1-i)*bmpIhead.biWidth*3, 3, bmpIhead.biWidth, fp))
162         {
163             free(prgb);
164             return -1;
165         }
166     }
167     
168     fclose(fp);
169     *ppRgb = prgb;
170     *pw    = bmpIhead.biWidth;
171     *ph    = bmpIhead.biHeight;
172     
173     return 0;
174 }
175 
176 int _init_QualityTables(int Qp)
177 {
178     Qp = (Qp >= 100)?99:(Qp<=0?1:Qp);
179     for (int i=0, tmp=0; i<64; i++)
180     {
181         tmp = ((int)Lum_Quantization_Tab[i] * Qp + 50) / 100;
182         tmp = (tmp > 0xFF)?0xFF:(tmp<=0?1:tmp);
183         MB_YTab[ZigZag[i]] = (unsigned char)tmp;   //按照ZigZag扫描的顺序存储Qp调整后的量化值
184         
185         tmp = ((int)Chroma_Quantization_Tab[i] * Qp + 50) / 100;
186         tmp = (tmp > 0xFF)?0xFF:(tmp<=0?1:tmp);
187         MB_CbCrTab[ZigZag[i]] = (unsigned char)tmp;//同上    
188     }
189 }
190 
191 void _computeHuffmanTable(const char* nr_codes, const unsigned char* std_table, BitString* huffman_table)
192 {
193     unsigned char pos_in_table = 0;
194     unsigned short code_value = 0;
195 
196     for(int k = 1; k <= 16; k++)
197     {
198         for(int j = 1; j <= nr_codes[k-1]; j++)
199         {
200             huffman_table[std_table[pos_in_table]].value = code_value;
201             huffman_table[std_table[pos_in_table]].length = k;
202             pos_in_table++;
203             code_value++;
204         }
205         code_value <<= 1;
206     }  
207 }
208 void _initHuffmanTables(void)
209 {
210     memset(&Y_DC_Huffman_Tab, 0, sizeof(Y_DC_Huffman_Tab));
211     _computeHuffmanTable(Standard_DC_Lum_NRCodes, Standard_DC_Lum_Values, Y_DC_Huffman_Tab);
212 
213     memset(&Y_AC_Huffman_Tab, 0, sizeof(Y_AC_Huffman_Tab));
214     _computeHuffmanTable(Standard_AC_Lum_NRCodes, Standard_AC_Lum_Values, Y_AC_Huffman_Tab);
215 
216     memset(&CbCr_DC_Huffman_Tab, 0, sizeof(CbCr_DC_Huffman_Tab));
217     _computeHuffmanTable(Standard_DC_Chroma_NRCodes, Standard_DC_Chroma_Values, CbCr_DC_Huffman_Tab);
218 
219     memset(&CbCr_AC_Huffman_Tab, 0, sizeof(CbCr_AC_Huffman_Tab));
220     _computeHuffmanTable(Standard_AC_Chroma_NRCodes, Standard_AC_Chroma_Values, CbCr_AC_Huffman_Tab);
221 }
222 
223 BitString _getBitCode(int value)
224 {
225     BitString ret;
226     int v = (value>0) ? value : -value;
227     
228     //bit 的长度
229     int length = 0;
230     for(length=0; v; v>>=1) length++;
231 
232     ret.value = value>0 ? value : ((1<<length)+value-1);
233     ret.length = length;
234 
235     return ret;
236 }
237 
238 void _write_(const void* p, int byteSize, FILE* fp)
239 {
240     fwrite(p, 1, byteSize, fp);
241 }
242 void _write_word_(unsigned short value, FILE *fp)
243 {
244     unsigned short _value = ((value>>8)&0xFF)|((value&0xFF)<<8); //value是小端模式,对字节顺序调整
245     fwrite(&_value, 1, 2, fp);
246     return;
247 }
248 
249 void _write_byte_(unsigned char value, FILE *fp)
250 {
251     fwrite(&value, 1, 1, fp);
252     return;
253 }
254 
255 void _write_bitstring_(const BitString* bs, int counts, int* pnewByte, int *pnewBytePos, FILE* fp)
256 {
257     unsigned short mask[] = {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768};
258     int newByte = *pnewByte;
259     int newBytePos = *pnewBytePos;
260     
261     for(int i=0; i<counts; i++)
262     {
263         int value = bs[i].value;
264         int posval = bs[i].length - 1;
265 
266         while (posval >= 0)
267         {
268             if ((value & mask[posval]) != 0)
269             {
270                 newByte = newByte  | mask[newBytePos];
271             }
272             posval--;
273             newBytePos--;
274             if (newBytePos < 0)
275             {
276                 // Write to stream
277                 _write_byte_((unsigned char)(newByte), fp);
278                 if (newByte == 0xFF)
279                 {
280                     // Handle special case
281                     _write_byte_((unsigned char)(0x00), fp);
282                 }
283 
284                 // Reinitialize
285                 newBytePos = 7;
286                 newByte = 0;
287             }
288         }
289     }
290     
291     *pnewByte = newByte;
292     *pnewBytePos = newBytePos;
293 }
294 void _write_jpeg_header(FILE* fp)
295 {
296     //SOI
297     _write_word_(0xFFD8, fp);        // marker = 0xFFD8
298 
299     //APPO
300     _write_word_(0xFFE0,fp);        // marker = 0xFFE0
301     _write_word_(16, fp);            // length = 16 for usual JPEG, no thumbnail
302     _write_("JFIF", 5, fp);            // 'JFIF\0'
303     _write_byte_(1, fp);            // version_hi
304     _write_byte_(1, fp);            // version_low
305     _write_byte_(0, fp);            // xyunits = 0 no units, normal density
306     _write_word_(1, fp);            // xdensity
307     _write_word_(1, fp);            // ydensity
308     _write_byte_(0, fp);            // thumbWidth
309     _write_byte_(0, fp);            // thumbHeight
310 
311     //DQT
312     _write_word_(0xFFDB, fp);        //marker = 0xFFDB
313     _write_word_(132, fp);            //size=132
314     _write_byte_(0, fp);            //QTYinfo== 0:  bit 0..3: number of QT = 0 (table for Y) 
315                                     //                bit 4..7: precision of QT
316                                     //                bit 8    : 0
317     _write_(MB_YTab, 64, fp);        //YTable
318     _write_byte_(1, fp);            //QTCbinfo = 1 (quantization table for Cb,Cr)
319     _write_(MB_CbCrTab, 64, fp);    //CbCrTable
320 
321     //SOFO
322     _write_word_(0xFFC0, fp);            //marker = 0xFFC0
323     _write_word_(17, fp);                //length = 17 for a truecolor YCbCr JPG
324     _write_byte_(8, fp);                //precision = 8: 8 bits/sample 
325     _write_word_(picheight&0xFFFF, fp);    //height
326     _write_word_(picwidth&0xFFFF, fp);    //width
327     _write_byte_(3, fp);                //nrofcomponents = 3: We encode a truecolor JPG
328 
329     _write_byte_(1, fp);                //IdY = 1
330     _write_byte_(0x11, fp);                //HVY sampling factors for Y (bit 0-3 vert., 4-7 hor.)(SubSamp 1x1)
331     _write_byte_(0, fp);                //QTY  Quantization Table number for Y = 0
332 
333     _write_byte_(2, fp);                //IdCb = 2
334     _write_byte_(0x11, fp);                //HVCb = 0x11(SubSamp 1x1)
335     _write_byte_(1, fp);                //QTCb = 1
336 
337     _write_byte_(3, fp);                //IdCr = 3
338     _write_byte_(0x11, fp);                //HVCr = 0x11 (SubSamp 1x1)
339     _write_byte_(1, fp);                //QTCr Normally equal to QTCb = 1
340     
341     //DHT
342     _write_word_(0xFFC4, fp);        //marker = 0xFFC4
343     _write_word_(0x01A2, fp);        //length = 0x01A2
344     _write_byte_(0, fp);            //HTYDCinfo bit 0..3    : number of HT (0..3), for Y =0
345                                     //            bit 4        : type of HT, 0 = DC table,1 = AC table
346                                     //            bit 5..7    : not used, must be 0
347     _write_(Standard_DC_Lum_NRCodes, sizeof(Standard_DC_Lum_NRCodes), fp);    //DC_L_NRC
348     _write_(Standard_DC_Lum_Values, sizeof(Standard_DC_Lum_Values), fp);        //DC_L_VALUE
349     _write_byte_(0x10, fp);            //HTYACinfo
350     _write_(Standard_AC_Lum_NRCodes, sizeof(Standard_AC_Lum_NRCodes), fp);
351     _write_(Standard_AC_Lum_Values, sizeof(Standard_AC_Lum_Values), fp); //we'll use the standard Huffman tables
352     _write_byte_(0x01, fp);            //HTCbDCinfo
353     _write_(Standard_DC_Chroma_NRCodes, sizeof(Standard_DC_Chroma_NRCodes), fp);
354     _write_(Standard_DC_Chroma_Values, sizeof(Standard_DC_Chroma_Values), fp);
355     _write_byte_(0x11, fp);            //HTCbACinfo
356     _write_(Standard_AC_Chroma_NRCodes, sizeof(Standard_AC_Chroma_NRCodes), fp);
357     _write_(Standard_AC_Chroma_Values, sizeof(Standard_AC_Chroma_Values), fp);
358 
359     //SOS
360     _write_word_(0xFFDA, fp);        //marker = 0xFFC4
361     _write_word_(12, fp);            //length = 12
362     _write_byte_(3, fp);            //nrofcomponents, Should be 3: truecolor JPG
363 
364     _write_byte_(1, fp);            //Idy=1
365     _write_byte_(0, fp);            //HTY    bits 0..3: AC table (0..3)
366                                     //        bits 4..7: DC table (0..3)
367     _write_byte_(2, fp);            //IdCb
368     _write_byte_(0x11, fp);            //HTCb
369 
370     _write_byte_(3, fp);            //IdCr
371     _write_byte_(0x11, fp);            //HTCr
372 
373     _write_byte_(0, fp);            //Ss not interesting, they should be 0,63,0
374     _write_byte_(0x3F, fp);            //Se
375     _write_byte_(0, fp);            //Bf
376 }
377 
378 void _convertMBColorRGB2YUV(char *pRgb, int xPos, int yPos, int patch, char* yData, char* cbData, char* crData)
379 {
380     for (int y=0; y<8; y++)
381     {
382         unsigned char* p = pRgb + (y+yPos)*patch*3 + xPos*3;
383         for (int x=0; x<8; x++)
384         {
385             unsigned char B = *p++;
386             unsigned char G = *p++;
387             unsigned char R = *p++;
388 
389             yData[y*8+x] = (char)(0.299f * R + 0.587f * G + 0.114f * B - 128); //公式根据JPEG FILE Interchange Format标准
390             cbData[y*8+x] = (char)(-0.1687f * R - 0.3313f * G + 0.5f * B );
391             crData[y*8+x] = (char)(0.5f * R - 0.4187f * G - 0.0813f * B);
392         }
393     }
394 }
395 
396 void _forword_FDC(const char* channel_data, short* fdc_data, unsigned char QTab[])
397 {
398     const float PI = 3.1415926f;
399     for(int v=0; v<8; v++)
400     {
401         for(int u=0; u<8; u++)
402         {
403             //使用二维DCT对8x8宏块进行变换,得到DC和AC系数
404             float alpha_u = (u==0) ? 1/sqrt(8.0f) : 0.5f;
405             float alpha_v = (v==0) ? 1/sqrt(8.0f) : 0.5f;
406 
407             float temp = 0.f;
408             for(int x=0; x<8; x++)
409             {
410                 for(int y=0; y<8; y++)
411                 {
412                     float data = channel_data[y*8+x];
413 
414                     data *= cos((2*x+1)*u*PI/16.0f);
415                     data *= cos((2*y+1)*v*PI/16.0f);
416 
417                     temp += data;
418                 }
419             }
420             
421             //使用ZigZag方式存储的量化表对变换系数量化
422             temp *= alpha_u*alpha_v/QTab[ZigZag[v*8+u]];
423             
424             //对量化后的值四舍五入处理,放入ZigZag排列的输出缓存区
425             fdc_data[ZigZag[v*8+u]] = (short) ((short)(temp + 16384.5) - 16384);
426         }
427     }
428 }
429 
430 void _doHuffmanEncoding(const short* DU, short *prevDC, const BitString* HTDC, const BitString* HTAC, 
431     BitString* outputBitString, int *bitStringCounts)
432 {
433     BitString EOB = HTAC[0x00];
434     BitString SIXTEEN_ZEROS = HTAC[0xF0];
435 
436     int index=0;
437 
438     // encode DC
439     int dcDiff = (int)(DU[0] - *prevDC);
440     *prevDC = DU[0];
441 
442     if (dcDiff == 0) 
443         outputBitString[index++] = HTDC[0];
444     else
445     {
446         BitString bs = _getBitCode(dcDiff);
447 
448         outputBitString[index++] = HTDC[bs.length];
449         outputBitString[index++] = bs;
450     }
451 
452     // encode ACs
453     int endPos=63; //end0pos = first element in reverse order != 0
454     while((endPos > 0) && (DU[endPos] == 0)) endPos--;
455 
456     for(int i=1; i<=endPos; )
457     {
458         int startPos = i;
459         while((DU[i] == 0) && (i <= endPos)) i++;
460 
461         int zeroCounts = i - startPos;
462         if (zeroCounts >= 16)
463         {
464             for (int j=1; j<=zeroCounts/16; j++)
465                 outputBitString[index++] = SIXTEEN_ZEROS;
466             zeroCounts = zeroCounts%16;
467         }
468 
469         BitString bs = _getBitCode(DU[i]);
470 
471         outputBitString[index++] = HTAC[(zeroCounts << 4) | bs.length];
472         outputBitString[index++] = bs;
473         i++;
474     }
475 
476     if (endPos != 63)
477         outputBitString[index++] = EOB;
478 
479     *bitStringCounts = index;
480 }
481 
482 int encode_rgb2jpg(char *pRgb, int width, int height, int Qp, char *pJpgFile)
483 {
484     FILE *fp = fopen(pJpgFile, "w");
485     short prev_DC_Y = 0, prev_DC_Cb = 0, prev_DC_Cr = 0;
486     int newByte = 0, newBytePos = 7;
487     BitString MbBitString[128];
488     int bitStringCnt;
489     char yData[64], cbData[64], crData[64];
490     short yQuant[64], cbQuant[64], crQuant[64];    
491     
492     //根据质量因子调整量化表
493     _init_QualityTables(Qp);
494     
495     //初始化huffman熵编码表
496     _initHuffmanTables();
497     
498     /* 1、写入JPG文件各个字段信息 */
499     _write_jpeg_header(fp);
500     
501     /* 2、图片数据压缩 */
502     for(int y = 0; y < height; y += 8)
503     {//按照8x8宏块进行编码
504         for(int x = 0; x < width; x += 8)
505         {
506             //当前宏块色彩RGB转为YCbCr,JPG只对YUV进行编码
507             _convertMBColorRGB2YUV(pRgb, x, y, width, yData, cbData, crData);
508                 
509             //Y通道数据进行DCT变换 + 量化 + 哈夫曼编码 + 写入文件
510             _forword_FDC(yData, yQuant, MB_YTab);
511             _doHuffmanEncoding(yQuant, &prev_DC_Y, Y_DC_Huffman_Tab, Y_AC_Huffman_Tab, MbBitString, &bitStringCnt);
512             _write_bitstring_(MbBitString, bitStringCnt, &newByte, &newBytePos, fp);
513             
514             //Cb通道数据进行DCT变换 + 量化 + 哈夫曼编码 + 写入文件
515             _forword_FDC(cbData, cbQuant, MB_CbCrTab);
516             _doHuffmanEncoding(cbQuant, &prev_DC_Cb, CbCr_DC_Huffman_Tab, CbCr_AC_Huffman_Tab, MbBitString, &bitStringCnt);
517             _write_bitstring_(MbBitString, bitStringCnt, &newByte, &newBytePos, fp);
518             
519             //Cr通道数据进行DCT变换 + 量化 + 哈夫曼编码 + 写入文件
520             _forword_FDC(crData, crQuant, MB_CbCrTab);
521             _doHuffmanEncoding(crQuant, &prev_DC_Cr, CbCr_DC_Huffman_Tab, CbCr_AC_Huffman_Tab, MbBitString, &bitStringCnt);
522             _write_bitstring_(MbBitString, bitStringCnt, &newByte, &newBytePos, fp);
523         }
524     }
525     
526     /* 3、写入JPG文件尾 */
527     _write_word_(0xFFD9, fp);
528     
529     fclose(fp);
530     
531     return 0;
532 }
533 int main(int argc, char *argv[])
534 {
535     char *pRgb = NULL;
536     if (argc < 4)
537     {
538         printf("./bmp2jpg ./input.bmp ./output.jpg qp(1~99)\n");
539         return -1;
540     }
541     int qp = atoi(argv[3]);
542     readbmp(argv[1], &pRgb, (int *)&picwidth, (int *)&picheight);
543     encode_rgb2jpg(pRgb, picwidth, picheight, qp, argv[2]);
544     free(pRgb);
545     
546     return 0;
547 }

 

标签:fp,编码,--,JPEG,Standard,write,99,int,byte
From: https://www.cnblogs.com/hankgo/p/17422907.html

相关文章

  • quartz定时任务时间设置
    每天凌晨2点002**?和每天隔一小时0**/1**?例1:每隔5秒执行一次:*/5****?例2:每隔5分执行一次:0*/5***?在26分、29分、33分执行一次:026,29,33***?例3:每天半夜12点30分执行一次:0300**?(注意日期域为0不是24)每天凌晨1点执行一次:001**?......
  • 18-关键字高亮
    高亮原理我们在百度,京东搜索时,关键字会变成红色,比较醒目,这叫高亮显示:高亮显示的实现分为两步:1)给文档中的所有关键字都添加一个标签,例如<em>标签2)页面给<em>标签编写CSS样式实现高亮语法注意高亮是对关键字高亮,因此搜索条件必须带有关键字,而不能是范围这样的查询。......
  • linux 一块空磁盘初始化为dos的磁盘分区表,然后可以直接初始化整个磁盘为ext4格式,也可
    问:linux一块空磁盘初始化为dos的磁盘分区表,然后可以直接初始化整个磁盘为ext4格式,也可以先把磁盘分出一个Partition再初始化为ext4格式,这两种方式有什么区别,有什么特点答:在Linux上,对一块空磁盘进行初始化为ext4文件系统时,你可以选择两种不同的方式:直接初始化整个磁盘为......
  • 启发式算法在三维装箱问题上的应用
    启发式算法的出现时间比较难以确定,因为很多算法的提出都是在不同的领域和不同的时间段内,而且随着时间的推移,这些算法也在不断地完善和发展。以下是一些比较有代表性的启发式算法及其出现时间:1953年,模拟退火算法(SimulatedAnnealing,SA)模拟退火算法是一种基于固体物理学中固体退火......
  • <video>修改封面样式为填充
    视频的默认封面是没有填充满的,可能会留有空白,显得不美观,可以设置样式调整为填充:object-fit:cover 这样就显得好看多了:   ......
  • webgoat-sql注入
    advanced第五关在注册页面输入tom'or'1'='1,显示↓,说明此处存在在注入点,被带入数据库查询。输入tom'or'1'='2,出现报错。可以看出,对于正确与错误显示有明显的区别,故此处可以尝试基于布尔的盲注。首先我们想到的就是取用sqlmap工具跑抓包、将数据包复制到sqlmap文件......
  • 【毕业季】毕业设计避坑指南
    前言......
  • 将dom转化为图片和批量下载
    利用html2canvas和jszip第三方库importhtml2canvasfrom'html2canvas'importjszipfrom'jszip'具体实现:downloadAll(){this.loading=truelet_this=thisconststations=document.getElementsByClassName('station_b......
  • 查看ubuntu版本
    ​ 方法一在终端中执行下列指令:cat/etc/issue查看ubuntu版本ubuntu@VM-4-10-ubuntu:~$cat/etc/issueUbuntu22.04LTS\n\l 可以查看当前正在运行的 Ubuntu 的版本号。其输出结果类似下面的内容:Ubuntu14.04LTS\n\l方法二使用lsb_release命令也可以查......
  • Js获取当前是本年度第几周、周开始日期结束日期
    js获取今年第几周和获取周的开始和结束日期获取今年第几周周的开始和结束日期 获取今年第几周//页面初始时获取当前是本年第几周functiongetYearWeek(a,b,c){//a为年b为月c为日/*date1是当前日期date2是当年第一天......