├── CMakeLists.txt ├── README.md ├── test.cpp ├── jpeg_encoder.h └── jpeg_encoder.cpp /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.3) 2 | 3 | project(jpeg_encoder) 4 | 5 | add_executable(jpeg_encoder 6 | jpeg_encoder.cpp 7 | jpeg_encoder.h 8 | test.cpp 9 | ) 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | jpeg_encoder 2 | ============ 3 | 4 | 压缩bmp图像至jpg文件中。 5 | 这个工程是为我的博客中的一个系列文章准备的。 6 | http://thecodeway.com/blog/?p=69 7 | 目的是为了解释jpeg压缩算法的过程,所以没有考虑优化,只可用来学习,不建议用在实际项目中。 8 | 9 | 使用方法 10 | 11 | #include "jpeg_encoder.h" 12 | 13 | JpegEncoder encoder; 14 | //输入的文件必须是24bit的bmp文件,尺寸必须是8的倍数 15 | encoder.readFromBMP(inputFileName); 16 | 17 | //第二个参数在1~199之间,代表文件压缩程度,数字越大,压缩后的文件体积越小 18 | encoder.encodeToJPG(outputFileName, 50); 19 | 20 | -------------------------------------------------------------------------------- /test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "jpeg_encoder.h" 3 | 4 | //------------------------------------------------------------------------------- 5 | int main(int argc, char* argv[]) 6 | { 7 | if(argc<2) 8 | { 9 | printf("Usage: %s inputFile\n\tInput file must be 24bit bitmap file.\n", argv[0]); 10 | return 1; 11 | } 12 | 13 | const char* inputFileName = argv[1]; 14 | 15 | JpegEncoder encoder; 16 | if(!encoder.readFromBMP(inputFileName)) 17 | { 18 | return 1; 19 | } 20 | 21 | if(!encoder.encodeToJPG("out.jpg", 50)) 22 | { 23 | return 1; 24 | } 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /jpeg_encoder.h: -------------------------------------------------------------------------------- 1 | #ifndef __JPEG_ENCODER_HEADER__ 2 | #define __JPEG_ENCODER_HEADER__ 3 | 4 | 5 | class JpegEncoder 6 | { 7 | public: 8 | /** 清理数据 */ 9 | void clean(void); 10 | 11 | /** 从BMP文件中读取文件,仅支持24bit,长度是8的倍数的文件 */ 12 | bool readFromBMP(const char* fileName); 13 | 14 | /** 压缩到jpg文件中,quality_scale表示质量,取值范围(0,100), 数字越大压缩比例越高*/ 15 | bool encodeToJPG(const char* fileName, int quality_scale); 16 | 17 | private: 18 | int m_width; 19 | int m_height; 20 | unsigned char* m_rgbBuffer; 21 | 22 | unsigned char m_YTable[64]; 23 | unsigned char m_CbCrTable[64]; 24 | 25 | struct BitString 26 | { 27 | int length; 28 | int value; 29 | }; 30 | 31 | BitString m_Y_DC_Huffman_Table[12]; 32 | BitString m_Y_AC_Huffman_Table[256]; 33 | 34 | BitString m_CbCr_DC_Huffman_Table[12]; 35 | BitString m_CbCr_AC_Huffman_Table[256]; 36 | 37 | private: 38 | void _initHuffmanTables(void); 39 | void _initQualityTables(int quality); 40 | void _computeHuffmanTable(const char* nr_codes, const unsigned char* std_table, BitString* huffman_table); 41 | BitString _getBitCode(int value); 42 | 43 | void _convertColorSpace(const unsigned char* rgbBuffer, char* yData, char* cbData, char* crData); 44 | void _foword_FDC(const char* channel_data, short* fdc_data, const unsigned char* quant_table); 45 | void _doHuffmanEncoding(const short* DU, short& prevDC, const BitString* HTDC, const BitString* HTAC, 46 | BitString* outputBitString, int& bitStringCounts); 47 | 48 | private: 49 | void _write_jpeg_header(FILE* fp); 50 | void _write_byte_(unsigned char value, FILE* fp); 51 | void _write_word_(unsigned short value, FILE* fp); 52 | void _write_bitstring_(const BitString* bs, int counts, int& newByte, int& newBytePos, FILE* fp); 53 | void _write_(const void* p, int byteSize, FILE* fp); 54 | 55 | public: 56 | JpegEncoder(); 57 | ~JpegEncoder(); 58 | }; 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /jpeg_encoder.cpp: -------------------------------------------------------------------------------- 1 | #ifdef _MSC_VER 2 | #define _CRT_SECURE_NO_WARNINGS 3 | #endif 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "jpeg_encoder.h" 10 | 11 | namespace { 12 | //------------------------------------------------------------------------------- 13 | const unsigned char Luminance_Quantization_Table[64] = 14 | { 15 | 16, 11, 10, 16, 24, 40, 51, 61, 16 | 12, 12, 14, 19, 26, 58, 60, 55, 17 | 14, 13, 16, 24, 40, 57, 69, 56, 18 | 14, 17, 22, 29, 51, 87, 80, 62, 19 | 18, 22, 37, 56, 68, 109, 103, 77, 20 | 24, 35, 55, 64, 81, 104, 113, 92, 21 | 49, 64, 78, 87, 103, 121, 120, 101, 22 | 72, 92, 95, 98, 112, 100, 103, 99 23 | }; 24 | 25 | //------------------------------------------------------------------------------- 26 | const unsigned char Chrominance_Quantization_Table[64] = 27 | { 28 | 17, 18, 24, 47, 99, 99, 99, 99, 29 | 18, 21, 26, 66, 99, 99, 99, 99, 30 | 24, 26, 56, 99, 99, 99, 99, 99, 31 | 47, 66, 99, 99, 99, 99, 99, 99, 32 | 99, 99, 99, 99, 99, 99, 99, 99, 33 | 99, 99, 99, 99, 99, 99, 99, 99, 34 | 99, 99, 99, 99, 99, 99, 99, 99, 35 | 99, 99, 99, 99, 99, 99, 99, 99 36 | }; 37 | 38 | //------------------------------------------------------------------------------- 39 | const char ZigZag[64] = 40 | { 41 | 0, 1, 5, 6,14,15,27,28, 42 | 2, 4, 7,13,16,26,29,42, 43 | 3, 8,12,17,25,30,41,43, 44 | 9,11,18,24,31,40,44,53, 45 | 10,19,23,32,39,45,52,54, 46 | 20,22,33,38,46,51,55,60, 47 | 21,34,37,47,50,56,59,61, 48 | 35,36,48,49,57,58,62,63 49 | }; 50 | 51 | //------------------------------------------------------------------------------- 52 | const char Standard_DC_Luminance_NRCodes[] = { 0, 0, 7, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }; 53 | const unsigned char Standard_DC_Luminance_Values[] = { 4, 5, 3, 2, 6, 1, 0, 7, 8, 9, 10, 11 }; 54 | 55 | //------------------------------------------------------------------------------- 56 | const char Standard_DC_Chrominance_NRCodes[] = { 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 }; 57 | const unsigned char Standard_DC_Chrominance_Values[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; 58 | 59 | //------------------------------------------------------------------------------- 60 | const char Standard_AC_Luminance_NRCodes[] = { 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d }; 61 | const unsigned char Standard_AC_Luminance_Values[] = 62 | { 63 | 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 64 | 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 65 | 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 66 | 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 67 | 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 68 | 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 69 | 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 70 | 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 71 | 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 72 | 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 73 | 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 74 | 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 75 | 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 76 | 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 77 | 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 78 | 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 79 | 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 80 | 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 81 | 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 82 | 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 83 | 0xf9, 0xfa 84 | }; 85 | 86 | //------------------------------------------------------------------------------- 87 | const char Standard_AC_Chrominance_NRCodes[] = { 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 }; 88 | const unsigned char Standard_AC_Chrominance_Values[] = 89 | { 90 | 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 91 | 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 92 | 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 93 | 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 94 | 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 95 | 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 96 | 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 97 | 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 98 | 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 99 | 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 100 | 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 101 | 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 102 | 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 103 | 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 104 | 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 105 | 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 106 | 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 107 | 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 108 | 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 109 | 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 110 | 0xf9, 0xfa 111 | }; 112 | 113 | } 114 | 115 | //------------------------------------------------------------------------------- 116 | JpegEncoder::JpegEncoder() 117 | : m_width(0) 118 | , m_height(0) 119 | , m_rgbBuffer(0) 120 | { 121 | //初始化静态表格 122 | _initHuffmanTables(); 123 | } 124 | 125 | //------------------------------------------------------------------------------- 126 | JpegEncoder::~JpegEncoder() 127 | { 128 | clean(); 129 | } 130 | 131 | //------------------------------------------------------------------------------- 132 | void JpegEncoder::clean(void) 133 | { 134 | if(m_rgbBuffer) delete[] m_rgbBuffer; 135 | m_rgbBuffer=0; 136 | 137 | m_width=0; 138 | m_height=0; 139 | } 140 | 141 | //------------------------------------------------------------------------------- 142 | bool JpegEncoder::readFromBMP(const char* fileName) 143 | { 144 | //清理旧数据 145 | clean(); 146 | 147 | //BMP 文件格式 148 | #pragma pack(push, 2) 149 | typedef struct { 150 | unsigned short bfType; 151 | unsigned int bfSize; 152 | unsigned short bfReserved1; 153 | unsigned short bfReserved2; 154 | unsigned int bfOffBits; 155 | } BITMAPFILEHEADER; 156 | 157 | typedef struct { 158 | unsigned int biSize; 159 | int biWidth; 160 | int biHeight; 161 | unsigned short biPlanes; 162 | unsigned short biBitCount; 163 | unsigned int biCompression; 164 | unsigned int biSizeImage; 165 | int biXPelsPerMeter; 166 | int biYPelsPerMeter; 167 | unsigned int biClrUsed; 168 | unsigned int biClrImportant; 169 | } BITMAPINFOHEADER; 170 | #pragma pack(pop) 171 | 172 | //打开文件 173 | FILE* fp = fopen(fileName, "rb"); 174 | if(fp==0) return false; 175 | 176 | bool successed=false; 177 | do 178 | { 179 | BITMAPFILEHEADER fileHeader; 180 | BITMAPINFOHEADER infoHeader; 181 | 182 | if(1 != fread(&fileHeader, sizeof(fileHeader), 1, fp)) break; 183 | if(fileHeader.bfType!=0x4D42) break; 184 | 185 | if(1 != fread(&infoHeader, sizeof(infoHeader), 1, fp)) break; 186 | if(infoHeader.biBitCount!=24 || infoHeader.biCompression!=0) break; 187 | int width = infoHeader.biWidth; 188 | int height = infoHeader.biHeight < 0 ? (-infoHeader.biHeight) : infoHeader.biHeight; 189 | if((width&7)!=0 || (height&7)!=0) break; //必须是8的倍数 190 | 191 | int bmpSize = width*height*3; 192 | 193 | unsigned char* buffer = new unsigned char[bmpSize]; 194 | if(buffer==0) break; 195 | 196 | fseek(fp, fileHeader.bfOffBits, SEEK_SET); 197 | 198 | if(infoHeader.biHeight>0) 199 | { 200 | for(int i=0; i (yData, cbData, crData), [-128,128] 256 | unsigned char* rgbBuffer = m_rgbBuffer + yPos * m_width * 3 + xPos * 3; 257 | _convertColorSpace(rgbBuffer, yData, cbData, crData); 258 | 259 | BitString outputBitString[128]; 260 | int bitStringCounts; 261 | 262 | //Y通道压缩(yData -> yQuant) 263 | _foword_FDC(yData, yQuant, m_YTable); 264 | _doHuffmanEncoding(yQuant, prev_DC_Y, m_Y_DC_Huffman_Table, m_Y_AC_Huffman_Table, outputBitString, bitStringCounts); 265 | _write_bitstring_(outputBitString, bitStringCounts, newByte, newBytePos, fp); 266 | 267 | //Cb通道压缩(cbData -> cbQuant) 268 | _foword_FDC(cbData, cbQuant, m_CbCrTable); 269 | _doHuffmanEncoding(cbQuant, prev_DC_Cb, m_CbCr_DC_Huffman_Table, m_CbCr_AC_Huffman_Table, outputBitString, bitStringCounts); 270 | _write_bitstring_(outputBitString, bitStringCounts, newByte, newBytePos, fp); 271 | 272 | //Cr通道压缩(crData -> crQuant) 273 | _foword_FDC(crData, crQuant, m_CbCrTable); 274 | _doHuffmanEncoding(crQuant, prev_DC_Cr, m_CbCr_DC_Huffman_Table, m_CbCr_AC_Huffman_Table, outputBitString, bitStringCounts); 275 | _write_bitstring_(outputBitString, bitStringCounts, newByte, newBytePos, fp); 276 | } 277 | } 278 | 279 | //flush remain data 280 | if (newBytePos != 7) { 281 | _write_byte_(newByte, fp); 282 | } 283 | 284 | _write_word_(0xFFD9, fp); //Write End of Image Marker 285 | 286 | fclose(fp); 287 | 288 | return true; 289 | } 290 | 291 | //------------------------------------------------------------------------------- 292 | void JpegEncoder::_initHuffmanTables(void) 293 | { 294 | memset(&m_Y_DC_Huffman_Table, 0, sizeof(m_Y_DC_Huffman_Table)); 295 | _computeHuffmanTable(Standard_DC_Luminance_NRCodes, Standard_DC_Luminance_Values, m_Y_DC_Huffman_Table); 296 | 297 | memset(&m_Y_AC_Huffman_Table, 0, sizeof(m_Y_AC_Huffman_Table)); 298 | _computeHuffmanTable(Standard_AC_Luminance_NRCodes, Standard_AC_Luminance_Values, m_Y_AC_Huffman_Table); 299 | 300 | memset(&m_CbCr_DC_Huffman_Table, 0, sizeof(m_CbCr_DC_Huffman_Table)); 301 | _computeHuffmanTable(Standard_DC_Chrominance_NRCodes, Standard_DC_Chrominance_Values, m_CbCr_DC_Huffman_Table); 302 | 303 | memset(&m_CbCr_AC_Huffman_Table, 0, sizeof(m_CbCr_AC_Huffman_Table)); 304 | _computeHuffmanTable(Standard_AC_Chrominance_NRCodes, Standard_AC_Chrominance_Values, m_CbCr_AC_Huffman_Table); 305 | } 306 | //------------------------------------------------------------------------------- 307 | JpegEncoder::BitString JpegEncoder::_getBitCode(int value) 308 | { 309 | BitString ret; 310 | int v = (value>0) ? value : -value; 311 | 312 | //bit 的长度 313 | int length = 0; 314 | for(length=0; v; v>>=1) length++; 315 | 316 | ret.value = value>0 ? value : ((1<=100) quality_scale=99; 327 | 328 | for(int i=0; i<64; i++) 329 | { 330 | int temp = ((int)(Luminance_Quantization_Table[i] * quality_scale + 50) / 100); 331 | if (temp<=0) temp = 1; 332 | if (temp>0xFF) temp = 0xFF; 333 | m_YTable[ZigZag[i]] = (unsigned char)temp; 334 | 335 | temp = ((int)(Chrominance_Quantization_Table[i] * quality_scale + 50) / 100); 336 | if (temp<=0) temp = 1; 337 | if (temp>0xFF) temp = 0xFF; 338 | m_CbCrTable[ZigZag[i]] = (unsigned char)temp; 339 | } 340 | } 341 | 342 | //------------------------------------------------------------------------------- 343 | void JpegEncoder::_computeHuffmanTable(const char* nr_codes, const unsigned char* std_table, BitString* huffman_table) 344 | { 345 | unsigned char pos_in_table = 0; 346 | unsigned short code_value = 0; 347 | 348 | for(int k = 1; k <= 16; k++) 349 | { 350 | for(int j = 1; j <= nr_codes[k-1]; j++) 351 | { 352 | huffman_table[std_table[pos_in_table]].value = code_value; 353 | huffman_table[std_table[pos_in_table]].length = k; 354 | pos_in_table++; 355 | code_value++; 356 | } 357 | code_value <<= 1; 358 | } 359 | } 360 | 361 | //------------------------------------------------------------------------------- 362 | void JpegEncoder::_write_byte_(unsigned char value, FILE* fp) 363 | { 364 | _write_(&value, 1, fp); 365 | } 366 | 367 | //------------------------------------------------------------------------------- 368 | void JpegEncoder::_write_word_(unsigned short value, FILE* fp) 369 | { 370 | unsigned short _value = ((value>>8)&0xFF) | ((value&0xFF)<<8); 371 | _write_(&_value, 2, fp); 372 | } 373 | 374 | //------------------------------------------------------------------------------- 375 | void JpegEncoder::_write_(const void* p, int byteSize, FILE* fp) 376 | { 377 | fwrite(p, 1, byteSize, fp); 378 | } 379 | 380 | //------------------------------------------------------------------------------- 381 | void JpegEncoder::_doHuffmanEncoding(const short* DU, short& prevDC, const BitString* HTDC, const BitString* HTAC, 382 | BitString* outputBitString, int& bitStringCounts) 383 | { 384 | BitString EOB = HTAC[0x00]; 385 | BitString SIXTEEN_ZEROS = HTAC[0xF0]; 386 | 387 | int index=0; 388 | 389 | // encode DC 390 | int dcDiff = (int)(DU[0] - prevDC); 391 | prevDC = DU[0]; 392 | 393 | if (dcDiff == 0) 394 | outputBitString[index++] = HTDC[0]; 395 | else 396 | { 397 | BitString bs = _getBitCode(dcDiff); 398 | 399 | outputBitString[index++] = HTDC[bs.length]; 400 | outputBitString[index++] = bs; 401 | } 402 | 403 | // encode ACs 404 | int endPos=63; //end0pos = first element in reverse order != 0 405 | while((endPos > 0) && (DU[endPos] == 0)) endPos--; 406 | 407 | for(int i=1; i<=endPos; ) 408 | { 409 | int startPos = i; 410 | while((DU[i] == 0) && (i <= endPos)) i++; 411 | 412 | int zeroCounts = i - startPos; 413 | if (zeroCounts >= 16) 414 | { 415 | for (int j=1; j<=zeroCounts/16; j++) 416 | outputBitString[index++] = SIXTEEN_ZEROS; 417 | zeroCounts = zeroCounts%16; 418 | } 419 | 420 | BitString bs = _getBitCode(DU[i]); 421 | 422 | outputBitString[index++] = HTAC[(zeroCounts << 4) | bs.length]; 423 | outputBitString[index++] = bs; 424 | i++; 425 | } 426 | 427 | if (endPos != 63) 428 | outputBitString[index++] = EOB; 429 | 430 | bitStringCounts = index; 431 | } 432 | 433 | //------------------------------------------------------------------------------- 434 | void JpegEncoder::_write_bitstring_(const BitString* bs, int counts, int& newByte, int& newBytePos, FILE* fp) 435 | { 436 | unsigned short mask[] = {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768}; 437 | 438 | for(int i=0; i= 0) 444 | { 445 | if ((value & mask[posval]) != 0) 446 | { 447 | newByte = newByte | mask[newBytePos]; 448 | } 449 | posval--; 450 | newBytePos--; 451 | if (newBytePos < 0) 452 | { 453 | // Write to stream 454 | _write_byte_((unsigned char)(newByte), fp); 455 | if (newByte == 0xFF) 456 | { 457 | // Handle special case 458 | _write_byte_((unsigned char)(0x00), fp); 459 | } 460 | 461 | // Reinitialize 462 | newBytePos = 7; 463 | newByte = 0; 464 | } 465 | } 466 | } 467 | } 468 | 469 | //------------------------------------------------------------------------------- 470 | void JpegEncoder::_convertColorSpace(const unsigned char* rgbBuffer, char* yData, char* cbData, char* crData) 471 | { 472 | for (int y=0; y<8; y++) 473 | { 474 | const unsigned char* p = rgbBuffer + y*m_width*3; 475 | for (int x=0; x<8; x++) 476 | { 477 | unsigned char B = *p++; 478 | unsigned char G = *p++; 479 | unsigned char R = *p++; 480 | 481 | yData[y*8+x] = (char)(0.299f * R + 0.587f * G + 0.114f * B - 128); 482 | cbData[y*8+x] = (char)(-0.1687f * R - 0.3313f * G + 0.5f * B ); 483 | crData[y*8+x] = (char)(0.5f * R - 0.4187f * G - 0.0813f * B); 484 | } 485 | } 486 | } 487 | 488 | //------------------------------------------------------------------------------- 489 | void JpegEncoder::_foword_FDC(const char* channel_data, short* fdc_data, const unsigned char* quant_table) 490 | { 491 | const float PI = 3.1415926f; 492 | for(int v=0; v<8; v++) 493 | { 494 | for(int u=0; u<8; u++) 495 | { 496 | float alpha_u = (u==0) ? 1.f/sqrtf(8.0f) : 0.5f; 497 | float alpha_v = (v==0) ? 1.f/sqrtf(8.0f) : 0.5f; 498 | 499 | float temp = 0.f; 500 | for(int x=0; x<8; x++) 501 | { 502 | for(int y=0; y<8; y++) 503 | { 504 | float data = channel_data[y*8+x]; 505 | 506 | data *= cosf((2*x+1)*u*PI/16.0f); 507 | data *= cosf((2*y+1)*v*PI/16.0f); 508 | 509 | temp += data; 510 | } 511 | } 512 | int zigZagIndex = ZigZag[v * 8 + u]; 513 | 514 | //量化 515 | temp *= alpha_u*alpha_v/ quant_table[zigZagIndex]; 516 | fdc_data[zigZagIndex] = (short) ((short)(temp + 16384.5) - 16384); 517 | } 518 | } 519 | } 520 | 521 | //------------------------------------------------------------------------------- 522 | void JpegEncoder::_write_jpeg_header(FILE* fp) 523 | { 524 | //SOI 525 | _write_word_(0xFFD8, fp); // marker = 0xFFD8 526 | 527 | //APPO 528 | _write_word_(0xFFE0,fp); // marker = 0xFFE0 529 | _write_word_(16, fp); // length = 16 for usual JPEG, no thumbnail 530 | _write_("JFIF", 5, fp); // 'JFIF\0' 531 | _write_byte_(1, fp); // version_hi 532 | _write_byte_(1, fp); // version_low 533 | _write_byte_(0, fp); // xyunits = 0 no units, normal density 534 | _write_word_(1, fp); // xdensity 535 | _write_word_(1, fp); // ydensity 536 | _write_byte_(0, fp); // thumbWidth 537 | _write_byte_(0, fp); // thumbHeight 538 | 539 | //DQT 540 | _write_word_(0xFFDB, fp); //marker = 0xFFDB 541 | _write_word_(132, fp); //size=132 542 | _write_byte_(0, fp); //QTYinfo== 0: bit 0..3: number of QT = 0 (table for Y) 543 | // bit 4..7: precision of QT 544 | // bit 8 : 0 545 | _write_(m_YTable, 64, fp); //YTable 546 | _write_byte_(1, fp); //QTCbinfo = 1 (quantization table for Cb,Cr) 547 | _write_(m_CbCrTable, 64, fp); //CbCrTable 548 | 549 | //SOFO 550 | _write_word_(0xFFC0, fp); //marker = 0xFFC0 551 | _write_word_(17, fp); //length = 17 for a truecolor YCbCr JPG 552 | _write_byte_(8, fp); //precision = 8: 8 bits/sample 553 | _write_word_(m_height&0xFFFF, fp); //height 554 | _write_word_(m_width&0xFFFF, fp); //width 555 | _write_byte_(3, fp); //nrofcomponents = 3: We encode a truecolor JPG 556 | 557 | _write_byte_(1, fp); //IdY = 1 558 | _write_byte_(0x11, fp); //HVY sampling factors for Y (bit 0-3 vert., 4-7 hor.)(SubSamp 1x1) 559 | _write_byte_(0, fp); //QTY Quantization Table number for Y = 0 560 | 561 | _write_byte_(2, fp); //IdCb = 2 562 | _write_byte_(0x11, fp); //HVCb = 0x11(SubSamp 1x1) 563 | _write_byte_(1, fp); //QTCb = 1 564 | 565 | _write_byte_(3, fp); //IdCr = 3 566 | _write_byte_(0x11, fp); //HVCr = 0x11 (SubSamp 1x1) 567 | _write_byte_(1, fp); //QTCr Normally equal to QTCb = 1 568 | 569 | //DHT 570 | _write_word_(0xFFC4, fp); //marker = 0xFFC4 571 | _write_word_(0x01A2, fp); //length = 0x01A2 572 | _write_byte_(0, fp); //HTYDCinfo bit 0..3 : number of HT (0..3), for Y =0 573 | // bit 4 : type of HT, 0 = DC table,1 = AC table 574 | // bit 5..7 : not used, must be 0 575 | _write_(Standard_DC_Luminance_NRCodes, sizeof(Standard_DC_Luminance_NRCodes), fp); //DC_L_NRC 576 | _write_(Standard_DC_Luminance_Values, sizeof(Standard_DC_Luminance_Values), fp); //DC_L_VALUE 577 | _write_byte_(0x10, fp); //HTYACinfo 578 | _write_(Standard_AC_Luminance_NRCodes, sizeof(Standard_AC_Luminance_NRCodes), fp); 579 | _write_(Standard_AC_Luminance_Values, sizeof(Standard_AC_Luminance_Values), fp); //we'll use the standard Huffman tables 580 | _write_byte_(0x01, fp); //HTCbDCinfo 581 | _write_(Standard_DC_Chrominance_NRCodes, sizeof(Standard_DC_Chrominance_NRCodes), fp); 582 | _write_(Standard_DC_Chrominance_Values, sizeof(Standard_DC_Chrominance_Values), fp); 583 | _write_byte_(0x11, fp); //HTCbACinfo 584 | _write_(Standard_AC_Chrominance_NRCodes, sizeof(Standard_AC_Chrominance_NRCodes), fp); 585 | _write_(Standard_AC_Chrominance_Values, sizeof(Standard_AC_Chrominance_Values), fp); 586 | 587 | //SOS 588 | _write_word_(0xFFDA, fp); //marker = 0xFFC4 589 | _write_word_(12, fp); //length = 12 590 | _write_byte_(3, fp); //nrofcomponents, Should be 3: truecolor JPG 591 | 592 | _write_byte_(1, fp); //Idy=1 593 | _write_byte_(0, fp); //HTY bits 0..3: AC table (0..3) 594 | // bits 4..7: DC table (0..3) 595 | _write_byte_(2, fp); //IdCb 596 | _write_byte_(0x11, fp); //HTCb 597 | 598 | _write_byte_(3, fp); //IdCr 599 | _write_byte_(0x11, fp); //HTCr 600 | 601 | _write_byte_(0, fp); //Ss not interesting, they should be 0,63,0 602 | _write_byte_(0x3F, fp); //Se 603 | _write_byte_(0, fp); //Bf 604 | } 605 | --------------------------------------------------------------------------------