zoukankan      html  css  js  c++  java
  • 一种使用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 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
    }
            在我的測试代码中,文件名称中包括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;
    }
            其压缩结果是


            从压缩结果看。尺寸压缩是稳定的。质量压缩是不稳定的。假设想通过压缩算法控制文件大小,须要结合这两种方法。可是须要指出的是。该质量压缩算法不能够滥用。由于在一定情况下,该质量压缩会使文件空间大小变大。


    最后附上project代码。

  • 相关阅读:
    Asp.net的核心对象
    webform在页面生成的代码与事件回传
    计算机专业课程
    代替iframe的方法
    js中斜杠转义
    Uncaught Error: Syntax error, unrecognized expression: |117的js错误
    vs调试时报503错误
    Md5加密方法
    ps批量修改图片
    “Parsing filters unsupported” error during extraction of RAR file
  • 原文地址:https://www.cnblogs.com/zsychanpin/p/7340230.html
Copyright © 2011-2022 走看看