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