I'm making a C++ program which takes screenshot of the entire screen. I am facing quite a problem. When I run the program, it takes screenshot of the console screen only, not the entire desktop.
HDC Screen = CreateDC(L"DISPLAY", NULL, NULL, NULL);
HDC Capture = CreateCompatibleDC(Screen);
int width = GetDeviceCaps(Screen, HORZRES);
int height = GetDeviceCaps(Screen, VERTRES);
LPBYTE lpcapture;
BITMAPINFO bmiCapture =
{ { sizeof(BITMAPINFOHEADER),width,height,1,24,BI_RGB,0,0,0,0,0 } };
HBITMAP hbmCapture = CreateDIBSection(Screen, &bmiCapture, DIB_RGB_COLORS, (LPVOID *)&lpcapture, NULL, 0);
if (hbmCapture)
{
HBITMAP hbmOld = (HBITMAP) SelectObject(Capture, Capture);
BitBlt(Capture, 0, 0, width, height, Screen, 0, 0, SRCCOPY);
SelectObject(Capture, hbmOld);
}
DeleteDC(Capture);
DeleteDC(Screen);
return hbmCapture;
This should work in a console program, but it would show black console screen in the middle
int ScreenCapture(const char* fname)
{
int result = 0;
HWND hWnd = GetDesktopWindow();
HBITMAP hbmScreen = NULL;
HDC hdcScreen = GetDC(NULL);
HDC hdcWindow = GetDC(hWnd);
int w = GetSystemMetrics(SM_CXSCREEN);
int h = GetSystemMetrics(SM_CYSCREEN);
HDC hdcMemDC = CreateCompatibleDC(hdcWindow);
if (!hdcMemDC) goto cleanup;
hbmScreen = CreateCompatibleBitmap(hdcWindow, w, h);
if (!hbmScreen) goto cleanup;
SelectObject(hdcMemDC, hbmScreen);
if (!BitBlt(hdcMemDC, 0, 0, w, h, hdcWindow, 0, 0, SRCCOPY)) goto cleanup;
BITMAPFILEHEADER bmfHeader;
BITMAPINFOHEADER bi;
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = w;
bi.biHeight = h;
bi.biPlanes = 1;
bi.biBitCount = 32;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
DWORD dwBmpSize = ((w * bi.biBitCount + 31) / 32) * 4 * h;
HANDLE hDIB = GlobalAlloc(GHND, dwBmpSize);
char* lpbitmap = (char*)GlobalLock(hDIB);
GetDIBits(hdcWindow, hbmScreen, 0, h, lpbitmap, (BITMAPINFO*)&bi, DIB_RGB_COLORS);
bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);
bmfHeader.bfSize = dwBmpSize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
bmfHeader.bfType = 0x4D42; //'BM' for Bitmaps
DWORD temp = 0;
HANDLE hFile = CreateFileA(fname, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
WriteFile(hFile, (LPSTR)&bmfHeader, sizeof(BITMAPFILEHEADER), &temp, NULL);
WriteFile(hFile, (LPSTR)&bi, sizeof(BITMAPINFOHEADER), &temp, NULL);
WriteFile(hFile, (LPSTR)lpbitmap, dwBmpSize, &temp, NULL);
CloseHandle(hFile);
GlobalUnlock(hDIB);
GlobalFree(hDIB);
result = 1; //success
cleanup:
DeleteObject(hbmScreen);
DeleteObject(hdcMemDC);
ReleaseDC(NULL, hdcScreen);
ReleaseDC(hWnd, hdcWindow);
return result;
}
Related
Trying to find a way that also works when the window is covered by another.
I tried PrintWindow but it doesn't store the transparency information in the hdc.
I also tried BitBlt, but the image saved doesn't contains the window transparency, and I'm not sure how to capture it when its covered by another windows.
int CaptureAnImage(HWND hWnd)
{
HDC hdcScreen;
HDC hdcWindow;
HDC hdcMemDC = NULL;
HBITMAP hbmScreen = NULL;
BITMAP bmpScreen;
DWORD dwBytesWritten = 0;
DWORD dwSizeofDIB = 0;
HANDLE hFile = NULL;
char* lpbitmap = NULL;
HANDLE hDIB = NULL;
DWORD dwBmpSize = 0;
// Retrieve the handle to a display device context for the client
// area of the window.
hdcScreen = GetDC(hWnd); // GetDC(NULL);
hdcWindow = GetDC(hWnd);
// Create a compatible DC, which is used in a BitBlt from the window DC.
hdcMemDC = CreateCompatibleDC(hdcWindow);
if (!hdcMemDC)
{
MessageBox(hWnd, L"CreateCompatibleDC has failed", L"Failed", MB_OK);
goto done;
}
// Get the client area for size calculation.
RECT rcClient;
GetClientRect(hWnd, &rcClient);
// This is the best stretch mode.
SetStretchBltMode(hdcWindow, HALFTONE);
// The source DC is the entire screen, and the destination DC is the current window (HWND).
if (!StretchBlt(hdcWindow,
0, 0,
rcClient.right, rcClient.bottom,
hdcScreen,
0, 0,
rcClient.right, //GetSystemMetrics(SM_CXSCREEN),
rcClient.bottom, //GetSystemMetrics(SM_CYSCREEN),
SRCCOPY | CAPTUREBLT))
{
MessageBox(hWnd, L"StretchBlt has failed", L"Failed", MB_OK);
goto done;
}
// Create a compatible bitmap from the Window DC.
hbmScreen = CreateCompatibleBitmap(hdcWindow, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top);
if (!hbmScreen)
{
MessageBox(hWnd, L"CreateCompatibleBitmap Failed", L"Failed", MB_OK);
goto done;
}
// Select the compatible bitmap into the compatible memory DC.
SelectObject(hdcMemDC, hbmScreen);
// Bit block transfer into our compatible memory DC.
if (!BitBlt(hdcMemDC,
0, 0,
rcClient.right - rcClient.left, rcClient.bottom - rcClient.top,
hdcWindow,
0, 0,
SRCCOPY | CAPTUREBLT))
{
MessageBox(hWnd, L"BitBlt has failed", L"Failed", MB_OK);
goto done;
}
// Get the BITMAP from the HBITMAP.
GetObject(hbmScreen, sizeof(BITMAP), &bmpScreen);
BITMAPFILEHEADER bmfHeader;
BITMAPINFOHEADER bi;
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bmpScreen.bmWidth;
bi.biHeight = bmpScreen.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = 32;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmpScreen.bmHeight;
// Starting with 32-bit Windows, GlobalAlloc and LocalAlloc are implemented as wrapper functions that
// call HeapAlloc using a handle to the process's default heap. Therefore, GlobalAlloc and LocalAlloc
// have greater overhead than HeapAlloc.
hDIB = GlobalAlloc(GHND, dwBmpSize);
lpbitmap = (char*)GlobalLock(hDIB);
// Gets the "bits" from the bitmap, and copies them into a buffer
// that's pointed to by lpbitmap.
GetDIBits(hdcWindow, hbmScreen, 0,
(UINT)bmpScreen.bmHeight,
lpbitmap,
(BITMAPINFO*)&bi, DIB_RGB_COLORS);
// A file is created, this is where we will save the screen capture.
hFile = CreateFile(L"captureqwsx.png",
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
// Add the size of the headers to the size of the bitmap to get the total file size.
dwSizeofDIB = dwBmpSize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
// Offset to where the actual bitmap bits start.
bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);
// Size of the file.
bmfHeader.bfSize = dwSizeofDIB;
// bfType must always be BM for Bitmaps.
bmfHeader.bfType = 0x4D42; // BM.
WriteFile(hFile, (LPSTR)&bmfHeader, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL);
WriteFile(hFile, (LPSTR)&bi, sizeof(BITMAPINFOHEADER), &dwBytesWritten, NULL);
WriteFile(hFile, (LPSTR)lpbitmap, dwBmpSize, &dwBytesWritten, NULL);
// Unlock and Free the DIB from the heap.
GlobalUnlock(hDIB);
GlobalFree(hDIB);
// Close the handle for the file that was created.
CloseHandle(hFile);
// Clean up.
done:
DeleteObject(hbmScreen);
DeleteObject(hdcMemDC);
ReleaseDC(NULL, hdcScreen);
ReleaseDC(hWnd, hdcWindow);
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
HWND hWnd = FindWindow(NULL, L"Untitled - Notepad");
DWORD exstyle = GetWindowLong(hWnd, GWL_EXSTYLE);
SetWindowLong(hWnd, GWL_EXSTYLE, exstyle | WS_EX_LAYERED);
SetLayeredWindowAttributes(hWnd, 0, 100, LWA_ALPHA);
CaptureAnImage(hWnd);
}
I'm facing an issue when I want to get a screenshot compressed with RLE using windows api.
I'm using Qt/C++.
Here is my code :
void Screenshot::captureScreenCompressed() {
HWND hDesktopWnd = GetDesktopWindow();
HDC hDesktopDC = GetDC(hDesktopWnd);
HDC hCaptureDC = CreateCompatibleDC(hDesktopDC);
HBITMAP hCaptureBitmap = CreateCompatibleBitmap(hDesktopDC, _screenWidth, _screenHeight);
SelectObject(hCaptureDC, hCaptureBitmap);
BitBlt(hCaptureDC, 0, 0, _screenWidth, _screenHeight, hDesktopDC, 0,0, SRCCOPY | CAPTUREBLT);
BITMAPINFO bmi = {0};
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
bmi.bmiHeader.biWidth = _screenWidth;
bmi.bmiHeader.biHeight = - _screenHeight;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RLE4;
if (GetDIBits(hCaptureDC, hCaptureBitmap, 0, _screenHeight, NULL, &bmi, DIB_RGB_COLORS) == 0) {
qDebug() << "Problem on Compression";
}
ReleaseDC(hDesktopWnd, hDesktopDC);
DeleteDC(hCaptureDC);
DeleteObject(hCaptureBitmap);
}
The final sizeImage is 0 and the getDiBits function returns 0.
I need some help thanks !
As an example, a IMediaSample is filled by random data to test a DirectShow Video Source Filter:
HRESULT CVCamStream::FillBuffer(IMediaSample *pms)
{
REFERENCE_TIME rtNow;
REFERENCE_TIME avgFrameTime = ((VIDEOINFOHEADER*)m_mt.pbFormat)->AvgTimePerFrame;
rtNow = m_rtLastTime;
m_rtLastTime += avgFrameTime;
pms->SetTime(&rtNow, &m_rtLastTime);
pms->SetSyncPoint(TRUE);
BYTE *pData;
long lDataLen;
pms->GetPointer(&pData);
lDataLen = pms->GetSize();
for(int i = 0; i < lDataLen; ++i) pData[i] = rand();
}
Instead, I want to fill the buffer with a bitmap loaded from file-system, and this is what I'm trying to do:
AM_MEDIA_TYPE *mt;
HRESULT hr;
hr = pms->GetMediaType(&mt);
if (FAILED(hr)) return hr;
VIDEOINFOHEADER *pVih;
if ((mt->formattype == FORMAT_VideoInfo) &&
(mt->cbFormat >= sizeof(VIDEOINFOHEADER)) &&
(mt->pbFormat != NULL))
{
pVih = (VIDEOINFOHEADER*)mt->pbFormat;
}
else
{
FreeMediaType(*mt);
return VFW_E_INVALIDMEDIATYPE;
}
DWORD dwBmpSize = ((640 * 3 + 31) / 32) * 4 * 480; // 640x480x24bit
HANDLE hDIB = GlobalAlloc(GHND, dwBmpSize);
char *lpbitmap = (char *)GlobalLock(hDIB);
HBITMAP hBMP = (HBITMAP)LoadImage(NULL, "path/to/my/image.png", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
HDC hdc = GetDC(NULL);
GetDIBits(hdc, hBMP, 0, 480, lpbitmap, (BITMAPINFO*)&pVih->bmiHeader, DIB_RGB_COLORS);
SetDIBitsToDevice(
hdc, 0, 0,
pVih->bmiHeader.biWidth,
pVih->bmiHeader.biHeight,
0, 0,
0,
pVih->bmiHeader.biHeight,
lpbitmap,
(BITMAPINFO*)&pVih->bmiHeader,
DIB_RGB_COLORS
);
But when I try it with Skype is just crashes...
A part any hint about the code above, how I'm supposed to debug such a filter?
Here the working code to fill IMediaSample with a bitmap:
HRESULT CVCamStream::FillBuffer(IMediaSample *pms)
{
REFERENCE_TIME rtNow;
REFERENCE_TIME avgFrameTime = ((VIDEOINFOHEADER*)m_mt.pbFormat)->AvgTimePerFrame;
rtNow = m_rtLastTime;
m_rtLastTime += avgFrameTime;
pms->SetTime(&rtNow, &m_rtLastTime);
pms->SetSyncPoint(TRUE);
BYTE *pData;
long lDataLen;
pms->GetPointer(&pData);
lDataLen = pms->GetSize();
HDC hdc = GetDC(NULL);
HBITMAP hBmp = (HBITMAP)LoadImage(NULL, "path/to/image.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
BITMAP bmp;
GetObject(hBmp, sizeof(BITMAP), &bmp);
BITMAPINFOHEADER bi;
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bmp.bmWidth;
bi.biHeight = bmp.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = 24;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
DWORD dwBmpSize = ((bmp.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmp.bmHeight;
HANDLE hDIB = GlobalAlloc(GHND, dwBmpSize);
char *lpbitmap = (char *)GlobalLock(hDIB);
GetDIBits(hdc, hBmp, 0, (UINT)bmp.bmHeight, lpbitmap, (BITMAPINFO *)&bi, DIB_RGB_COLORS);
memcpy(pData, lpbitmap, lDataLen);
return NOERROR;
} // FillBuffer
I'm taking a screenshot of a window in order to proccess it with Leptonica and later do some OCR with Tesseract
The problem is, performance wise I would like to avoid writing and reading the BMP to the disc and just work in memory instead. This is how I make the screenshot:
int width, height = 0;
HDC hdcWindow;
HDC hdcMemDC = NULL;
HBITMAP hbmScreen = NULL;
BITMAP bmpScreen;
// Retrieve the handle to a display device context for the client
// area of the window.
//hdcScreen = GetDC(NULL);
//hdcWindow = GetDC(hWnd);
hdcWindow = GetDC(hWnd);
// Create a compatible DC which is used in a BitBlt from the window DC
hdcMemDC = CreateCompatibleDC(hdcWindow);
if (!hdcMemDC)
{
MessageBox(hWnd, L"CreateCompatibleDC has failed", L"Failed", MB_OK);
goto done;
}
// Get the client area for size calculation
RECT rcClient;
GetClientRect(hWnd, &rcClient);
// Create a compatible bitmap from the Window DC
hbmScreen = CreateCompatibleBitmap(hdcWindow, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top);
if (!hbmScreen)
{
MessageBox(hWnd, L"CreateCompatibleBitmap Failed", L"Failed", MB_OK);
goto done;
}
// Select the compatible bitmap into the compatible memory DC.
SelectObject(hdcMemDC, hbmScreen);
// Bit block transfer into our compatible memory DC.
if (!BitBlt(hdcMemDC,
0, 0,
rcClient.right - rcClient.left, rcClient.bottom - rcClient.top,
hdcWindow,
0, 0,
SRCCOPY))
{
MessageBox(hWnd, L"BitBlt has failed", L"Failed", MB_OK);
goto done;
}
// Get the BITMAP from the HBITMAP
GetObject(hbmScreen, sizeof(BITMAP), &bmpScreen);
BITMAPFILEHEADER bmfHeader;
BITMAPINFOHEADER bi;
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bmpScreen.bmWidth;
bi.biHeight = bmpScreen.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = 32;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
DWORD dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmpScreen.bmHeight;
// Starting with 32-bit Windows, GlobalAlloc and LocalAlloc are implemented as wrapper functions that
// call HeapAlloc using a handle to the process's default heap. Therefore, GlobalAlloc and LocalAlloc
// have greater overhead than HeapAlloc.
HANDLE hDIB = GlobalAlloc(GHND, dwBmpSize);
char *lpbitmap = (char *)GlobalLock(hDIB);
// Gets the "bits" from the bitmap and copies them into a buffer
// which is pointed to by lpbitmap.
GetDIBits(hdcWindow, hbmScreen, 0,
(UINT)bmpScreen.bmHeight,
lpbitmap,
(BITMAPINFO *)&bi, DIB_RGB_COLORS);
// A file is created, this is where we will save the screen capture.
HANDLE hFile = CreateFile(L"pics/UI.bmp",
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
// Add the size of the headers to the size of the bitmap to get the total file size
DWORD dwSizeofDIB = dwBmpSize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
//Offset to where the actual bitmap bits start.
bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);
//Size of the file
bmfHeader.bfSize = dwSizeofDIB;
//bfType must always be BM for Bitmaps
bmfHeader.bfType = 0x4D42; //BM
DWORD dwBytesWritten = 0;
WriteFile(hFile, (LPSTR)&bmfHeader, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL);
WriteFile(hFile, (LPSTR)&bi, sizeof(BITMAPINFOHEADER), &dwBytesWritten, NULL);
WriteFile(hFile, (LPSTR)lpbitmap, dwBmpSize, &dwBytesWritten, NULL);
//Unlock and Free the DIB from the heap
GlobalUnlock(hDIB);
GlobalFree(hDIB);
//Close the handle for the file that was created
CloseHandle(hFile);
width = rcClient.right - rcClient.left;
height = rcClient.bottom - rcClient.top;
//Clean up
done:
DeleteObject(hbmScreen);
DeleteObject(hdcMemDC);
ReleaseDC(hWnd, hdcWindow);
And this is how I read it:
PIX* pixUI = pixRead("pics/UI.bmp");
So, I've seen that the library has a PIX * pixReadMemBmp ( const l_uint8 *cdata, size_t size ) method which takes a l_uint8 which is an unsigned char buffer
The problem is, I don't understand how I can get such a buffer from my HBITMAP or BITMAP object.
Copy the bitmap into a buffer first, then hand this buffer to pixReadMemBmp(). The copying has to be done because , I assume, the pixReadMemBmp() function needs the both bitmap headers in front of the bitmap data, as it would be in a file. Pseudocode:
std::vector<unsigned char> buffer(sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwBmpSize);
std::copy(reinterpret_cast<unsigned char*>(&bmfHeader), reinterpret_cast<unsigned char*>(&bmfHeader) + sizeof(BITMAPFILEHEADER), buffer.begin());
std::copy(reinterpret_cast<unsigned char*>(&bi), reinterpret_cast<unsigned char*>(&bi) + sizeof(BITMAPINFOHEADER), buffer.begin() + sizeof(BITMAPFILEHEADER));
std::copy(lpbitmap, lpbitmap + dwBmpSize, buffer.begin() + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER));
pixReadMemBmp(&buffer[0], buffer.size());
My GetScreen function looks like:
void GetScreen(int clientSocket, const char *filename) {
HDC hDC = NULL;
int nScreenWidth = GetSystemMetrics(SM_CXSCREEN);
int nScreenHeight = GetSystemMetrics(SM_CYSCREEN);
HWND hDesktopWnd = GetDesktopWindow();
HDC hDesktopDC = GetDC(hDesktopWnd);
HDC hCaptureDC = CreateCompatibleDC(hDesktopDC);
HBITMAP hCaptureBitmap =CreateCompatibleBitmap(hDesktopDC,
nScreenWidth, nScreenHeight);
SelectObject(hCaptureDC,hCaptureBitmap);
BitBlt(hCaptureDC,0,0,nScreenWidth,nScreenHeight,
hDesktopDC,0,0,SRCCOPY|CAPTUREBLT);
SaveBitmap(clientSocket, "test.bmp",hCaptureBitmap); //here to save the captured image to disk
**//here to send Hbitmap: send(clientSocket,?,?,Null);**
ReleaseDC(hDesktopWnd,hDesktopDC);
DeleteDC(hCaptureDC);
DeleteObject(hCaptureBitmap);
}
Now I want to send HBITMAP over socket without bitmap saving.
I've Googled and have found GetDIBits and SetDIBits
but I do not know how I can use it exactly. Can someone help me? Thank you.
now i tried to get BYTE from HBITMAP with this code:
BYTE* getPixArray(HBITMAP hBitmap)
{
HDC hdc,hdcMem;
hdc = GetDC(NULL);
hdcMem = CreateCompatibleDC(hdc);
BITMAPINFO MyBMInfo = {0};
MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader);
// Get the BITMAPINFO structure from the bitmap
if(0 == GetDIBits(hdcMem, hBitmap, 0, 0, NULL, &MyBMInfo, DIB_RGB_COLORS))
{
cout<<"FAIL\n"<<endl;
}
// create the bitmap buffer
BYTE* lpPixels = new BYTE[MyBMInfo.bmiHeader.biSizeImage];
MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader);
MyBMInfo.bmiHeader.biBitCount = 32;
MyBMInfo.bmiHeader.biCompression = BI_RGB;
MyBMInfo.bmiHeader.biHeight = (MyBMInfo.bmiHeader.biHeight < 0) ? (-MyBMInfo.bmiHeader.biHeight) : (MyBMInfo.bmiHeader.biHeight);
// get the actual bitmap buffer
if(0 == GetDIBits(hdc, hBitmap, 0, MyBMInfo.bmiHeader.biHeight, (LPVOID)lpPixels, &MyBMInfo, DIB_RGB_COLORS))
{
cout<<"FAIL\n"<<endl;
}
return lpPixels;
}
now in the other side of socket i want to get HBITMAP from BYTE!?!
please help me. thx.
Once you have an HBITMAP, call HBITMAPToPixels. Send the width, the height, and the bitsperpixel. Next send the pixels..
On the other end of the socket, read width, read height, read bitsperpixel.
Then create a buffer of size: ((width * Bmp.bmBitsPixel + 31) / 32) * 4 * height
Read that many bytes into the buffer and call HBITMAPFromPixels
The functions discussed are defined below..
#include <iostream>
#include <stdexcept>
#include <vector>
#include <cstring>
#include <memory>
#include <windows.h>
std::unique_ptr<std::remove_pointer<HBITMAP>::type, std::function<void(HBITMAP)>> HBITMAPFromPixels(const std::vector<std::uint8_t> &Pixels, std::uint32_t width, std::uint32_t height, std::uint16_t BitsPerPixel)
{
BITMAPINFO Info = {0};
std::memset(&Info, 0, sizeof(BITMAPINFO));
Info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
Info.bmiHeader.biWidth = width;
Info.bmiHeader.biHeight = -height;
Info.bmiHeader.biPlanes = 1;
Info.bmiHeader.biBitCount = BitsPerPixel;
Info.bmiHeader.biCompression = BI_RGB;
Info.bmiHeader.biSizeImage = ((width * BitsPerPixel + 31) / 32) * 4 * height;
HBITMAP Result = CreateDIBitmap(GetDC(nullptr), &Info.bmiHeader, CBM_INIT, &Pixels[0], &Info, DIB_RGB_COLORS);
return std::unique_ptr<std::remove_pointer<HBITMAP>::type, std::function<void(HBITMAP)>>(Result, [&](HBITMAP hBmp){DeleteObject(hBmp);});
}
void HBITMAPToPixels(HBITMAP BitmapHandle, std::vector<std::uint8_t> &Pixels, std::uint32_t &width, std::uint32_t &height, std::uint16_t &BitsPerPixel)
{
if (BitmapHandle == nullptr)
{
throw std::logic_error("Null Pointer Exception. BitmapHandle is Null.");
}
Pixels.clear();
BITMAP Bmp = {0};
BITMAPINFO Info = {0};
HDC DC = CreateCompatibleDC(nullptr);
std::memset(&Info, 0, sizeof(BITMAPINFO));
HBITMAP OldBitmap = (HBITMAP)SelectObject(DC, BitmapHandle);
GetObject(BitmapHandle, sizeof(Bmp), &Bmp);
Info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
Info.bmiHeader.biWidth = width = Bmp.bmWidth;
Info.bmiHeader.biHeight = height = Bmp.bmHeight;
Info.bmiHeader.biPlanes = 1;
Info.bmiHeader.biBitCount = BitsPerPixel = Bmp.bmBitsPixel;
Info.bmiHeader.biCompression = BI_RGB;
Info.bmiHeader.biSizeImage = ((width * Bmp.bmBitsPixel + 31) / 32) * 4 * height;
Pixels.resize(Info.bmiHeader.biSizeImage);
GetDIBits(DC, BitmapHandle, 0, height, &Pixels[0], &Info, DIB_RGB_COLORS);
SelectObject(DC, OldBitmap);
height = height < 0 ? -height : height;
DeleteDC(DC);
}
Always send the pixel data of the bitmaps (unsigned char *). HBITMAP is just a handle for your bitmap. Also take care of the size issues, if your height, width and bpp are high, u need to think of compressing the pixels data.