我正在尝试将窗口的截图通过TCP发送到服务器。获取截图不是问题(使用GDIplus)。网络也很容易处理。问题在于尝试将gdi+位图转换为PNG格式(在内存中),以便从中获取数据并将其发送到服务器。请问有谁能够帮助我吗?
我正在尝试将窗口的截图通过TCP发送到服务器。获取截图不是问题(使用GDIplus)。网络也很容易处理。问题在于尝试将gdi+位图转换为PNG格式(在内存中),以便从中获取数据并将其发送到服务器。请问有谁能够帮助我吗?
Gdiplus可以保存到文件,也可以使用IStream
保存到内存。请参阅Gdiplus::Image::Save方法
//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;
}
hg
是什么? - Gray ProgrammerzHGLOBAL
的值。请参考“最小示例”获取可工作的代码。 - Barmak Shemirani
imencode()
将基于内存的图像转换为PNG格式,但这需要导入一个庞大的依赖项。相反,您可以使用NetPBM
工具,并通过popen()
进行外壳调用来执行bmptopnm()
,然后是pnmtopng()
http://netpbm.sourceforge.net/doc/pnmtopng.html,而且NetPBM的东西比OpenCV小得多。 - Mark Setchell