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;row alloc_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