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

📄 tonyjpegencoder.cpp

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

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

//write soi, app0, Y_dqt, CbCr_dqt, sof, 4 * dht, sos.
void CTonyJpegEncoder::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 CTonyJpegEncoder::write_soi()
{
	emit_marker(M_SOI);
}

void CTonyJpegEncoder::write_app0()
{
  /*
   * Length of APP0 block	(2 bytes)
   * Block ID			(4 bytes - ASCII "JFIF")
   * Zero byte			(1 byte to terminate the ID string)
   * Version Major, Minor	(2 bytes - 0x01, 0x01)
   * Units			(1 byte - 0x00 = none, 0x01 = inch, 0x02 = cm)
   * Xdpu			(2 bytes - dots per unit horizontal)
   * Ydpu			(2 bytes - dots per unit vertical)
   * Thumbnail X size		(1 byte)
   * Thumbnail Y size		(1 byte)
   */
  
  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);

  /* We currently emit version code 1.01 since we use no 1.02 features.
   * This may avoid complaints from some older decoders.
   */
  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 CTonyJpegEncoder::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 CTonyJpegEncoder::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 CTonyJpegEncoder::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 CTonyJpegEncoder::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

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




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

bool CTonyJpegEncoder::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;
	m_pOutBuf = pOutBuf;

	//write soi, app0, Y_dqt, CbCr_dqt, sof, 4 * dht, sos.
	WriteJpegHeader();

	//	let pOutBuf rewind to the first byte of output buffer
	int nHeadBytes = m_pOutBuf - pOutBuf;//here being equal to header size

	// bmp row bytes
	int nRowBytes = ( m_nWidth * 3 + 3 ) / 4 * 4;		

	// exception
	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
	//	Vertically flip image data
	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
			//	Vert-flip here !!!
			pTileRow = pInBuf + (m_nHeight - yPixel) * 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 ))
				return false;			
		}
	}
	
	//	Maybe there are some bits left, send them here
	if( m_nPutBits > 0 )
	{
		EmitLeftBits( );
	}

	// write EOI; end of Image
	emit_marker(M_EOI);
	nOutputBytes = m_pOutBuf - pOutBuf;
	return true;
}

////////////////////////////////////////////////////////////////////////////////
//	function Purpose:	compress one 16*16 pixels with jpeg
//	destination is m_pOutBuf, in jpg format

bool CTonyJpegEncoder::CompressOneTile(	
	unsigned char * pBgr	//source data, in BGR format
	)
{
	//	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];	

	//	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;
	for( i=0; i<6; i++ )
	{
		ForwardDct( pYCbCr + i*64, coef );
		
		Quantize( coef, i );	//coef is both in and out
		
		HuffmanEncode( coef, i );//output into m_pOutBuf	
	}

	return true;
}


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

void CTonyJpegEncoder::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 CTonyJpegEncoder::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

⌨️ 快捷键说明

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