一种使用GDI+对图片尺寸和质量的压缩方法
生活随笔
收集整理的這篇文章主要介紹了
一种使用GDI+对图片尺寸和质量的压缩方法
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
? ? ? ? 今天同事向我詢問圖片壓縮的算法,我想起大概兩三年前做過的一個項目。其中包含了尺寸和質量兩種壓縮算法,并且支持JPEG、bmp、PNG等格式。今天把這段邏輯貼出來,供大家參考。(轉載請指明來源于breaksoftware的CSDN博客)
- 尺寸壓縮
bool CompressImagePixel( const WCHAR* pszOriFilePath, const WCHAR* pszDestFilePah, UINT ulNewHeigth, UINT ulNewWidth )
{// Initialize GDI+.GdiplusStartupInput gdiplusStartupInput;ULONG_PTR gdiplusToken;Status stat = GenericError;stat = GdiplusStartup( &gdiplusToken, &gdiplusStartupInput, NULL );if ( Ok != stat ) {return false;}// 重置狀態stat = GenericError;// Get an image from the disk.Image* pImage = new Image(pszOriFilePath);do {if ( NULL == pImage ) {break;}// 獲取長寬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)ulNewWidth, (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, NULL);if ( Ok != stat ) {break;}stat = pTempBitmap->Save( pszDestFilePah, &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 );
} - 質量壓縮
bool CompressImageQuality( const WCHAR* pszOriFilePath, const WCHAR* pszDestFilePah,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;}// 重置狀態stat = GenericError;// Get an image from the disk.Image* pImage = new Image(pszOriFilePath);do {if ( NULL == pImage ) {break;}// 獲取長寬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 = EncoderParameterValueTypeLong;encoderParameters.Parameter[0].NumberOfValues = 1;encoderParameters.Parameter[0].Value = &quality;stat = pImage->Save(pszDestFilePah, &encoderClsid, &encoderParameters);} while(0);if ( pImage ) {delete pImage;pImage = NULL;}GdiplusShutdown(gdiplusToken);return ( ( stat == Ok ) ? true : false );
}? ? ? ? 這兩個算法,都關聯了一個函數GetEncoderClsid,其實現是: #include <Windows.h>
#include <GdiPlus.h>
#pragma comment( lib, "GdiPlus.lib" )
using namespace Gdiplus;bool GetEncoderClsid(const WCHAR* pszFormat, CLSID* pClsid)
{UINT unNum = 0; // number of image encodersUINT unSize = 0; // size of the image encoder array in bytesImageCodecInfo* 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
}? ? ? ? 在我的測試代碼中,文件名中包含A的為源文件,文件名中包含B的是尺寸壓縮算法得到的文件,文件名中包含C的是質量壓縮(尺寸不變)算法得到的文件。測試代碼是 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;
}? ? ? ? 其壓縮結果是 ? ? ? ? 從壓縮結果看,尺寸壓縮是穩定的,質量壓縮是不穩定的。如果想通過壓縮算法控制文件大小,需要結合這兩種方法。但是需要指出的是,該質量壓縮算法不可以濫用。因為在一定情況下,該質量壓縮會使文件空間大小變大。
最后附上工程代碼。
總結
以上是生活随笔為你收集整理的一种使用GDI+对图片尺寸和质量的压缩方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PE文件和COFF文件格式分析——导出表
- 下一篇: Windows客户端C/C++编程规范“