为啥我的 Gdiplus::Bitmap 不能保存文件

Posted

技术标签:

【中文标题】为啥我的 Gdiplus::Bitmap 不能保存文件【英文标题】:Why won't my Gdiplus::Bitmap save a file为什么我的 Gdiplus::Bitmap 不能保存文件 【发布时间】:2017-03-23 18:53:23 【问题描述】:

我是使用 GDI+ 的新手,我正在为我的个人项目做概念验证。

对于这个代码段,我基本上想将cv::Mat 转换为位图并将文件保存到任意路径。

我的转换过程改编自这个 *** 答案:

How to convert an opencv mat image to gdi bitmap

我的问题是当我调用bitmap.Save()时,它返回的错误代码为2(InvalidParameter)。

我不明白为什么我的一个或多个输入参数是错误的。

cv::Mat 初始化

cv::Mat mat = cv::Mat::ones(768, 1366, CV_8UC3);
show_image_from_mat(mat);

show_image_from_mat 函数

int show_image_from_mat(cv::Mat image) 

    cv::Size size = image.size();
    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR           gdiplusToken;
    // Initialize GDI+.
    printf("================================================================");
    printf("\n%i StarupStatus ",GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL));
    // gdiplus
    Gdiplus::Bitmap bitmap(size.width, size.height, image.step1(), PixelFormat24bppRGB, image.data);
    CLSID bmpClsid;
    printf("\n%p result", CLSIDFromString(L"557cf400-1a04-11d3-9a73-0000f81ef32e",&bmpClsid));
    printf("\n%p clsid", bmpClsid);
    const WCHAR* filename = L"C:\\output.bmp";
    char shortfilename[15];//You will need to malloc if you need to handle arbitrary filenames.

    printf("\n%i ErrorCode",bitmap.Save(filename, &bmpClsid,NULL));
    wcstombs(shortfilename, filename, 15);
    show_image_from_file(shortfilename);
    GdiplusShutdown(gdiplusToken);
    return 9001;

我从Does GDI+ have standard image encoder CLSIDs? 得到了 CLSID 可憎。

我正在 Visual Studio 中编写这个(我也是新手)。

如果图片没有加载,我的输出是这样的:

【问题讨论】:

我不确定将 CLSID 作为指针打印有什么意义。而且您还没有显示实际尝试保存图像的代码。但我最好的猜测是,您正在尝试将文件写入 C: 的根目录,并且(除非您禁用了 UAC)除非您的程序被提升,否则这是不可能的。 我只是想确保 CLSID 实际包含数据。我尝试将路径切换到桌面上的某个文件夹,但 bitmap.Save() 仍然返回错误代码 2。 Bitmap.save 是将文件写入磁盘的内容。 Bitmap 继承了 gdiplus 的 Image 类的 Save 方法 您不能将CLSID 直接传递给printf(),您必须打印各个字段:printf("\n%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X clsid", bmpClsid.Data1, bmpClsid.Data2, bmpClsid.Data3, bmpClsid.Data4[0], bmpClsid.Data4[1], bmpClsid.Data4[2], bmpClsid.Data4[3], bmpClsid.Data4[4], bmpClsid.Data4[5], bmpClsid.Data4[6], bmpClsid.Data4[7]); 否则,将CLSID 传递给StringFromCLSID() 或类似函数,然后打印结果字符串。 获取给定图像格式的CLSID正确方法是动态查询它(参见MSDN上的Retrieving the Class Identifier for an Encoder。other question也涉及到这一点)。不要依赖硬编码的 CLSID,以防有一天它确实发生了变化。 GetGdiplusEncoderClsid(L"image/bmp", &bmpClsid); 您传递给Gdiplus::Bitmap 构造函数的参数的值是多少(即size.width、size.height、image.step1())?在构造函数之后立即调用Bitmap::GetLastStatus(),查看构造过程中是否有错误。尝试其他输出路径(例如c:\Users\<UserName>\Documents),因为默认情况下,系统驱动器的根在没有管理员权限的情况下是不可写的。 【参考方案1】:

答案是您所有答案的组合。我的 CLSID 中的一个八位字节有误,输出路径不在当前用户的范围内。并且我的位图构造函数的输入参数要求步幅参数(我将 image.step1() 推入的那个)可以被 4 整除。我收到的状态错误代码为 2 是从我的位图构造函数中继承的

【讨论】:

以上是关于为啥我的 Gdiplus::Bitmap 不能保存文件的主要内容,如果未能解决你的问题,请参考以下文章

Gdiplus :: Bitmap到BYTE数组?

Gdiplus::Bitmap::FromHICON 失败

如何从 Gdiplus::Bitmap 快速复制数据

为啥我不能在 XNA 中保存我的 Xbox 360 游戏?

为啥我的Cookies不能保存信息?

为啥我的自定义按钮的值不能保存在我的数据库中?