📄 minijpegenc.cpp
字号:
*/
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 + -