Search code examples
c++winapigdi+clsid

Does GDI+ have standard image encoder CLSIDs?


The GDI+ Image::Save method requires a CLSID parameter to specify the encoder to use. The documentation points to some sample code for getting the encoder associated with a particular MIME type, such as image/jpeg or image/png. However I'm balking at the thought of copying a half-page function just to support a 1-line debugging aid where I save an intermediate result out to disk.

Shouldn't there be a list of standard CLSIDs for the standard encoders? Where would I find such a list? I haven't been able to find one by searching Microsoft's include files.


Solution

  • There isn't one. I think they intended the codec list to be extensible and support plugins, but never got around to it. Given that they haven't made any changes to GDI+ in quite some time, they likely won't anytime soon. You could probably get away with generating your own hard coded list based on an enumeration of Gdiplus::GetImageEncoders.

    That is:

    image/bmp  : {557cf400-1a04-11d3-9a73-0000f81ef32e}
    image/jpeg : {557cf401-1a04-11d3-9a73-0000f81ef32e} 
    image/gif  : {557cf402-1a04-11d3-9a73-0000f81ef32e} 
    image/tiff : {557cf405-1a04-11d3-9a73-0000f81ef32e}
    image/png  : {557cf406-1a04-11d3-9a73-0000f81ef32e}
    

    Here's the function I routinely cut&paste between projects for getting at the CLSID of the encoder. You could modify it to be a table lookup.

    #include <windows.h>
    #include <gdiplus.h>
    #include <string>
    #include <vector>
    
    HRESULT GetGdiplusEncoderClsid(const std::wstring& format, GUID* pGuid)
    {
        HRESULT hr = S_OK;
        UINT  nEncoders = 0;          // number of image encoders
        UINT  nSize = 0;              // size of the image encoder array in bytes
        std::vector<BYTE> spData;
        Gdiplus::ImageCodecInfo* pImageCodecInfo = NULL;
        Gdiplus::Status status;
        bool found = false;
    
        if (format.empty() || !pGuid)
        {
            hr = E_INVALIDARG;
        }
    
        if (SUCCEEDED(hr))
        {
            *pGuid = GUID_NULL;
            status = Gdiplus::GetImageEncodersSize(&nEncoders, &nSize);
    
            if ((status != Gdiplus::Ok) || (nSize == 0))
            {
                hr = E_FAIL;
            }
        }
    
        if (SUCCEEDED(hr))
        {
    
            spData.resize(nSize);
            pImageCodecInfo = (Gdiplus::ImageCodecInfo*)&spData.front();
            status = Gdiplus::GetImageEncoders(nEncoders, nSize, pImageCodecInfo);
    
            if (status != Gdiplus::Ok)
            {
                hr = E_FAIL;
            }
        }
    
        if (SUCCEEDED(hr))
        {
            for (UINT j = 0; j < nEncoders && !found; j++)
            {
                if (pImageCodecInfo[j].MimeType == format)
                {
                    *pGuid = pImageCodecInfo[j].Clsid;
                    found = true;
                }
            }
    
            hr = found ? S_OK : E_FAIL;
        }
    
        return hr;
    }
    
    
    int main()
    {
        Gdiplus::GdiplusStartupInput gdiplusStartupInput;
        ULONG_PTR gdiplusToken;
        GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
    
        GUID guidBmp = {};
        GUID guidJpeg = {};
        GUID guidGif = {};
        GUID guidTiff = {};
        GUID guidPng = {};
    
        GetGdiplusEncoderClsid(L"image/bmp", &guidBmp);
        GetGdiplusEncoderClsid(L"image/jpeg", &guidJpeg);
        GetGdiplusEncoderClsid(L"image/gif", &guidGif);
        GetGdiplusEncoderClsid(L"image/tiff", &guidTiff);
        GetGdiplusEncoderClsid(L"image/png", &guidPng);
    
        return 0;
    }