C++ gdi::Bitmap 到内存中的 PNG 图像
Posted
技术标签:
【中文标题】C++ gdi::Bitmap 到内存中的 PNG 图像【英文标题】:C++ gdi::Bitmap to PNG Image in memory 【发布时间】:2018-12-25 21:04:35 【问题描述】:我正在尝试通过 tcp 将窗口的屏幕截图发送到服务器。 获取屏幕截图没有问题(使用 GDIplus)。网络对我来说也很容易。问题是尝试将 gdi+ 位图转换为 png(在内存中)以从中获取数据并将其发送到服务器。 谁能帮帮我?
【问题讨论】:
不是认可,但 FreeImage 可能会有所帮助...freeimage.sourceforge.net 类似问题***.com/questions/39551863/… 不太相似,因为我想通过 tcp 将其作为字符串发送,而那家伙想将其保存到文件中 OpenCV 可以使用imencode()
将基于内存的图像转换为PNG,但这对导入有很大的依赖性。相反,您可以使用NetPBM
工具并通过popen()
执行bmptopnm()
然后pnmtopng()
netpbm.sourceforge.net/doc/pnmtopng.html 和NetPBM 的东西比OpenCV 小几英里。
这可能会有所帮助...***.com/a/22580958/2836621
【参考方案1】:
Gdiplus 可以保存到文件,或者使用IStream
保存到内存。见Gdiplus::Image::Save method
//get gdi+ bitmap
Gdiplus::Bitmap bitmap(hbitmap, nullptr);
//write to IStream
IStream* istream = nullptr;
HRESULT hr = CreateStreamOnHGlobal(NULL, TRUE, &istream);
CLSID clsid_png;
CLSIDFromString(L"557cf406-1a04-11d3-9a73-0000f81ef32e", &clsid_png);
bitmap.Save(istream, &clsid_png);
内存足够小,您可以从IStream
复制到单个缓冲区(有关详细信息,请参阅“最小示例”)
//get memory handle associated with istream
HGLOBAL hg = NULL;
GetHGlobalFromStream(istream, &hg);
//copy IStream to buffer
int bufsize = GlobalSize(hg);
char *buffer = new char[bufsize];
//lock & unlock memory
LPVOID ptr = GlobalLock(hg);
memcpy(buffer, ptr, bufsize);
GlobalUnlock(hg);
//release will automatically free the memory allocated in CreateStreamOnHGlobal
istream->Release();
PNG 现在在buffer
中可用,其大小为bufsize
。您可以直接处理二进制数据,也可以转换为 Base64 以通过网络发送。
最小示例:
#include <iostream>
#include <fstream>
#include <vector>
#include <Windows.h>
#include <gdiplus.h>
bool save_png_memory(HBITMAP hbitmap, std::vector<BYTE>& data)
Gdiplus::Bitmap bmp(hbitmap, nullptr);
//write to IStream
IStream* istream = nullptr;
if (CreateStreamOnHGlobal(NULL, TRUE, &istream) != 0)
return false;
CLSID clsid_png;
if (CLSIDFromString(L"557cf406-1a04-11d3-9a73-0000f81ef32e", &clsid_png)!=0)
return false;
Gdiplus::Status status = bmp.Save(istream, &clsid_png);
if (status != Gdiplus::Status::Ok)
return false;
//get memory handle associated with istream
HGLOBAL hg = NULL;
if (GetHGlobalFromStream(istream, &hg) != S_OK)
return 0;
//copy IStream to buffer
int bufsize = GlobalSize(hg);
data.resize(bufsize);
//lock & unlock memory
LPVOID pimage = GlobalLock(hg);
if (!pimage)
return false;
memcpy(&data[0], pimage, bufsize);
GlobalUnlock(hg);
istream->Release();
return true;
int main()
CoInitialize(NULL);
ULONG_PTR token;
Gdiplus::GdiplusStartupInput tmp;
Gdiplus::GdiplusStartup(&token, &tmp, NULL);
//take screenshot
RECT rc;
GetClientRect(GetDesktopWindow(), &rc);
auto hdc = GetDC(0);
auto memdc = CreateCompatibleDC(hdc);
auto hbitmap = CreateCompatibleBitmap(hdc, rc.right, rc.bottom);
auto oldbmp = SelectObject(memdc, hbitmap);
BitBlt(memdc, 0, 0, rc.right, rc.bottom, hdc, 0, 0, SRCCOPY);
SelectObject(memdc, oldbmp);
DeleteDC(memdc);
ReleaseDC(0, hdc);
//save as png
std::vector<BYTE> data;
if(save_png_memory(hbitmap, data))
//write from memory to file for testing:
std::ofstream fout("test.png", std::ios::binary);
fout.write((char*)data.data(), data.size());
DeleteObject(hbitmap);
Gdiplus::GdiplusShutdown(token);
CoUninitialize();
return 0;
【讨论】:
Bitmap map(currentImg, NULL); IStream* stream = nullptr; HRESULT hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); if (hr != S_OK) Utils::log(Utils::Warning, "Failed to create stream!"); continue; if (map.Save(stream, &clsid_png) != Ok) Utils::log(Utils::Warning, "Failed to save to stream!"); continue;
问题:它输出“Failed to save to stream!”,这使得错误位置很明显,但是为什么?
我如何正确格式化代码?带换行符
错误显示 InvalidParameter (GDI Status) 顺便说一句,我目前正在搜索但欢迎帮助!
无效参数通常意味着HBITMAP
句柄无效。你用的是什么编译器?查看编辑,尝试 MCVE。
@GrayProgrammerz 这是HGLOBAL
值。有关工作代码,请参阅“最小示例”。以上是关于C++ gdi::Bitmap 到内存中的 PNG 图像的主要内容,如果未能解决你的问题,请参考以下文章