为啥我的 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 不能保存文件的主要内容,如果未能解决你的问题,请参考以下文章