Today, my colleague asked me about the image compression algorithm. I think of a project I did about two or three years ago. It contains two compression algorithms: size and quality, and supports JPEG, bmp, and PNG formats. I will post this logic for your reference today. (For details, refer to the CSDN blog from breaksoftware)
Size Compression
Bool CompressImagePixel (const WCHAR * pszOriFilePath, const WCHAR * pszdestfilepha, UINT ulNewHeigth, UINT ulNewWidth) {// Initialize GDI +. gdiplusStartupInput gdiplusStartupInput; ULONG_PTR gdiplusToken; Status stat = GenericError; stat = GdiplusStartup (& gdiplusToken, & gdiplusStartupInput, NULL); if (OK! = Stat) {return false;} // reset the status stat = GenericError; // Get an image from the disk. image * pImage = new Image (pszOriFilePath); do {if (NULL = pImage) {break;} // obtain the length and width of UINT unOriHeight = pImage-> GetHeight (); UINT unOriWidth = pImage-> GetWidth (); do {CLSID encoderClsid; if (unOriWidth <1 | unOriHeight <1) {break;} // Get the CLSID of the JPEG encoder. if (! GetEncoderClsid (L "image/jpeg", & encoderClsid) {break;} REAL fSrcX = 0.0f; REAL fSrcY = 0.0f; REAL fSrcWidth = (REAL) unOriWidth; REAL fSrcHeight = (REAL) unOriHeight; RectF RectDest (0.0f, 0.0f, (REAL) Second, (REAL) ulNewHeigth); Bitmap * pTempBitmap = new Bitmap (ulNewWidth, ulNewHeigth ); graphics * graphics = NULL; do {if (! PTempBitmap) {break;} graphics = Graphics: FromImage (pTempBitmap); if (! Graphics) {break;} stat = graphics-> SetInterpolationMode (Gdiplus: InterpolationModeHighQuality); if (OK! = Stat) {break;} stat = graphics-> SetSmoothingMode (Gdiplus: SmoothingModeHighQuality); if (OK! = Stat) {break;} stat = graphics-> DrawImage (pImage, RectDest, fSrcX, fSrcY, fSrcWidth, fSrcHeight, UnitPixel, NULL, NULL); if (OK! = Stat) {break;} stat = pTempBitmap-> Save (pszdestfilepha, & encoderClsid, NULL); if (OK! = Stat) {break;} while (0); if (NULL! = Graphics) {delete graphics; graphics = NULL;} if (NULL! = PTempBitmap) {delete pTempBitmap; pTempBitmap = NULL ;}} while (0) ;}while (0); if (pImage) {delete pImage; pImage = NULL ;} gdiplusShutdown (gdiplusToken); return (OK = stat )? True: false );}
Quality Compression
Bool CompressImageQuality (const WCHAR * pszOriFilePath, const WCHAR * pszdestfilepha, ULONG quality) {// copy from http://msdn.microsoft.com/en-us/library/ms533844 (v = VS.85 ). aspx // Initialize GDI +. gdiplusStartupInput gdiplusStartupInput; ULONG_PTR gdiplusToken; Status stat = GenericError; stat = GdiplusStartup (& gdiplusToken, & gdiplusStartupInput, NULL); if (OK! = Stat) {return false;} // reset the status stat = GenericError; // Get an image from the disk. image * pImage = new Image (pszOriFilePath); do {if (NULL = pImage) {break;} // obtain the length and width of UINT ulHeight = pImage-> GetHeight (); UINT ulWidth = pImage-> GetWidth (); if (ulWidth <1 | ulHeight <1) {break;} // Get the CLSID of the JPEG encoder. CLSID encoderClsid; if (! GetEncoderClsid (L "image/jpeg", & encoderClsid) {break;} // The one EncoderParameter object has an array of values. // In this case, there is only one value (of type ULONG) // in the array. we will let this value vary from 0 to 100. encoderParameters encoderParameters; encoderParameters. count = 1; encoderParameters. parameter [0]. guid = EncoderQuality; encoderParameters. parameter [0]. type = EncoderP ArameterValueTypeLong; encoderParameters. parameter [0]. numberOfValues = 1; encoderParameters. parameter [0]. value = & quality; stat = pImage-> Save (pszdestfilepha, & encoderClsid, & encoderParameters) ;}while (0); if (pImage) {delete pImage; pImage = NULL ;} gdiplusShutdown (gdiplusToken); return (stat = OK )? True: false );}
The two algorithms are associated with a function GetEncoderClsid, which is implemented as follows:
#include
#include
#pragma comment( lib, "GdiPlus.lib" )using namespace Gdiplus;bool GetEncoderClsid(const WCHAR* pszFormat, CLSID* pClsid){ UINT unNum = 0; // number of image encoders UINT unSize = 0; // size of the image encoder array in bytes ImageCodecInfo* pImageCodecInfo = NULL; // How many encoders are there? // How big (in bytes) is the array of all ImageCodecInfo objects? GetImageEncodersSize( &unNum, &unSize ); if ( 0 == unSize ) { return false; // Failure } // Create a buffer large enough to hold the array of ImageCodecInfo // objects that will be returned by GetImageEncoders. pImageCodecInfo = (ImageCodecInfo*)( malloc(unSize) ); if ( !pImageCodecInfo ) { return false; // Failure } // GetImageEncoders creates an array of ImageCodecInfo objects // and copies that array into a previously allocated buffer. // The third argument, imageCodecInfos, is a pointer to that buffer. GetImageEncoders( unNum, unSize, pImageCodecInfo ); for ( UINT j = 0; j < unNum; ++j ) { if ( wcscmp( pImageCodecInfo[j].MimeType, pszFormat ) == 0 ) { *pClsid = pImageCodecInfo[j].Clsid; free(pImageCodecInfo); pImageCodecInfo = NULL; return true; // Success } } free( pImageCodecInfo ); pImageCodecInfo = NULL; return false; // Failure}
In my test code, the file name contains A as the source file, and the file name contains B as the size compression algorithm. The file name contains C as the quality compression (the size remains unchanged) the file obtained by the algorithm. The test code is
int _tmain(int argc, _TCHAR* argv[]){ CompressImagePixel( L"1A.jpg", L"1B.jpg", 100, 100 ); CompressImageQuality( L"1A.jpg", L"1C.jpg", 30 ); CompressImagePixel( L"2A.png", L"2B.jpg", 100, 100 ); CompressImageQuality( L"2A.png", L"2C.jpg", 30 ); CompressImagePixel( L"3A.bmp", L"3B.jpg", 100, 100 ); CompressImageQuality( L"3A.bmp", L"3C.jpg", 30 );return 0;}
The compression result is
From the compression results, the size compression is stable and the quality compression is unstable. If you want to control the file size through the compression algorithm, you need to combine these two methods. However, this quality compression algorithm cannot be abused. Under certain circumstances, this compression will increase the size of the file space.
Add the project code.