//jpeg转bmp的原理很简单,用ipciture读入jpg图像,然后在成bmp的,由于在vc 6.0里面可以自动存储的格式只有两种:bmp和ico,由此的来
void JpegToBmp(const char *resourcepath,const char *destnatepath)
{
IPicture *m_picture;
CFile file(resourcepath,CFile::modeRead);
DWORD m_filelen=file.GetLength();
HGLOBAL hglobal=GlobalAlloc(GMEM_MOVEABLE,m_filelen);
LPVOID pdata=NULL;
pdata=GlobalLock(hglobal);
file.ReadHuge(pdata,m_filelen);
IStream *m_stream;
GlobalUnlock(hglobal);
file.Close();
CreateStreamOnHGlobal(hglobal,TRUE,&m_stream);
OleLoadPicture(m_stream,m_filelen,TRUE,IID_IPicture,(LPVOID*)&m_picture);
LONG size;
m_picture->SaveAsFile(m_stream,TRUE,&size);
char pathbuf[1024];
CFile iconfile;
iconfile.Open(destnatepath,CFile::modeCreate|CFile::modeWrite);
LARGE_INTEGER li;
li.HighPart = 0;
li.LowPart = 0;
ULARGE_INTEGER ulnewpos;
m_stream->Seek(li,STREAM_SEEK_SET,&ulnewpos);
ULONG uReadCount = 1;
while(uReadCount>0)
{
m_stream->Read(pathbuf,sizeof(pathbuf),&uReadCount);
if(uReadCount>0)
iconfile.Write(pathbuf,uReadCount);
}
GlobalFree(hglobal);
m_stream->Release();
m_stream=NULL;
m_picture->Release();
}
bmp转jpg的麻烦一点儿,因为jpg需要复杂的解压,从网上download了一个,可用主要是通过两个类实现:
/* These two fields directly represent the contents of a JPEG DHT marker */
unsigned char bits[17]; /* bits[k] = # of symbols with codes of */
/* length k bits; bits[0] is unused */
unsigned char huffval[256]; /* The symbols, in order of incr code length */
/* This field is used only during compression. It's initialized FALSE when
* the table is created, and set TRUE when it's been output to the file.
* You could suppress output of a table by setting this to TRUE.
* (See jpeg_suppress_tables for an example.)*/
}HUFFMAN_TABLE;
class CCompressEncode
{
public:
CCompressEncode();
virtual ~CCompressEncode();
CCompressEncode( int nQuality );
bool 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
);
////////////////////////////////////////////////////////////////////////////
// Following data members should be computed in initialization
unsigned short m_nQuality, m_nScale;
//RGB转化YCbCr颜色对应表
int m_RToY[256], m_GToY[256], m_BToY[256];
int m_RToCb[256], m_GToCb[256], m_BToCb[256];
int m_RToCr[256], m_GToCr[256], m_BToCr[256];
// To speed up, we precompute two DCT quant tables
unsigned short m_qtblY[64], m_qtblCbCr[64];
//用来写入JPG文件头
unsigned char m_dqtY[64], m_dqtCbCr[64];
HUFFMAN_TABLE m_htblYDC, m_htblYAC, m_htblCbCrDC, m_htblCbCrAC;
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
// Following are should be initialized for compressing every image
unsigned short m_nWidth, m_nHeight;
// Three dc records, used for dc differentize for Y/Cb/Cr
int m_dcY, m_dcCb, m_dcCr;
// The size (in bits) and value (in 4 byte buffer) to be written out
int m_nPutBits, m_nPutVal;
unsigned char *m_pOutBuf;
////////////////////////////////////////////////////////////////////////////
private:
void InitEncoder( void );
void InitColorTable( void );
void InitQuantTable( void );
void ScaleQuantTable(
unsigned short* tblRst,
unsigned char* tblStd,
unsigned short* tblAan
);
void ScaleTable(unsigned char* tbl, int scale, int max);
void InitHuffmanTable( void );
void ComputeHuffmanTable(
unsigned char * pBits,
unsigned char * pVal,
HUFFMAN_TABLE * pTbl
);
bool CompressOneTile(
unsigned char * pBgr //source data, in BGR format
);
void 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
);
void BGRToYCbCrEx(
unsigned char * pBgr, //in, tile data, in BGR format, 768 bytes
int * pBlock //out, Y: 256; Cb: 64; Cr: 64
);
void ForwardDct(
int* data, //source data, length is 64
int* coef //output dct coefficients
);
void Quantize(
int* coef, //coef is both in and out
int iBlock //block id; Y: 0,1,2,3; Cb: 4; Cr: 5
);
bool HuffmanEncode(
int* pCoef, // DCT coefficients
int iBlock // 0,1,2,3:Y; 4:Cb; 5:Cr;
);
bool EmitBits(
unsigned int code, //Huffman code
int size //Size in bits of the Huffman code
);
void EmitLeftBits(void);
void WriteJpegHeader(void);
void write_sos(void);
void write_sof(int code);
void write_app0(void);
void write_soi(void);
void write_dht(int IsCbCr, int IsAc);
void write_dqt(int index);
};
#endif // !defined(AFX_COMPRESSENCODE_H__0EF37988_FDDE_4229_9EF1_CA5B1E51BEFF__INCLUDED_)
class PictureOperate
{
public:
PictureOperate();
~PictureOperate();
//加载位图
BOOL Load( const char * );
//进行编码压缩并且保存文件
void picCompressEncode(CString filename, BOOL color, int quality);
UINT m_width, m_height, m_rowbytes;
private:
DWORD m_dwDibSize;
unsigned char *m_pDib, *m_pDibBits;
BITMAPINFOHEADER *m_pBIH;
CPalette m_Palette;
RGBQUAD *m_pPalette;
int m_nPaletteEntries;
};
#endif
CFile cf;
// Attempt to open the Dib file for reading.
if( !cf.Open( pszFilename, CFile::modeRead ) )
return( FALSE );
// Get the size of the file and store
// in a local variable. Subtract the
// size of the BITMAPFILEHEADER structure
// since we won't keep that in memory.
DWORD dwDibSize;
dwDibSize =
cf.GetLength() - sizeof( BITMAPFILEHEADER );
// Attempt to allocate the Dib memory.
unsigned char *pDib;
pDib = new unsigned char [dwDibSize];
if( pDib == NULL )
return( FALSE );
BITMAPFILEHEADER BFH;
// Read in the Dib header and data.
try{
// Did we read in the entire BITMAPFILEHEADER?
if( cf.Read( &BFH, sizeof( BITMAPFILEHEADER ) )
!= sizeof( BITMAPFILEHEADER ) ||
// Is the type 'MB'?
BFH.bfType != 'MB' ||
// Did we read in the remaining data?
cf.Read( pDib, dwDibSize ) != dwDibSize ){
// Delete the memory if we had any
// errors and return FALSE.
delete [] pDib;
return( FALSE );
}
}
// If we catch an exception, delete the
// exception, the temporary Dib memory,
// and return FALSE.
catch( CFileException *e ){
e->Delete();
delete [] pDib;
return( FALSE );
}
// If we got to this point, the Dib has been
// loaded. If a Dib was already loaded into
// this class, we must now delete it.
if( m_pDib != NULL )
delete m_pDib;
// Store the local Dib data pointer and
// Dib size variables in the class member
// variables.
m_pDib = pDib;
m_dwDibSize = dwDibSize;
// Pointer our BITMAPINFOHEADER and RGBQUAD
// variables to the correct place in the Dib data.
m_pBIH = (BITMAPINFOHEADER *) m_pDib;
m_pPalette =
(RGBQUAD *) &m_pDib[sizeof(BITMAPINFOHEADER)];
// get image width and height
m_width = m_pBIH->biWidth;
m_height = m_pBIH->biHeight;
// Calculate the number of palette entries.
m_nPaletteEntries = 1 << m_pBIH->biBitCount;
if( m_pBIH->biBitCount > 8 )
m_nPaletteEntries = 0;
else if( m_pBIH->biClrUsed != 0 )
m_nPaletteEntries = m_pBIH->biClrUsed;
// Point m_pDibBits to the actual Dib bits data.
m_pDibBits =
&m_pDib[sizeof(BITMAPINFOHEADER)+
m_nPaletteEntries*sizeof(RGBQUAD)];
// If we have a valid palette, delete it.
if( m_Palette.GetSafeHandle() != NULL )
m_Palette.DeleteObject();
// If there are palette entries, we'll need
// to create a LOGPALETTE then create the
// CPalette palette.
if( m_nPaletteEntries != 0 ){
// Allocate the LOGPALETTE structure.
LOGPALETTE *pLogPal = (LOGPALETTE *) new char
[sizeof(LOGPALETTE)+
m_nPaletteEntries*sizeof(PALETTEENTRY)];
if( pLogPal != NULL ){
// Set the LOGPALETTE to version 0x300
// and store the number of palette
// entries.
pLogPal->palVersion = 0x300;
pLogPal->palNumEntries = m_nPaletteEntries;
// Store the RGB values into each
// PALETTEENTRY element.
for( int i=0; i<m_nPaletteEntries; i++){
pLogPal->palPalEntry[i].peRed =
m_pPalette[i].rgbRed;
pLogPal->palPalEntry[i].peGreen =
m_pPalette[i].rgbGreen;
pLogPal->palPalEntry[i].peBlue =
m_pPalette[i].rgbBlue;
}
// Create the CPalette object and
// delete the LOGPALETTE memory.
m_Palette.CreatePalette( pLogPal );
delete [] pLogPal;
}
}
return( TRUE );
}
///////////////////////////////////////////////////////////////////////////////
//对位图进行基于DCT的压缩编码,并且保存为JPG文件
void PictureOperate::picCompressEncode(CString filename, BOOL color, int quality)
{
//压缩后的字节数
int nOutputBytes = 0;
unsigned char *pJpg;
pJpg = new unsigned char [m_dwDibSize];
LARGE_INTEGER iLarge;
QueryPerformanceFrequency( &iLarge );
double dbFreq = (double) iLarge.QuadPart;
//获得起始时间
QueryPerformanceCounter( &iLarge );
double dbBegin = (double) iLarge.QuadPart;
/////////////////////////////////////////////////////
//quality为压缩质量
CCompressEncode encoder( quality );
encoder.CompressImage( m_pDibBits, pJpg,
m_pBIH->biWidth, m_pBIH->biHeight, nOutputBytes );
//////////////////////////////////////////////////////
//获得压缩结束后时间
QueryPerformanceCounter( &iLarge );
double dbEnd = (double) iLarge.QuadPart;
int nms = (int) (( dbEnd - dbBegin ) * 1000.0 / dbFreq );
float ratio = (float) m_dwDibSize / nOutputBytes;
CString str;
//输出压缩后信息
str.Format( "压缩后字节数 = %d, 压缩比 = %f, 耗时 = %d ",
nOutputBytes, ratio, nms );
AfxMessageBox( str );
//保存JPG文件
CFile cf;
if( !cf.Open( filename, CFile::modeCreate | CFile::modeWrite ) )
{
AfxMessageBox("Can not create jpg file!");
return;
}
cf.Write( pJpg, nOutputBytes );
delete []pJpg;
}
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;
//////////////////////////////////////////////////////////////////////
CCompressEncode::CCompressEncode()
{
m_nQuality = 50;
InitEncoder( );
}
CCompressEncode::CCompressEncode(int nQuality)
{
m_nQuality = nQuality;
InitEncoder( );
}
CCompressEncode::~CCompressEncode()
{
}
//////////////////////////////////////////////////////////////////////////
//初始化颜色转化表、量化表、Huffman表
void CCompressEncode::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 CCompressEncode::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 CCompressEncode::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 CCompressEncode::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 CCompressEncode::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 CCompressEncode::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 CCompressEncode::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 CCompressEncode::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 CCompressEncode::write_soi()
{
emit_marker(M_SOI);
}
void CCompressEncode::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 CCompressEncode::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 CCompressEncode::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 CCompressEncode::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 CCompressEncode::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
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//对图像进行压缩编码的主函数
bool CCompressEncode::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 CCompressEncode::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 CCompressEncode::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 CCompressEncode::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 CCompressEncode::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 CCompressEncode::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 CCompressEncode::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 CCompressEncode::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 CCompressEncode::EmitLeftBits(void)
{
if (! EmitBits(0x7F, 7)) /* fill 7 bits with ones */
return;
m_nPutVal = 0;
m_nPutBits = 0;
}
////////////////////////////////////////////////////////////////////////////////
CompressEncode.h
CompressEncode.cpp
PicOperate.h
PicOperate.cpp
使用规则:
char *bmppath="1.bmp";
CString jpgpath="2.jpg";
int qui=30;
m_op.Load( bmppath);
m_op.picCompressEncode(jpgpath,TRUE,qui);
哈哈