📄 jpg.h
字号:
/*************************************************************
Filename: JPG.h.
Writer: Dai Zhiheng.
Time: 2005-5-14.
**************************************************************/
#include "dct.h"
#include "math.h"
#include <fstream>
using namespace std;
int DCTOrd[64] = //Zig-Zag Order
{
0, 1, 8,16, 9, 2, 3,10,
17,24,32,25,18,11, 4, 5,
12,19,26,33,40,48,41,34,
27,20,13, 6, 7,14,21,28,
35,42,49,56,57,50,43,36,
29,22,15,23,30,37,44,51,
58,59,52,45,38,31,39,46,
53,60,61,54,47,55,62,63
};
double Q[64] = //Q
{
16, 11, 10, 16, 24, 40, 51, 61,
12, 12, 14, 19, 26, 58, 60, 55,
14, 13, 16, 24, 40, 57, 69, 56,
14, 17, 22, 29, 51, 87, 80, 62,
18, 22, 37, 56, 68,109,103, 77,
24, 35, 55, 64, 81,104,113, 92,
49, 64, 78, 87,103,121,120,101,
72, 92, 95, 98,112,100,103, 99
};
int DC_size[12] = {0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09};
int DC_code[12] = {0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x0e, 0x1e, 0x3e, 0x7e, 0xfe, 0x3fe};
int AC_size[256] =
{ 4,
2, 2, 3, 4, 5, 7, 8, 10, 16, 16, 0, 0, 0, 0, 0, 0,
4, 5, 7, 9, 11, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0,
5, 8, 10, 12, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0,
6, 9, 12, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0,
6, 10, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0,
7, 11, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0,
7, 12, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0,
8, 12, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0,
9, 15, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0,
9, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0,
9, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0,
10, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0,
10, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0,
11, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0,
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0,
11, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0
};
int AC_code[256] =
{
10, //EOB
0, 1, 4, 11, 26, 120, 248, 1014, 65410, 65411, 65535, 65535, 65535, 65535, 65535, 65535,
12, 27, 121, 502, 2038, 65412, 65413, 65414, 65415, 65416, 65535, 65535, 65535, 65535, 65535, 65535,
28, 249, 1015, 4084, 65417, 65418, 65419, 65420, 65421, 65422, 65535, 65535, 65535, 65535, 65535, 65535,
58, 503, 4085, 65423, 65424, 65425, 65426, 65427, 65428, 65429, 65535, 65535, 65535, 65535, 65535, 65535,
59, 1016, 65430, 65431, 65432, 65433, 65434, 65435, 65436, 65437, 65535, 65535, 65535, 65535, 65535, 65535,
122, 2039, 65438, 65439, 65440, 65441, 65442, 65443, 65444, 65445, 65535, 65535, 65535, 65535, 65535, 65535,
123, 4086, 65446, 65447, 65448, 65449, 65450, 65451, 65452, 65453, 65535, 65535, 65535, 65535, 65535, 65535,
250, 4087, 65454, 65455, 65456, 65457, 65458, 65459, 65460, 65461, 65535, 65535, 65535, 65535, 65535, 65535,
504, 32704, 65462, 65463, 65464, 65465, 65466, 65467, 65468, 65469, 65535, 65535, 65535, 65535, 65535, 65535,
505, 65470, 65471, 65472, 65473, 65474, 65475, 65476, 65477, 65478, 65535, 65535, 65535, 65535, 65535, 65535,
506, 65479, 65480, 65481, 65482, 65483, 65484, 65485, 65486, 65487, 65535, 65535, 65535, 65535, 65535, 65535,
1017, 65488, 65489, 65490, 65491, 65492, 65493, 65494, 65495, 65496, 65535, 65535, 65535, 65535, 65535, 65535,
1018, 65497, 65498, 65499, 65500, 65501, 65502, 65503, 65504, 65505, 65535, 65535, 65535, 65535, 65535, 65535,
2040, 65506, 65507, 65508, 65509, 65510, 65511, 65512, 65513, 65514, 65535, 65535, 65535, 65535, 65535, 65535,
65515, 65516, 65517, 65518, 65519, 65520, 65521, 65522, 65523, 65524, 65535, 65535, 65535, 65535, 65535,
2041, //ZRL
65525, 65526, 65527, 65528, 65529, 65530, 65531, 65532, 65533, 65534, 65535, 65535, 65535, 65535, 65535
};
unsigned char SOI[2] =
{
0xff,0xd8
};
unsigned char EOI[2] =
{
0xff,0xd9
};
unsigned char DQT[5] =
{
0xff,0xdb,0x00,0x43,0x03
};//还有64Byte的Q
unsigned char DHT_DC[33] =
{
0xff,0xc4,0x00,0x1f,0x00,
0x00,0x01,0x05,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b
};
unsigned char DHT_AC[183] =
{
0xff,0xc4,0x00,0xb5,0x11,
0x00,0x02,0x01,0x03,0x03,0x02,0x04,0x03,0x05,0x05,0x04,0x04,0x00,0x00,0x01,0x7d,
0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,
0x22,0x71,0x14,0x32,0x81,0x91,0xA1,0x08,0x23,0x42,0xB1,0xC1,0x15,0x52,0xD1,0xF0,
0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1A,0x25,0x26,0x27,0x28,
0x29,0x2A,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x43,0x44,0x45,0x46,0x47,0x48,0x49,
0x4A,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x63,0x64,0x65,0x66,0x67,0x68,0x69,
0x6A,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x83,0x84,0x85,0x86,0x87,0x88,0x89,
0x8A,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,
0xA8,0xA9,0xAA,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xC2,0xC3,0xC4,0xC5,
0xC6,0xC7,0xC8,0xC9,0xCA,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xE1,0xE2,
0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,
0xF9,0xFA
};
unsigned char SOS[10] =
{
0xff,0xDA,0x00,0x08,0x01,0x00,0x01,0x00,0x3f,0x00
};
unsigned char APPO[18] =
{
0xff,0xe0,0x00,0x10,0x4a,0x46,0x49,0x46,0x00,0x01,
0x02,0x00,0x00,0x01,0x00,0x01,0x00,0x00
};
unsigned char SOFO[13] =
{
0xff,0xc0,0x00,0x0b,0x08,0x01,0x00,0x01,0x00,0x01,0x00,0x22,0x03
};
/**********************************************************************************
函数功能:把2维BMP格式数据转换成JPG文件
Parameter:
*f 图像数据指针
height 图像长
width 图像宽
bmf JPG文件流指针
**********************************************************************************/
void jpg(double *f, int height, int width, ofstream bmf)
{
double *X1 = new double[64] ;//载入各块数据
double *F = new double [64] ;//DCT变换结果
int *X = new int[64] ;//量化和Zig-Zag排序结果
int *Z = new int[64] ;//游程中0的个数
int *P = new int[64] ;//游程值
int k=0; //AC保留个数
int ctc =0 ;//连0记数器
int DC_temp = 0;//DPCM 编码(上一块的DC)
int DC; //DC
int AC; //AC
long jpgcode = 0; //剩余的JPG码流
long jpg_codeN = 0; //剩余的码子长度
int r=1; //用来计算位数
int seg = 0; //位数
//向JPG 文件写JPG信息
bmf.seekp(0);
bmf.write(SOI, 2); //SOI
bmf.write(APPO, 18); //APPO
unsigned char Q1[64]; //量化表
for(int z=0; z<64;z++)
{
Q1[z] = (unsigned char)Q[DCTOrd[z]];
}
bmf.write(DQT, 5);
bmf.write(Q1, 64);
SOFO[5] = height>>8; //SOFO
SOFO[6] = height&0xff;
SOFO[7] = width>>8;
SOFO[8] = width&0xff;
bmf.write(SOFO, 13);
bmf.write(DHT_DC, 33); //Huffuman Table
bmf.write(DHT_AC, 183);
bmf.write(SOS, 10); //SOS
//开始编码
for(int i=0; i<(height/8); i++)//按块进行编码
for(int j=0; j<(width/8); j++)
{
//记数清0
k=0;
ctc=0;
//P、Z清零,载入数据:f->X1,Zig-Zag 排序//量化
for(int m=0; m<8; m++)
for(int n=0; n<8; n++)
{
*(Z + m*8 + n) = 0;
*(P + m*8 + n) = 0;
*(X1 + m*8 + n) = *(f + width*i*8 + width*m + 8*j + n) - 128;
}
//DCT变换:X1->F
// D2BMPDCT(X1, F, 8, 8, 3);//DCT变换:f-->F
dct2(X1, F, 8, 8);
//量化,四舍五入:F->X
for(m=0; m<64; m++)
{
if(*(F + DCTOrd[m])/Q1[m] - (int)(*(F + DCTOrd[m])/Q1[m]) <0.5)
*(X + m) = (int)(*(F + DCTOrd[m])/Q1[m]);
else
*(X + m) = (int)( *(F + DCTOrd[m])/Q1[m]) + 1;
}
//行程编码->P、Z,k
for(m=0; m<8; m++)
for(int n=0; n<8; n++)
{
if((m+n)==0)
{
*P=*X;
k++;
continue;
}
if(*(X + m*8 + n)!=0)
{
for(int l=0; l<ctc/16+1; l++)
{
if((ctc%16)!=(ctc-l*16))
{
*(Z + k) = 15;
*(P + k) = 0;
}
else
{
*(Z + k) = (ctc%16);
*(P + k) = *(X + m*8 + n);
}
k++;
}
ctc=0;
}
else
{
ctc++;
}
}
//k个行程中,1个DC分量,k-1个AC分量
//先对DC求差分、查Huffuman表、
r = 1;
seg = 0;
while(1)
{
if(r>abs(*P - DC_temp))break;
else{
r = (r<<1);
seg++;
}
}
if((*P - DC_temp)<0) DC = ((~(DC_temp-*P))&(r-1));
else DC = (*P - DC_temp);
{
jpgcode = (jpgcode<<(DC_size[seg] + seg)) + ((DC_code[seg])<<seg) + DC;
jpg_codeN = jpg_codeN + DC_size[seg] + seg;
}
while(jpg_codeN > 7){
jpg_codeN -= 8;
bmf.put((unsigned char)(jpgcode/(1<<jpg_codeN)));
if((unsigned char)(jpgcode/(1<<jpg_codeN))==255)
bmf.put((unsigned char)0);//0xFF->补0x00
jpgcode = jpgcode - ((jpgcode>>jpg_codeN)<<jpg_codeN);
}
//再对AC进行Huffuman编码
for(m=1; m<k; m++)
{
r=1;
seg = 0;
while(1)
{
if(r>abs(*(P + m)))break;
else{
r=(r<<1);
seg++;
}
}
if(*(P + m)<0) AC = ((~(-*(P + m)))&(r-1));
else AC = *(P + m);
jpgcode = (jpgcode<<(AC_size[*(Z+m)*16 + seg] + seg)) + (AC_code[*(Z+m)*16 + seg]<<seg) + AC;
jpg_codeN = jpg_codeN + AC_size[*(Z+m)*16 + seg] + seg;
while(jpg_codeN > 7){
jpg_codeN -= 8;
bmf.put((unsigned char)(jpgcode/(1<<jpg_codeN)));
if((unsigned char)(jpgcode/(1<<jpg_codeN))==255)
bmf.put((unsigned char)0);//0xFF->补0x00
jpgcode= jpgcode - ((jpgcode>>jpg_codeN)<<jpg_codeN);
}
}
if(k<63)//输出EOB
{
jpgcode = (jpgcode<<(AC_size[0])) + AC_code[0];
jpg_codeN = jpg_codeN + AC_size[0];
while(jpg_codeN > 7){
jpg_codeN -= 8;
bmf.put((unsigned char)(jpgcode/(1<<jpg_codeN)));
if((unsigned char)(jpgcode/(1<<jpg_codeN))==255)
bmf.put((unsigned char)0);//0xFF->补0x00
jpgcode= jpgcode - ((jpgcode>>jpg_codeN)<<jpg_codeN);
}
}
DC_temp = *P;//备份DC
}
//补全一个Byte.
if(jpg_codeN>0)
{
bmf.put((unsigned char)( (jpgcode<<(8-jpg_codeN)) + (1<<(8-jpg_codeN)) -1 ));
if((unsigned char)( (jpgcode<<(8-jpg_codeN)) + (1<<(8-jpg_codeN)) -1 )==255)
bmf.put((unsigned char)0);//0xFF->补0x00
}
bmf.write(EOI, 2);
bmf.close();
delete []X;
delete []Z;
delete []P;
delete []F;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -