I used this code in this link to take a screenshot of the screen using GdiPlus and convert the bitmap to png bytes.
#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;
}
Question
- How can prepare that byte data (std::vector data;) to pass it through dart ffi to work with it in flutter?
- Please anyway possible will be accepted.
My biggest confussion is ffi doesn't have a coresponding byte data type, so how should I go by it?
The data type you are looking for on the Dart side is
Pointer<Uint8>
, which is a pointer to unsigned bytes. You can pass this pointer over the ffi boundary and access the pointee bytes on either side. But, pointer is no good to you until you allocate some storage (thinkmalloc
/free
).There are two ways to allocate the storage (array of bytes) that the pointer will reference. You can either
malloc
(and subsequentlyfree
) the bytes on the C side, ormalloc.allocate<Uint8>()
(and subsequentlymalloc.free()
) them on the Dart side.Then, on the C side you already have sample code in your snippet for copying the
std::vector<BYTE>
into the pointee buffer:copies
bufsize
bytes fromdata
to the buffer pointed to by the pointer. (Alternatively, you could just assign&data[0]
to the pointer as long as you know data won't go out of scope - and you free it after you use it).Once you have the
Pointer<Uint8>
on the Dart side, just callasTypedList
to get aUint8List
that allows you to access the bytes on the Dart side.Also, remember that Dart FFI is a
C
interface, so if you want to use C++ classes you will need to wrap them in C methods. See: Can I call a C++ constructor function in dart ffi? Those C methods can/should be in C++ source files as long as they are markedextern "C"
.