⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 compressencode.cpp

📁 本程序是用VC++6.0开发的BMP转JPEG格式的图片压缩源程序
💻 CPP
📖 第 1 页 / 共 2 页
字号:
	//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 + -