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

📄 minijpegenc.cpp

📁 About JPEG, executable on Visual C++
💻 CPP
📖 第 1 页 / 共 3 页
字号:
	*/
	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];
	}
}

////////////////////////////////////////////////////////////////////////////////
//	CMiniJpegEncoder::CompressImage(), the main function in this class !!
//	Don't ask me its purpose, parameter lists, and return value,       d:-)

bool CMiniJpegEncoder::CompressImage(	
	 unsigned char *pInBuf,	//source data, bgr format, 3 bytes per pixel
	 unsigned char *pOutBuf,//destination buffer, in jpg format
	 int nWidthPix,			//image width in pixels
	 int nHeight,			//height
	 int& nOutputBytes		//return number of bytes being written
	 )
{
	//	Error handling
	if(( pInBuf == 0 )||( pOutBuf == 0 ))
		return false;

	m_nWidth = nWidthPix;
	m_nHeight = nHeight;

	//	image width and height, 4 bytes
	memcpy ( pOutBuf, & m_nWidth, 2 );
	pOutBuf += 2;
	memcpy ( pOutBuf, & m_nHeight, 2 );
	pOutBuf += 2;

	//	Write quality factor, 2 byte
	memcpy ( pOutBuf, & m_nQuality, 2 );
	pOutBuf += 2;

	//	let pOutBuf rewind to the first byte of output buffer
	pOutBuf -= 6;
	nOutputBytes = 6;
	
	int nRowBytes = ( m_nWidth * 3 + 3 ) / 4 * 4;		

	if(( nWidthPix <= 0 )||( nRowBytes <= 0 )||( nHeight <= 0 ))
		return false;

	//	declares
	int xPixel, yPixel, xTile, yTile, cxTile, cyTile, cxBlock, cyBlock;
	int x, y, nTrueRows, nTrueCols, nTileBytes;
	unsigned char byTile[768], *pTileRow, *pLastPixel, *pHolePixel;
		
	//	horizontal and vertical count of tile, macroblocks, 
	//	or MCU(Minimum Coded Unit), in 16*16 pixels
	cxTile = (nWidthPix + 15)>> 4;	
	cyTile = (nHeight + 15)	>> 4;

	//	horizontal and vertical count of block, in 8*8 pixels
	cxBlock = cxTile << 1;
	cyBlock = cyTile << 1;

	//	first set output bytes as zero
	nTileBytes = 0;

	//	three dc values set to zero, needed for compressing one new image
	m_dcY = m_dcCb = m_dcCr = 0;

	//	Initialize size (in bits) and value to be written out
	m_nPutBits = 0;
	m_nPutVal = 0;

	//	Run all the tiles, or macroblocks, or MCUs
	for( yTile = 0; yTile < cyTile; yTile++ )
	{
		for( xTile = 0; xTile < cxTile; xTile++ )
		{
			//	Get tile starting pixel position
			xPixel = xTile << 4;
			yPixel = yTile << 4;

			//	Get the true number of tile columns and rows
			nTrueRows = 16;
			nTrueCols = 16;			
			if( yPixel + nTrueRows > nHeight )
				nTrueRows = nHeight - yPixel;
			if( xPixel + nTrueCols > nWidthPix )
				nTrueCols = nWidthPix - xPixel;

			//	Prepare pointer to one row of this tile
			pTileRow = pInBuf + (yPixel-1) * nRowBytes + xPixel * 3;

			//	Get tile data from pInBuf into byTile. If not full, padding 
			//	byTile with the bottom row and rightest pixel
			for( y = 0; y < 16; y ++ )
			{
				if( y < nTrueRows )
				{	
					//	Get data of one row
					pTileRow += nRowBytes;					
					memcpy( byTile + y * 16 * 3, pTileRow, nTrueCols * 3 );
					
					//	padding to full tile with the rightest pixel
					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
				{
					//	padding the hole rows with the bottom row
					memcpy( byTile + y * 16 * 3, 
							byTile + (nTrueRows - 1) * 16 * 3,
							16 * 3 );
				}
			}
		
			//	Compress this full tile with jpeg algorithm here !!!!!
			//	The compressed data length for this tile is return by nTileBytes
			if( ! CompressOneTile(	byTile, 
									pOutBuf + nOutputBytes, 
									nTileBytes ))
				return false;
			nOutputBytes += nTileBytes;
		}
	}
	
	//	Maybe there are some bits left, send them here
	if( m_nPutBits > 0 )
	{
		EmitLeftBits( pOutBuf + nOutputBytes, nTileBytes );
		nOutputBytes += nTileBytes;
	}
	return true;
}

////////////////////////////////////////////////////////////////////////////////
//	function Purpose:	compress one 16*16 pixels with jpeg

bool CMiniJpegEncoder::CompressOneTile(	
	unsigned char * pBgr,	//source data, in BGR format
	unsigned char * pJpg,	//destination, in jpg format
	int& nTileBytes			//return value, the length of compressed data
	)
{
	//	Three color components, 256 + 64 + 64 elements 
	int pYCbCr[384];

	//	The DCT outputs are returned scaled up by a factor of 8;
	//	they therefore have a range of +-8K for 8-bit source data 
	int coef[64];	

	//	Initialize to zero
	nTileBytes = 0;

	//	Color conversion and subsampling
	//	pY data is in block order, e.g. 
	//	block 0 is from pY[0] to pY[63], block 1 is from pY[64] to pY[127]
	BGRToYCbCrEx( pBgr, pYCbCr );

	//	Do Y/Cb/Cr components, Y: 4 blocks; Cb: 1 block; Cr: 1 block
	int i, nBytes;
	for( i=0; i<6; i++ )
	{
		ForwardDct( pYCbCr + i*64, coef );
		
		Quantize( coef, i );	//coef is both in and out
		
		HuffmanEncode( coef, pJpg + nTileBytes, i, nBytes );
		nTileBytes += nBytes;
	}

	return true;
}


////////////////////////////////////////////////////////////////////////////////
//	Color convertion from bgr to ycbcr for one tile, 16*16 pixels
//	Actually being not used for efficiency !!!!! Please use BGRToYCbCrEx()

void CMiniJpegEncoder::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);
	}
}

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

//	(1) Color convertion from bgr to ycbcr for one tile, 16*16 pixels;
//	(2) Y has 4 blocks, with block 0 from pY[0] to pY[63], 
//		block 1 from pY[64] to pY[127], block 2 from pY[128] to pY[191], ...
//	(3) With Cb/Cr subsampling, i.e. 2*2 pixels get one Cb and one Cr
//		IJG use average for better performance; we just pick one from four
//	(4) Do unsigned->signed conversion, i.e. substract 128 

void CMiniJpegEncoder::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;
			}
		}
	}
}

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

/************************************************************************** 
 * (1)	Direct dct algorithms:
 *	are also available, but they are much more complex and seem not to 
 *  be any faster when reduced to code.
 *
 *************************************************************************
 * (2)  LL&M dct algorithm:
 *	This implementation is based on an algorithm described in
 *  C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT
 *  Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics,
 *  Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991.
 *	The primary algorithm described there uses 11 multiplies and 29 adds.
 *	We use their alternate method with 12 multiplies and 32 adds.
 *
 ***************************************************************************
 * (3)	AA&N DCT algorithm:
 * This implementation is based on Arai, Agui, and Nakajima's algorithm for
 * scaled DCT.  Their original paper (Trans. IEICE E-71(11):1095) is in
 * Japanese, but the algorithm is described in the Pennebaker & Mitchell
 * JPEG textbook (see REFERENCES section in file README).  The following 
 * code is based directly on figure 4-8 in P&M.
 *
 * The AA&N method needs only 5 multiplies and 29 adds. 
 *
 * The primary disadvantage of this method is that with fixed-point math,
 * accuracy is lost due to imprecise representation of the scaled
 * quantization values.  The smaller the quantization table entry, the less
 * precise the scaled value, so this implementation does worse with high-
 * quality-setting files than with low-quality ones.
 ***************************************************************************
 */

//	AA&N DCT algorithm implemention


void CMiniJpegEncoder::ForwardDct( 
		int* data,	//source data, length is 64 
		int* coef	//output dct coefficients
		)
{

////////////////////////////////////////////////////////////////////////////
//	define some macroes 
	
//	Scale up the float with 1<<8; so (int)(0.382683433 * 1<<8 ) = 98
#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) */
	
//	This macro changes float multiply into int multiply and right-shift
//	MULTIPLY(a, FIX_0_707106781) = (short)( 0.707106781 * a )
#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 */

⌨️ 快捷键说明

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