通过前面几篇的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 }

 

posted on 2023-05-23 11:41  沉默的思想  阅读(80)  评论(0编辑  收藏  举报