15

GDI+Image::Save方法需要一个 CLSID 参数来指定要使用的编码器。该文档指向一些示例代码,用于获取与特定 MIME 类型相关联的编码器,例如 image/jpeg 或 image/png。但是,我对复制半页函数只是为了支持 1 行调试帮助而犹豫不决,我将中间结果保存到磁盘。

不应该有标准编码器的标准 CLSID 列表吗?我在哪里可以找到这样的清单?我无法通过搜索 Microsoft 的包含文件找到一个。

4

3 回答 3

8

没有一个。我认为他们希望编解码器列表可扩展并支持插件,但从未解决过它。鉴于他们在相当长的一段时间内没有对 GDI+ 进行任何更改,他们可能不会很快改变。您可能会根据 Gdiplus::GetImageEncoders 的枚举生成自己的硬编码列表。

那是:

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}

这是我经常在项目之间剪切和粘贴以获取编码器的 CLSID 的功能。您可以将其修改为表格查找。

#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;
}
于 2011-03-17T22:25:15.550 回答
4

如果您只想编写 PNG,这似乎可行:

// image/png  : {557cf406-1a04-11d3-9a73-0000f81ef32e}
const CLSID pngEncoderClsId = { 0x557cf406, 0x1a04, 0x11d3,{ 0x9a,0x73,0x00,0x00,0xf8,0x1e,0xf3,0x2e } }; 
stat = image->Save(L"test.png", &pngEncoderClsId, NULL);

注意十六进制值的重新格式化。

来自: 如何初始化一个常量 CLSID

于 2015-10-17T00:25:41.573 回答
2

您可能想使用ImageCodecInfowith GetImageEncodersSize()GetImageEncoders()但我不知道有什么更简单的方法。

编辑:如果您具体知道自己想要什么,并且该死的所有其他事情,那么您就可以摆脱做这样的事情...

CLSID pngClsid;
GetEncoderClsid("image/png", &pngClsid);
image.Save("imagename.png", &pngClsid, NULL);
于 2011-03-17T22:10:48.940 回答