📄 compressencode.cpp
字号:
//Cb
emit_byte(2);//index
emit_byte(0x11);//dc and ac tbl use 1-th tbl
//Cr
emit_byte(3);//index
emit_byte(0x11);//dc and ac tbl use 1-th tbl
emit_byte(0);//Ss
emit_byte(0x3F);//Se
emit_byte(0);// Ah/Al
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//对图像进行压缩编码的主函数
bool CompressEncode::CompressImage(
unsigned char *pInBuf, //源数据
unsigned char *pOutBuf,//目标数据
int nWidthPix, //图像宽
int nHeight, //图像高
int& nOutputBytes //转化后字节数
)
{
// 错误处理
if(( pInBuf == 0 )||( pOutBuf == 0 ))
return false;
m_nWidth = nWidthPix;
m_nHeight = nHeight;
m_pOutBuf = pOutBuf;
//写入JPG头
WriteJpegHeader();
int nHeadBytes = m_pOutBuf - pOutBuf;
int nRowBytes = ( m_nWidth * 3 + 3 ) / 4 * 4;
//异常
if(( nWidthPix <= 0 )||( nRowBytes <= 0 )||( nHeight <= 0 ))
return false;
int xPixel, yPixel, xTile, yTile, cxTile, cyTile, cxBlock, cyBlock;
int x, y, nTrueRows, nTrueCols, nTileBytes;
unsigned char byTile[768], *pTileRow, *pLastPixel, *pHolePixel;
// 水平和垂直MCU的数量
// MCU(Minimum Coded Unit), 16*16 象素
cxTile = (nWidthPix + 15)>> 4;
cyTile = (nHeight + 15) >> 4;
// 水平和垂直块的数量 8*8 象素
cxBlock = cxTile << 1;
cyBlock = cyTile << 1;
//初始化
nTileBytes = 0;
m_dcY = m_dcCb = m_dcCr = 0;
m_nPutBits = 0;
m_nPutVal = 0;
//循环对每个MCU进行处理
for( yTile = 0; yTile < cyTile; yTile++ )
{
for( xTile = 0; xTile < cxTile; xTile++ )
{
//获得此MCU初始相似
xPixel = xTile << 4;
yPixel = yTile << 4;
// 获得列和栏数
nTrueRows = 16;
nTrueCols = 16;
if( yPixel + nTrueRows > nHeight )
nTrueRows = nHeight - yPixel;
if( xPixel + nTrueCols > nWidthPix )
nTrueCols = nWidthPix - xPixel;
pTileRow = pInBuf + (m_nHeight - yPixel) * nRowBytes + xPixel * 3;
//获得数据
for( y = 0; y < 16; y ++ )
{
if( y < nTrueRows )
{
pTileRow -= nRowBytes;
memcpy( byTile + y * 16 * 3, pTileRow, nTrueCols * 3 );
if( nTrueCols < 16 )
{
pLastPixel = pTileRow + (nTrueCols - 1) * 3;
pHolePixel = byTile + y * 16 * 3 + nTrueCols * 3;
for( x = nTrueCols; x < 16; x ++ )
{
memcpy( pHolePixel, pLastPixel, 3 );
pHolePixel += 3;
}
}
}
else
{
memcpy( byTile + y * 16 * 3,
byTile + (nTrueRows - 1) * 16 * 3,
16 * 3 );
}
}
//调用函数对此MCU进行压缩编码
if( ! CompressOneTile( byTile ))
return false;
}
}
//处理剩余部分
if( m_nPutBits > 0 )
{
EmitLeftBits( );
}
//写入结束标志
emit_marker(M_EOI);
nOutputBytes = m_pOutBuf - pOutBuf;
return true;
}
////////////////////////////////////////////////////////////////////////////////
// 对一个16*16象素的块进行基于DCT的压缩编码
bool CompressEncode::CompressOneTile(
unsigned char * pBgr
)
{
// 三个颜色部分
int pYCbCr[384];
// DCT变换输出
int coef[64];
// 颜色转换
BGRToYCbCrEx( pBgr, pYCbCr );
// 分别对Y/Cb/Cr几个部分进行压缩编码 Y: 4 blocks; Cb: 1 block; Cr: 1 block
int i;
for( i=0; i<6; i++ )
{
ForwardDct( pYCbCr + i*64, coef );
Quantize( coef, i );
HuffmanEncode( coef, i );
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
// 颜色转换
void CompressEncode::BGRToYCbCr(
unsigned char * pBgr, //tile source data, in BGR format, 768 bytes
unsigned char * pY, //out, Illuminance, 256 bytes
unsigned char * pCb, //out, Cb, 256 bytes
unsigned char * pCr //out, Cr, 256 bytes
)
{
int i;
unsigned char r, g, b, *pByte = pBgr, *py = pY, *pcb = pCb, *pcr = pCr;
for( i=0; i<256; i++ )
{
b = *(pByte ++);
g = *(pByte ++);
r = *(pByte ++);
*(py++) = (unsigned char)((m_RToY[r] + m_GToY[g] + m_BToY[b] )>>16);
*(pcb++) = (unsigned char)((m_RToCb[r] + m_GToCb[g] + m_BToCb[b])>>16);
*(pcr++) = (unsigned char)((m_RToCr[r] + m_GToCr[g] + m_BToCr[b])>>16);
}
}
////////////////////////////////////////////////////////////////////////////////
void CompressEncode::BGRToYCbCrEx(
unsigned char * pBgr, //in, tile data, in BGR format, 768 bytes
int * pBlock //out, Y: 256; Cb: 64; Cr: 64
)
{
int x, y, *py[4], *pcb, *pcr;
unsigned char r, g, b, *pByte;
pByte = pBgr;
for( x = 0; x < 4; x++ )
py[ x ] = pBlock + 64 * x;
pcb = pBlock + 256;
pcr = pBlock + 320;
for( y=0; y<16; y++ )
{
for( x=0; x<16; x++ )
{
b = *(pByte ++);
g = *(pByte ++);
r = *(pByte ++);
// block number is ((y/8) * 2 + x/8): 0, 1, 2, 3
*( py[((y>>3)<<1) + (x>>3)] ++ ) =
((m_RToY[ r ] + m_GToY[ g ] + m_BToY[ b ] )>>16) -128;
// Equal to: (( x%2 == 0 )&&( y%2 == 0 ))
if( (!(y & 1L)) && (!(x & 1L)) )
{
*(pcb++) =
((m_RToCb[ r ] + m_GToCb[ g ] + m_BToCb[ b ])>>16) -128;
*(pcr++) =
((m_RToCr[ r ] + m_GToCr[ g ] + m_BToCr[ b ])>>16) -128;
}
}
}
}
////////////////////////////////////////////////////////////////////////////////
//离散余弦正变换
void CompressEncode::ForwardDct(
int* data, //source data, length is 64
int* coef //output dct coefficients
)
{
////////////////////////////////////////////////////////////////////////////
//为了方便计算定义几个宏
#define FIX_0_382683433 ((int)98) /* FIX(0.382683433) */
#define FIX_0_541196100 ((int)139) /* FIX(0.541196100) */
#define FIX_0_707106781 ((int)181) /* FIX(0.707106781) */
#define FIX_1_306562965 ((int)334) /* FIX(1.306562965) */
#define MULTIPLY(var,cons) (int)(((cons) * (var)) >> 8 )
////////////////////////////////////////////////////////////////////////////
static const int DCTSIZE = 8;
int x, y;
int *dataptr;
int tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
int tmp10, tmp11, tmp12, tmp13;
int z1, z2, z3, z4, z5, z11, z13, *coefptr;
/* Pass 1: process rows. */
dataptr = data; //input
coefptr = coef; //output
for( y = 0; y < 8; y++ )
{
tmp0 = dataptr[0] + dataptr[7];
tmp7 = dataptr[0] - dataptr[7];
tmp1 = dataptr[1] + dataptr[6];
tmp6 = dataptr[1] - dataptr[6];
tmp2 = dataptr[2] + dataptr[5];
tmp5 = dataptr[2] - dataptr[5];
tmp3 = dataptr[3] + dataptr[4];
tmp4 = dataptr[3] - dataptr[4];
/* Even part */
tmp10 = tmp0 + tmp3; /* phase 2 */
tmp13 = tmp0 - tmp3;
tmp11 = tmp1 + tmp2;
tmp12 = tmp1 - tmp2;
coefptr[0] = tmp10 + tmp11; /* phase 3 */
coefptr[4] = tmp10 - tmp11;
z1 = MULTIPLY(tmp12 + tmp13, FIX_0_707106781); /* c4 */
coefptr[2] = tmp13 + z1; /* phase 5 */
coefptr[6] = tmp13 - z1;
/* Odd part */
tmp10 = tmp4 + tmp5; /* phase 2 */
tmp11 = tmp5 + tmp6;
tmp12 = tmp6 + tmp7;
/* The rotator is modified from fig 4-8 to avoid extra negations. */
z5 = MULTIPLY(tmp10 - tmp12, FIX_0_382683433); /* c6 */
z2 = MULTIPLY(tmp10, FIX_0_541196100) + z5; /* c2-c6 */
z4 = MULTIPLY(tmp12, FIX_1_306562965) + z5; /* c2+c6 */
z3 = MULTIPLY(tmp11, FIX_0_707106781); /* c4 */
z11 = tmp7 + z3; /* phase 5 */
z13 = tmp7 - z3;
coefptr[5] = z13 + z2; /* phase 6 */
coefptr[3] = z13 - z2;
coefptr[1] = z11 + z4;
coefptr[7] = z11 - z4;
dataptr += 8; /* advance pointer to next row */
coefptr += 8;
}
/* Pass 2: process columns. */
coefptr = coef; //both input and output
for ( x = 0; x < 8; x++ )
{
tmp0 = coefptr[DCTSIZE*0] + coefptr[DCTSIZE*7];
tmp7 = coefptr[DCTSIZE*0] - coefptr[DCTSIZE*7];
tmp1 = coefptr[DCTSIZE*1] + coefptr[DCTSIZE*6];
tmp6 = coefptr[DCTSIZE*1] - coefptr[DCTSIZE*6];
tmp2 = coefptr[DCTSIZE*2] + coefptr[DCTSIZE*5];
tmp5 = coefptr[DCTSIZE*2] - coefptr[DCTSIZE*5];
tmp3 = coefptr[DCTSIZE*3] + coefptr[DCTSIZE*4];
tmp4 = coefptr[DCTSIZE*3] - coefptr[DCTSIZE*4];
/* Even part */
tmp10 = tmp0 + tmp3; /* phase 2 */
tmp13 = tmp0 - tmp3;
tmp11 = tmp1 + tmp2;
tmp12 = tmp1 - tmp2;
coefptr[DCTSIZE*0] = tmp10 + tmp11; /* phase 3 */
coefptr[DCTSIZE*4] = tmp10 - tmp11;
z1 = MULTIPLY(tmp12 + tmp13, FIX_0_707106781); /* c4 */
coefptr[DCTSIZE*2] = tmp13 + z1; /* phase 5 */
coefptr[DCTSIZE*6] = tmp13 - z1;
/* Odd part */
tmp10 = tmp4 + tmp5; /* phase 2 */
tmp11 = tmp5 + tmp6;
tmp12 = tmp6 + tmp7;
/* The rotator is modified from fig 4-8 to avoid extra negations. */
z5 = MULTIPLY(tmp10 - tmp12, FIX_0_382683433); /* c6 */
z2 = MULTIPLY(tmp10, FIX_0_541196100) + z5; /* c2-c6 */
z4 = MULTIPLY(tmp12, FIX_1_306562965) + z5; /* c2+c6 */
z3 = MULTIPLY(tmp11, FIX_0_707106781); /* c4 */
z11 = tmp7 + z3; /* phase 5 */
z13 = tmp7 - z3;
coefptr[DCTSIZE*5] = z13 + z2; /* phase 6 */
coefptr[DCTSIZE*3] = z13 - z2;
coefptr[DCTSIZE*1] = z11 + z4;
coefptr[DCTSIZE*7] = z11 - z4;
coefptr++; /* advance pointer to next column */
}
}
////////////////////////////////////////////////////////////////////////////////
//进行量化
void CompressEncode::Quantize(
int* coef, //coef is both in and out
int iBlock //block id; Y: 0,1,2,3; Cb: 4; Cr: 5
)
{
int temp;
unsigned short qval, *pQuant;
if( iBlock < 4 )
pQuant = m_qtblY;
else
pQuant = m_qtblCbCr;
for (int i = 0; i < 64; i++)
{
qval = pQuant[i];
temp = coef[i];
#define DIVIDE_BY(a,b) if (a >= b) a /= b; else a = 0
if ( temp < 0)
{
temp = -temp;
temp += qval>>1; /* for rounding */
DIVIDE_BY(temp, qval);
temp = -temp;
}
else
{
temp += qval>>1; /* for rounding */
DIVIDE_BY(temp, qval);
}
coef[i] = temp;
}
}
////////////////////////////////////////////////////////////////////////////////
//Huffman编码
bool CompressEncode::HuffmanEncode(
int* pCoef, // DCT coefficients
int iBlock // 0,1,2,3:Y; 4:Cb; 5:Cr;
)
{
//对AC系数进行Z字型扫描
static const int jpeg_natural_order[64+16] = {
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,
63, 63, 63, 63, 63, 63, 63, 63,//extra entries for safety
63, 63, 63, 63, 63, 63, 63, 63
};
int temp, temp2, nbits, k, r, i;
int *block = pCoef;
int *pLastDc = &m_dcY;
HUFFMAN_TABLE *dctbl, *actbl;
if( iBlock < 4 )
{
dctbl = & m_htblYDC;
actbl = & m_htblYAC;
// pLastDc = &m_dcY;
}
else
{
dctbl = & m_htblCbCrDC;
actbl = & m_htblCbCrAC;
if( iBlock == 4 )
pLastDc = &m_dcCb;
else
pLastDc = &m_dcCr;
}
//对DC系数进行编码
temp = temp2 = block[0] - (*pLastDc);
*pLastDc = block[0];
if (temp < 0) {
temp = -temp; /* temp is abs value of input */
temp2 --;
}
/* Find the number of bits needed for the magnitude of the coefficient */
nbits = 0;
while (temp) {
nbits ++;
temp >>= 1;
}
// Write category number
if (! EmitBits( dctbl->code[nbits], dctbl->size[nbits] ))
return FALSE;
// Write category offset
if (nbits) /* EmitBits rejects calls with size 0 */
{
if (! EmitBits( (unsigned int) temp2, nbits ))
return FALSE;
}
////////////////////////////////////////////////////////////////////////////
//对AC系数进行编码
r = 0; /* r = run length of zeros */
for (k = 1; k < 64; k++)
{
if ((temp = block[jpeg_natural_order[k]]) == 0)
{
r++;
}
else
{
/* if run length > 15, must emit special run-length-16 codes (0xF0) */
while (r > 15) {
if (! EmitBits( actbl->code[0xF0], actbl->size[0xF0] ))
return FALSE;
r -= 16;
}
temp2 = temp;
if (temp < 0) {
temp = -temp; /* temp is abs value of input */
/* This code assumes we are on a two's complement machine */
temp2--;
}
/* Find the number of bits needed for the magnitude of the coefficient */
nbits = 1; /* there must be at least one 1 bit */
while ((temp >>= 1))
nbits++;
/* Emit Huffman symbol for run length / number of bits */
i = (r << 4) + nbits;
if (! EmitBits( actbl->code[i], actbl->size[i] ))
return FALSE;
// Write Category offset
if (! EmitBits( (unsigned int) temp2, nbits ))
return FALSE;
r = 0;
}
}
if (r > 0)
{
if (! EmitBits( actbl->code[0], actbl->size[0] ))
return FALSE;
}
return TRUE;
}
////////////////////////////////////////////////////////////////////////////////
inline bool CompressEncode::EmitBits(
unsigned int code, //Huffman code
int size //Size in bits of the Huffman code
)
{
/* This routine is heavily used, so it's worth coding tightly. */
int put_buffer = (int) code;
int put_bits = m_nPutBits;
/* if size is 0, caller used an invalid Huffman table entry */
if (size == 0)
return false;
put_buffer &= (((int)1)<<size) - 1; /* mask off any extra bits in code */
put_bits += size; /* new number of bits in buffer */
put_buffer <<= 24 - put_bits; /* align incoming bits */
put_buffer |= m_nPutVal; /* and merge with old buffer contents */
// If there are more than 8 bits, write it out
unsigned char uc;
while (put_bits >= 8)
{
// Write one byte out !!!!
uc = (unsigned char) ((put_buffer >> 16) & 0xFF);
emit_byte(uc);
if (uc == 0xFF) { //need to stuff a zero byte?
emit_byte(0); // Write one byte out !!!!
}
put_buffer <<= 8;
put_bits -= 8;
}
m_nPutVal = put_buffer; /* update state variables */
m_nPutBits = put_bits;
return TRUE;
}
////////////////////////////////////////////////////////////////////////////////
inline void CompressEncode::EmitLeftBits(void)
{
if (! EmitBits(0x7F, 7)) /* fill 7 bits with ones */
return;
m_nPutVal = 0;
m_nPutBits = 0;
}
////////////////////////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -