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

📄 compressencode.cpp

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


#include "stdafx.h"
#include "CompressEncode.h"


////////////////////////////////////////////////////////////////////////////////
//JPEG标志码
typedef enum {		
  M_SOF0  = 0xc0,
  M_SOF1  = 0xc1,
  M_SOF2  = 0xc2,
  M_SOF3  = 0xc3,
  
  M_SOF5  = 0xc5,
  M_SOF6  = 0xc6,
  M_SOF7  = 0xc7,
  
  M_JPG   = 0xc8,
  M_SOF9  = 0xc9,
  M_SOF10 = 0xca,
  M_SOF11 = 0xcb,
  
  M_SOF13 = 0xcd,
  M_SOF14 = 0xce,
  M_SOF15 = 0xcf,
  
  M_DHT   = 0xc4,
  
  M_DAC   = 0xcc,
  
  M_RST0  = 0xd0,
  M_RST1  = 0xd1,
  M_RST2  = 0xd2,
  M_RST3  = 0xd3,
  M_RST4  = 0xd4,
  M_RST5  = 0xd5,
  M_RST6  = 0xd6,
  M_RST7  = 0xd7,
  
  M_SOI   = 0xd8,
  M_EOI   = 0xd9,
  M_SOS   = 0xda,
  M_DQT   = 0xdb,
  M_DNL   = 0xdc,
  M_DRI   = 0xdd,
  M_DHP   = 0xde,
  M_EXP   = 0xdf,
  
  M_APP0  = 0xe0,
  M_APP1  = 0xe1,
  M_APP2  = 0xe2,
  M_APP3  = 0xe3,
  M_APP4  = 0xe4,
  M_APP5  = 0xe5,
  M_APP6  = 0xe6,
  M_APP7  = 0xe7,
  M_APP8  = 0xe8,
  M_APP9  = 0xe9,
  M_APP10 = 0xea,
  M_APP11 = 0xeb,
  M_APP12 = 0xec,
  M_APP13 = 0xed,
  M_APP14 = 0xee,
  M_APP15 = 0xef,
  
  M_JPG0  = 0xf0,
  M_JPG13 = 0xfd,
  M_COM   = 0xfe,
  
  M_TEM   = 0x01,
  
  M_ERROR = 0x100
} JPEG_MARKER;

//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
	};


	
	
	unsigned char std_luminance_quant_tbl[64] = 
	{
			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
	};
	unsigned char std_chrominance_quant_tbl[64] = 
	{
			17,  18,  24,  47,  99,  99,  99,  99,
			18,  21,  26,  66,  99,  99,  99,  99,
			24,  26,  56,  99,  99,  99,  99,  99,
			47,  66,  99,  99,  99,  99,  99,  99,
			99,  99,  99,  99,  99,  99,  99,  99,
			99,  99,  99,  99,  99,  99,  99,  99,
			99,  99,  99,  99,  99,  99,  99,  99,
			99,  99,  99,  99,  99,  99,  99,  99
	};





////////////////////////////////////////////////////////////////////////////////

#define emit_byte(val)	*m_pOutBuf++=(unsigned char)(val);

#define emit_2bytes(val)			\
*m_pOutBuf=(unsigned char)(((val)>>8)&0xFF);\
*(m_pOutBuf+1)=(unsigned char)((val)&0xFF);\
m_pOutBuf+=2;

#define emit_marker(val)			\
*m_pOutBuf=0xFF;\
*(m_pOutBuf+1)=(unsigned char)(val);\
m_pOutBuf+=2;
	


////////////////////////////////////////////////////////////////////////////////

CompressEncode::CompressEncode( )
{
	m_nQuality = 50;
	InitEncoder( );	
}

CompressEncode::CompressEncode( int nQuality )
{
	m_nQuality = nQuality;
	InitEncoder( );
}

CompressEncode::~CompressEncode( )
{
	
}


////////////////////////////////////////////////////////////////////////////////

//初始化颜色转化表、量化表、Huffman表
void CompressEncode::InitEncoder( )
{
	
	InitColorTable( );


	InitQuantTable( );

	
	InitHuffmanTable( );
}


////////////////////////////////////////////////////////////////////////////////

//从RGB转换成YCbCr
/*
 
 *	Y  =  0.29900 * R + 0.58700 * G + 0.11400 * B
 *	Cb = -0.16874 * R - 0.33126 * G + 0.50000 * B  + 128
 *	Cr =  0.50000 * R - 0.41869 * G - 0.08131 * B  + 128
 
 */
void CompressEncode::InitColorTable( void )
{
	int i;
	int nScale	= 1L << 16;		
	int CBCR_OFFSET = 128<<16;
	
	int nHalf = nScale >> 1;	

	for( i=0; i<256; i++ )
	{
		m_RToY[ i ]	= (int)( 0.29900 * nScale + 0.5 ) * i;
		m_GToY[ i ]	= (int)( 0.58700 * nScale + 0.5 ) * i;
		m_BToY[ i ]	= (int)( 0.11400 * nScale + 0.5 ) * i + nHalf;

		m_RToCb[ i ] = (int)( 0.16874 * nScale + 0.5 ) * (-i);
		m_GToCb[ i ] = (int)( 0.33126 * nScale + 0.5 ) * (-i);
		m_BToCb[ i ] = (int)( 0.50000 * nScale + 0.5 ) * i + 
										CBCR_OFFSET + nHalf - 1;

		m_RToCr[ i ] = m_BToCb[ i ];
		m_GToCr[ i ] = (int)( 0.41869 * nScale + 0.5 ) * (-i);
		m_BToCr[ i ] = (int)( 0.08131 * nScale + 0.5 ) * (-i);
	}
}


////////////////////////////////////////////////////////////////////////////////
//初始化量化表
//m_tblYQuant[0..63] 和m_tblCbCrQuant[0..63]

void CompressEncode::InitQuantTable( void )
{
	
	static unsigned short aanscales[64] = {
			
			16384, 22725, 21407, 19266, 16384, 12873,  8867,  4520,
			22725, 31521, 29692, 26722, 22725, 17855, 12299,  6270,
			21407, 29692, 27969, 25172, 21407, 16819, 11585,  5906,
			19266, 26722, 25172, 22654, 19266, 15137, 10426,  5315,
			16384, 22725, 21407, 19266, 16384, 12873,  8867,  4520,
			12873, 17855, 16819, 15137, 12873, 10114,  6967,  3552,
			 8867, 12299, 11585, 10426,  8867,  6967,  4799,  2446,
			 4520,  6270,  5906,  5315,  4520,  3552,  2446,  1247
	};
	
	
	m_nScale = m_nQuality;

	if (m_nScale <= 0) 
		m_nScale = 1;
	if (m_nScale > 100) 
		m_nScale = 100;
	
	
	if (m_nScale < 50)
		m_nScale = 5000 / m_nScale;
	else
		m_nScale = 200 - m_nScale*2;

	
	memcpy( m_dqtY,		std_luminance_quant_tbl,	64 );
	memcpy( m_dqtCbCr,	std_chrominance_quant_tbl,	64 );

	
	ScaleTable( m_dqtY,		m_nScale, 100 );
	ScaleTable( m_dqtCbCr,	m_nScale, 100 );		


	ScaleQuantTable( m_qtblY,    &std_luminance_quant_tbl[0],   aanscales );
	ScaleQuantTable( m_qtblCbCr, &std_chrominance_quant_tbl[0], aanscales );
}

////////////////////////////////////////////////////////////////////////////////
void CompressEncode::ScaleTable(unsigned char* tbl, int scale, int max)
{
	int i, temp, half = max/2;

	for (i = 0; i < 64; i++) 
	{
		
		temp = (int)(( m_nScale * tbl[i] + half ) / max );

		
		if (temp <= 0)
			temp = 1;
		if (temp > 255)
			temp = 255;

		
		tbl[i] = (unsigned char)temp;
	}
}


////////////////////////////////////////////////////////////////////////////////

void CompressEncode::ScaleQuantTable(
			unsigned short* tblRst,		
			unsigned char* tblStd,		
			unsigned short* tblAan		
			)
{
	int i, temp, half = 1<<10;
	for (i = 0; i < 64; i++) 
	{
		
		temp = (int)(( m_nScale * tblStd[i] + 50 ) / 100 );

		
		if (temp <= 0) 
			temp = 1;
		if (temp > 255)
			temp = 255;		

		
		tblRst[i] = (unsigned short)(( temp * tblAan[i] + half )>>11 );
	}
}


////////////////////////////////////////////////////////////////////////////////
//初始化Huffman表:
//		HUFFMAN_TABLE m_htblYDC, m_htblYAC, m_htblCbCrDC, m_htblCbCrAC;

void CompressEncode::InitHuffmanTable( void )
{
	//	Y dc系数
	static unsigned char bitsYDC[17] =
    { 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 };
	static unsigned char valYDC[] =
    { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
	

	//	CbCr dc
	static unsigned char bitsCbCrDC[17] =
    { 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 };
	static unsigned char valCbCrDC[] =
    { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
	

	//	Y ac系数
	static unsigned char bitsYAC[17] =
    { 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d };
	static unsigned char valYAC[] =
    { 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 };
	

	//	CbCr ac
	static unsigned char bitsCbCrAC[17] =
    { 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 };
	static unsigned char valCbCrAC[] =
    { 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
	0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
	0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
	0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
	0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
	0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
	0x27, 0x28, 0x29, 0x2a, 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, 0x82, 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,
	0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
	0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
	0xf9, 0xfa };

	//	计算生成Huffman表
	ComputeHuffmanTable( bitsYDC, valYDC, &m_htblYDC );
	ComputeHuffmanTable( bitsYAC, valYAC, &m_htblYAC );

	ComputeHuffmanTable( bitsCbCrDC, valCbCrDC, &m_htblCbCrDC );
	ComputeHuffmanTable( bitsCbCrAC, valCbCrAC, &m_htblCbCrAC );
}

////////////////////////////////////////////////////////////////////////////////

//	计算生成Huffman表
void CompressEncode::ComputeHuffmanTable(
		unsigned char *	pBits, 
		unsigned char * pVal,
		HUFFMAN_TABLE * pTbl	)
{
	int p, i, l, lastp, si;
	char huffsize[257];
	unsigned int huffcode[257];
	unsigned int code;

	// First we copy bits and huffval
	memcpy( pTbl->bits,		pBits,	sizeof(pTbl->bits) );
	memcpy( pTbl->huffval,  pVal,	sizeof(pTbl->huffval) );
	
	/* Figure C.1: make table of Huffman code length for each symbol */
	/* Note that this is in code-length order. */
	
	p = 0;
	for (l = 1; l <= 16; l++) {
		for (i = 1; i <= (int) pBits[l]; i++)
			huffsize[p++] = (char) l;
	}
	huffsize[p] = 0;
	lastp = p;
	
	/* Figure C.2: generate the codes themselves */
	/* Note that this is in code-length order. */
	
	code = 0;
	si = huffsize[0];
	p = 0;
	while (huffsize[p]) {
		while (((int) huffsize[p]) == si) {
			huffcode[p++] = code;
			code++;
		}
		code <<= 1;
		si++;
	}
	
	/* Figure C.3: generate encoding tables */
	/* These are code and size indexed by symbol value */
	
	/* Set any codeless symbols to have code length 0;
	* this allows EmitBits to detect any attempt to emit such symbols.
	*/
	memset( pTbl->size, 0, sizeof( pTbl->size ) );
	
	for (p = 0; p < lastp; p++) {
		pTbl->code[ pVal[p] ] = huffcode[p];
		pTbl->size[ pVal[p] ] = huffsize[p];
	}
}

///////////////////////////////////////////////////////////////////////////////

//写入JPG头,soi, app0, Y_dqt, CbCr_dqt, sof, 4 * dht, sos.
void CompressEncode::WriteJpegHeader(void)
{
	write_soi();

	write_app0();

	write_dqt(0);//Y

	write_dqt(1);//cbcr

	write_sof(M_SOF0);

	write_dht(0, 0);//m_htblYDC
	write_dht(0, 1);//m_htblYAC
	write_dht(1, 0);//m_htblCbCrDC
	write_dht(1, 1);//m_htblCbCrAC

	write_sos();
}

///////////////////////////////////////////////////////////////////////////////

void CompressEncode::write_soi()
{
	emit_marker(M_SOI);
}

void CompressEncode::write_app0()
{
  
  
  emit_marker(M_APP0);
  
  emit_2bytes(2 + 4 + 1 + 2 + 1 + 2 + 2 + 1 + 1); /* length */

  emit_byte(0x4A);	/* Identifier: ASCII "JFIF" */
  emit_byte(0x46);
  emit_byte(0x49);
  emit_byte(0x46);
  emit_byte(0);

  
  emit_byte(1);		/* Major version */
  emit_byte(1);		/* Minor version */
  emit_byte(1); /* Pixel size information */
  emit_2bytes(300);
  emit_2bytes(300);
  emit_byte(0);		/* No thumbnail image */
  emit_byte(0);
}

void CompressEncode::write_dqt(int index)//0:Y;1:CbCr
{
	unsigned char* dqt;
	if( index == 0 )
		dqt = &m_dqtY[0];//changed from std with quality
	else
		dqt = &m_dqtCbCr[0];

	//only allow prec = 0;

	emit_marker(M_DQT);
	emit_2bytes(67);//length
	emit_byte(index);

	int i;
	unsigned char qval;
	for (i = 0; i < 64; i++) 
	{
        qval = (unsigned char) (dqt[jpeg_natural_order[i]]);
		emit_byte(qval);
    }
}


//currently support M_SOF0 baseline implementation
void CompressEncode::write_sof(int code)
{
	emit_marker(code);
	emit_2bytes(17); //length

	emit_byte(8);//cinfo->data_precision);
	emit_2bytes(m_nHeight);
	emit_2bytes(m_nWidth);
	emit_byte(3);//cinfo->num_components);

	//for Y
	emit_byte(1);//compptr->component_id);
	emit_byte(34);//(compptr->h_samp_factor << 4) + compptr->v_samp_factor);
	emit_byte(0);//quant_tbl_no

	//for Cb
	emit_byte(2);//compptr->component_id);
	emit_byte(17);//(compptr->h_samp_factor << 4) + compptr->v_samp_factor);
	emit_byte(1);//quant_tbl_no

	//for Cr
	emit_byte(3);//compptr->component_id);
	emit_byte(17);//(compptr->h_samp_factor << 4) + compptr->v_samp_factor);
	emit_byte(1);//quant_tbl_no
}

void CompressEncode::write_dht(int IsCbCr, int IsAc)
{
	HUFFMAN_TABLE *htbl;
	int index;
	if( IsCbCr )
	{
		if( IsAc )
		{
			htbl = &m_htblCbCrAC;
			index = 17;
		}
		else
		{
			htbl = &m_htblCbCrDC;
			index = 1;
		}
	}
	else
	{
		if( IsAc )
		{
			htbl = &m_htblYAC;
			index = 16;
		}
		else
		{
			htbl = &m_htblYDC;
			index = 0;
		}
	}

	emit_marker(M_DHT);

	int i, length = 0;
    for (i = 1; i <= 16; i++)
		length += htbl->bits[i];
	
	emit_2bytes(length + 2 + 1 + 16);
	
    emit_byte(index);

	for (i = 1; i <= 16; i++)
		emit_byte(htbl->bits[i]);
    
    for (i = 0; i < length; i++)//varible-length
		emit_byte(htbl->huffval[i]);    
}

void CompressEncode::write_sos()
{
	emit_marker(M_SOS);

	int length = 2 * 3 + 2 + 1 + 3;
	emit_2bytes(length);

	emit_byte(3);//cinfo->comps_in_scan

	//Y
	emit_byte(1);//index
	emit_byte(0);//dc and ac tbl use 0-th tbl

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -