www.pudn.com > Jpeg.rar > Jpeg.cpp


// Jpeg.cpp: implementation of the CJpeg class. 
// 
////////////////////////////////////////////////////////////////////// 
 
#include "stdafx.h" 
#include  
 
#include "Jpeg.h" 
 
#ifdef __cplusplus 
	extern "C" { 
#endif // __cplusplus 
 
#include "jpeglib.h" 
 
#ifdef __cplusplus 
	} 
#endif // __cplusplus 
 
// 
// 
// 
 
/* 
 *  is used for the optional error recovery mechanism shown in 
 * the second part of the example. 
 */ 
 
#include  
 
#ifdef _DEBUG 
#undef THIS_FILE 
static char THIS_FILE[]=__FILE__; 
#define new DEBUG_NEW 
#endif 
 
// error handler, to avoid those pesky exit(0)'s 
 
struct my_error_mgr { 
  struct jpeg_error_mgr pub;	/* "public" fields */ 
 
  jmp_buf setjmp_buffer;	/* for return to caller */ 
}; 
 
typedef struct my_error_mgr * my_error_ptr; 
 
// 
// 
// 
 
METHODDEF(void) my_error_exit (j_common_ptr cinfo); 
 
// 
//	to handle fatal errors. 
//	the original JPEG code will just exit(0). can't really 
//	do that in Windows.... 
// 
 
METHODDEF(void) my_error_exit (j_common_ptr cinfo) 
{ 
	/* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ 
	my_error_ptr myerr = (my_error_ptr) cinfo->err; 
 
	char buffer[JMSG_LENGTH_MAX]; 
 
	/* Create the message */ 
	(*cinfo->err->format_message) (cinfo, buffer); 
 
	/* Always display the message. */ 
	MessageBox(GetActiveWindow(),buffer,"JPEG Fatal Error",MB_ICONSTOP); 
 
 
	/* Return control to the setjmp point */ 
	longjmp(myerr->setjmp_buffer, 1); 
} 
 
// store a scanline to our data buffer 
void j_putRGBScanline(BYTE *jpegline,  
						 int widthPix, 
						 BYTE *outBuf, 
						 int row); 
 
void j_putGrayScanlineToRGB(BYTE *jpegline,  
						 int widthPix, 
						 BYTE *outBuf, 
						 int row); 
 
////////////////////////////////////////////////////////////////////// 
// Construction/Destruction 
////////////////////////////////////////////////////////////////////// 
 
CJpeg::CJpeg() 
{ 
	m_strJPEGError = "No Error"; // yet 
	m_pDib = NULL; 
} 
 
CJpeg::CJpeg(CDib *pDib) 
{ 
	m_strJPEGError = "No Error"; // yet 
	m_pDib = NULL; 
	SetDib(pDib); 
} 
 
CJpeg::~CJpeg() 
{ 
	if (m_pDib != NULL) 
		delete m_pDib; 
} 
 
// free allocate memory 
void CJpeg::FreeBuffer(BYTE *Buffer) 
{ 
	delete[] Buffer; 
} 
 
// get error string 
CString CJpeg::GetErrorString() 
{ 
	return m_strJPEGError; 
} 
 
// load gif file 
BOOL CJpeg::Load(LPCSTR lpstrFileName) 
{ 
	UINT uWidth, uHeight, uWidthDW; 
 
	// read the GIF to a packed buffer of RGB bytes 
	BYTE *lpTmpBuffer = ReadJPEGFile(lpstrFileName, &uWidth, &uHeight); 
	if (lpTmpBuffer == NULL) 
		return FALSE; 
 
	// do this before DWORD-alignment!!! 
	// swap red and blue for display 
	BGRFromRGB(lpTmpBuffer, uWidth, uHeight); 
 
	// now DWORD-align for display 
	BYTE *lpBuffer = MakeDwordAlign(lpTmpBuffer, uWidth, uHeight, &uWidthDW); 
	FreeBuffer(lpTmpBuffer); 
 
	// flip for display 
	VertFlipBuf(lpBuffer, uWidthDW, uHeight); 
 
	BITMAPINFOHEADER bmiHeader; 
	bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 
	bmiHeader.biWidth = uWidth; 
	bmiHeader.biHeight = uHeight; 
	bmiHeader.biPlanes = 1; 
	bmiHeader.biBitCount = 24; 
	bmiHeader.biCompression = BI_RGB; 
	bmiHeader.biSizeImage = 0; 
	bmiHeader.biXPelsPerMeter = 0; 
	bmiHeader.biYPelsPerMeter = 0; 
	bmiHeader.biClrUsed = 0; 
	bmiHeader.biClrImportant = 0; 
 
    // Allocate enough memory for the new CF_DIB, and copy bits  
	DWORD dwHeaderSize = sizeof(BITMAPINFOHEADER); 
	DWORD dwBitsSize = WIDTHBYTES(uWidth*24) * uHeight; 
    HDIB hDIB = GlobalAlloc(GHND, dwHeaderSize + dwBitsSize);  
	if (hDIB == NULL) 
		return FALSE; 
 
    LPBYTE lpDIB = (LPBYTE)GlobalLock(hDIB);  
    memcpy(lpDIB, (LPBYTE)&bmiHeader, dwHeaderSize);  
    memcpy(FindDIBBits((LPBYTE)lpDIB), lpBuffer, dwBitsSize);  
	FreeBuffer(lpBuffer); 
 
	if (m_pDib != NULL) 
		delete m_pDib; 
 
	m_pDib = new CDib(); 
	m_pDib->Attach(hDIB); 
 
	return TRUE; 
} 
 
// save Jpeg file 
BOOL CJpeg::Save(LPCSTR lpstrFileName, CDib* pDib, BOOL bColor, int nQuality) 
{ 
	if (pDib == NULL) 
		pDib = m_pDib; 
	if (pDib == NULL) 
		return FALSE; 
 
	HDIB hDib = CopyHandle(pDib->GetHandle()); 
	if (hDib == NULL) 
		return FALSE; 
 
	CDib* pDibTmp = new CDib; 
	pDibTmp->Attach(hDib); 
 
	if (pDibTmp->GetBitCount() != 24) 
		pDibTmp->ConvertFormat(24); 
 
	UINT uWidth  = pDibTmp->GetWidth(); 
	UINT uHeight = pDibTmp->GetHeight(); 
 
	// convert from DIB format (DWORD aligned, vertically flipped, red and blue swapped) 
	BYTE* tmp = ClearDwordAlign(pDibTmp->GetBitsPtr(), 
									uWidth, 
									WIDTHBYTES(uWidth * 24), 
									uHeight); 
	if (tmp == NULL) 
		return FALSE; 
 
	// convert from DIB 
	VertFlipBuf(tmp, uWidth*3, uHeight); 
 
	BGRFromRGB(tmp, uWidth, uHeight); 
 
	BOOL bSuccess = WriteJPEGFile(lpstrFileName, 
							tmp, 
							uWidth,  
							uHeight, 
							bColor, 
							nQuality); 
 
	delete pDibTmp; 
	FreeBuffer(tmp); 
 
	return bSuccess; 
} 
 
// 
// copies BYTE buffer into DWORD-aligned BYTE buffer 
// return addr of new buffer 
// 
BYTE * CJpeg::MakeDwordAlign(BYTE *dataBuf, 
								 UINT widthPix,				// pixels!! 
								 UINT height, 
								 UINT *uiOutWidthBytes)		// bytes!!! 
{ 
	//////////////////////////////////////////////////////////// 
	// what's going on here? this certainly means trouble  
	if (dataBuf==NULL) 
		return NULL; 
 
	//////////////////////////////////////////////////////////// 
	// how big is the smallest DWORD-aligned buffer that we can use? 
	UINT uiWidthBytes; 
	uiWidthBytes = WIDTHBYTES(widthPix * 24); 
 
	DWORD dwNewsize=(DWORD)((DWORD)uiWidthBytes *  
							(DWORD)height); 
	BYTE *pNew; 
 
	//////////////////////////////////////////////////////////// 
	// alloc and open our new buffer 
	pNew=(BYTE *)new BYTE[dwNewsize]; 
	if (pNew==NULL) { 
		return NULL; 
	} 
	 
	//////////////////////////////////////////////////////////// 
	// copy row-by-row 
	UINT uiInWidthBytes = widthPix * 3; 
	UINT uiCount; 
	for (uiCount=0;uiCount < height;uiCount++)  
	{ 
		BYTE * bpInAdd; 
		BYTE * bpOutAdd; 
		ULONG lInOff; 
		ULONG lOutOff; 
 
		lInOff=uiInWidthBytes * uiCount; 
		lOutOff=uiWidthBytes * uiCount; 
 
		bpInAdd= dataBuf + lInOff; 
		bpOutAdd= pNew + lOutOff; 
 
		memcpy(bpOutAdd,bpInAdd,uiInWidthBytes); 
	} 
 
	*uiOutWidthBytes=uiWidthBytes; 
	return pNew; 
} 
 
// 
//	vertically flip a buffer  
//	note, this operates on a buffer of widthBytes bytes, not pixels!!! 
// 
BOOL CJpeg::VertFlipBuf(BYTE* inbuf, UINT widthBytes, UINT height) 
{    
	BYTE  *tb1; 
	BYTE  *tb2; 
 
	if (inbuf==NULL) 
		return FALSE; 
 
	UINT bufsize; 
 
	bufsize=widthBytes; 
 
	tb1= (BYTE *)new BYTE[bufsize]; 
	if (tb1==NULL)  
	{ 
		return FALSE; 
	} 
 
	tb2= (BYTE *)new BYTE [bufsize]; 
	if (tb1==NULL)  
	{ 
		return FALSE; 
	} 
	 
	UINT row_cnt;      
	ULONG off1=0; 
	ULONG off2=0; 
 
	for (row_cnt=0;row_cnt<(height+1)/2;row_cnt++)  
	{ 
		off1=row_cnt*bufsize; 
		off2=((height-1)-row_cnt)*bufsize;    
		 
		memcpy(tb1,inbuf+off1,bufsize); 
		memcpy(tb2,inbuf+off2,bufsize);	 
		memcpy(inbuf+off1,tb2,bufsize); 
		memcpy(inbuf+off2,tb1,bufsize); 
	}	 
 
	delete [] tb1; 
	delete [] tb2; 
 
	return TRUE; 
}         
 
// 
//	swap Rs and Bs 
// 
//	Note! this does its stuff on buffers with a whole number of pixels 
//	per data row!! 
// 
BOOL CJpeg::BGRFromRGB(BYTE *buf, UINT widthPix, UINT height) 
{ 
	if (buf==NULL) 
		return FALSE; 
 
	UINT col, row; 
	for (row=0;rowalloc_sarray) 
		((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); 
 
	/* Step 6: while (scan lines remain to be read) */ 
	/*           jpeg_read_scanlines(...); */ 
 
	/* Here we use the library's state variable cinfo.output_scanline as the 
	* loop counter, so that we don't have to keep track ourselves. 
	*/ 
	while (cinfo.output_scanline < cinfo.output_height)  
	{ 
		/* jpeg_read_scanlines expects an array of pointers to scanlines. 
		 * Here the array is only one element long, but you could ask for 
		 * more than one scanline at a time if that's more convenient. 
		 */ 
		(void) jpeg_read_scanlines(&cinfo, buffer, 1); 
		/* Assume put_scanline_someplace wants a pointer and sample count. */ 
 
		// asuumer all 3-components are RGBs 
		if (cinfo.out_color_components==3)  
		{ 
			 
			j_putRGBScanline(buffer[0],  
							*uWidth, 
							dataBuf, 
							cinfo.output_scanline-1); 
 
		}  
		else if (cinfo.out_color_components==1)  
		{ 
 
			// assume all single component images are grayscale 
			j_putGrayScanlineToRGB(buffer[0],  
								*uWidth, 
								dataBuf, 
								cinfo.output_scanline-1); 
 
		} 
 
	} 
 
	/* Step 7: Finish decompression */ 
 
	(void) jpeg_finish_decompress(&cinfo); 
	/* We can ignore the return value since suspension is not possible 
	* with the stdio data source. 
	*/ 
 
	/* Step 8: Release JPEG decompression object */ 
 
	/* This is an important step since it will release a good deal of memory. */ 
	jpeg_destroy_decompress(&cinfo); 
 
	/* After finish_decompress, we can close the input file. 
	* Here we postpone it until after no more JPEG errors are possible, 
	* so as to simplify the setjmp error logic above.  (Actually, I don't 
	* think that jpeg_destroy can do an error exit, but why assume anything...) 
	*/ 
	fclose(infile); 
 
	/* At this point you may want to check to see whether any corrupt-data 
	* warnings occurred (test whether jerr.pub.num_warnings is nonzero). 
	*/ 
 
	return dataBuf; 
} 
 
// 
//	write a JPEG file 
// 
BOOL CJpeg::WriteJPEGFile(LPCSTR lpstrFileName,  
						BYTE *dataBuf, 
						UINT widthPix, 
						UINT height, 
						BOOL color,  
						int quality) 
{ 
	if (dataBuf==NULL) 
		return FALSE; 
	if (widthPix==0) 
		return FALSE; 
	if (height==0) 
		return FALSE; 
 
	LPBYTE tmp; 
	if (!color)  
	{ 
		tmp = (BYTE*)new BYTE[widthPix*height]; 
		if (tmp==NULL)  
		{ 
			m_strJPEGError = "Memory error"; 
			return FALSE; 
		} 
 
		UINT row,col; 
		for (row=0;row