I have a bunch of squares and each has a specific identity/symbol I need to identify. So far I have something like:
#include <iostream>
#include <windows.h>
using namespace std;
int main() {
HDC dc = GetDC(0);
COLORREF color;
int sum, x, y;
while (true) {
sum = 0;
Sleep(100);
for (x = 512; x < 521; x++) {
for (y = 550; y < 565; y++) {
color = GetPixel(dc, x, y);
sum = GetRValue(color) + GetBValue(color) + GetGValue(color);
}
}
cout << "SUM: " << sum << endl;
}
return 0;
}
Obviously it only scans one block so far. The problem is somehow even though it's only just over 100 pixels, it takes an INSANELY long time. I can't even imagine what could be going on. It takes well over a second, maybe two seconds, for each repetition. What can I do? There has to be a faster way to do this. If I can't query individual pixels, would there be a way to get a region of the screen? The zone is not inside my program's window.
Jonathan comments in the question to use DIB, but there's no answer showing how. For the sake of completeness, here's Mister B's code:
COLORREF getcolor(POINT pt) {
HDC hDc = GetDC(0);
HDC hDcmem = CreateCompatibleDC(0);
HBITMAP hBmp = CreateCompatibleBitmap(hDc, 1, 1);
SelectObject(hDcmem, hBmp);
BitBlt(hDcmem, 0, 0, 1, 1, hDc, pt.x, pt.y, SRCCOPY);
LPBITMAPINFO lpbmi = new BITMAPINFO;
lpbmi->bmiHeader.biBitCount = 24;
lpbmi->bmiHeader.biCompression = BI_RGB;
lpbmi->bmiHeader.biPlanes = 1;
lpbmi->bmiHeader.biHeight = 1;
lpbmi->bmiHeader.biWidth = 1;
lpbmi->bmiHeader.biSize = sizeof(BITMAPINFO);
BYTE lpvBits[4];
GetDIBits(hDcmem, hBmp, 0, 1, lpvBits, lpbmi, DIB_RGB_COLORS);
COLORREF currColor = RGB(lpvBits[2], lpvBits[1], lpvBits[0]);
delete lpbmi;
DeleteObject(hBmp);
DeleteDC(hDcmem);
ReleaseDC(0, hDc);
return currColor;
}
This is still very slow as Ben points out in a comment, and the solution is to use these building blocks to copy the entire area at once. Your code would become something like this:
#include <iostream>
#include <vector>
#include <windows.h>
int main() {
int const startX = 512;
int const endX = 521;
int const startX = 550;
int const endY = 565;
int const width = endX - startX;
int const height = endY - startY;
HDC const hDc = GetDC(0);
HDC const hDcmem = CreateCompatibleDC(0);
HBITMAP const hBmp = CreateCompatibleBitmap(hDc, width, height);
auto const oldBmp = SelectObject(hDcmem, hBmp);
BITMAPINFO bmi{};
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biHeight = height;
bmi.bmiHeader.biWidth = width;
bmi.bmiHeader.biSize = sizeof(BITMAPINFO);
std::vector<RGBQUAD> pixels(height * width);
while (true) {
Sleep(100);
BitBlt(hDcmem, 0, 0, width, height, hDc, startX, startY, SRCCOPY);
GetDIBits(hDcmem, hBmp, 0, height, &pixels[0], &bmi, DIB_RGB_COLORS);
int sum = 0;
for (int i = 0; i < height * width; ++i) {
sum = pixels[i].R + pixels[i].G + pixels[i].B;
}
std::cout << "SUM: " << sum << std::endl;
}
SelectObject(hDcmem, oldBmp);
DeleteObject(hBmp);
DeleteDC(hDcmem);
ReleaseDC(0, hDc);
return 0;
}
Related
Getpixel() is too slow so I am trying to use bitmap to load the RGB values into a pointer to access the RGB values rapidly, but it seems
either I messed up on the bitmap operations or I can't get the pointer right!
I use Pixelcolor() to compare so I know I have it right if the returned RGB values matches one another.
Can anyone help me out?
Here is my code :
#include <iostream>
#include <Windows.h>
using namespace std;
void cout_colour();
void get_pixel();
void main()
{
cout_colour();
get_pixel();
}
void cout_colour()
{
HDC hdc, hdcTemp;
RECT rect;
BYTE* bitPointer;
int red = 0;
int green = 0;
int blue = 0;
hdc = GetDC(GetDesktopWindow());
GetWindowRect(GetDesktopWindow(), &rect);
int MAX_WIDTH = rect.right;
int MAX_HEIGHT = rect.bottom;
cout << "MAX_WIDTH" << MAX_WIDTH << endl;
cout << "MAX_HEIGHT" << MAX_HEIGHT << endl;
hdcTemp = CreateCompatibleDC(hdc);
BITMAPINFO bitmap;
bitmap.bmiHeader.biSize = sizeof(bitmap.bmiHeader);
bitmap.bmiHeader.biWidth = MAX_WIDTH;
bitmap.bmiHeader.biHeight = MAX_HEIGHT;
bitmap.bmiHeader.biPlanes = 1;
bitmap.bmiHeader.biBitCount = 32;
bitmap.bmiHeader.biCompression = BI_RGB;
bitmap.bmiHeader.biSizeImage = 0;
bitmap.bmiHeader.biClrUsed = 0;
bitmap.bmiHeader.biClrImportant = 0;
HBITMAP hBitmap2 = CreateDIBSection(hdcTemp, &bitmap, DIB_RGB_COLORS, (void**)(&bitPointer), NULL, NULL);
SelectObject(hdcTemp, hBitmap2);
BitBlt(hdcTemp, 0, 0, MAX_WIDTH, MAX_HEIGHT, hdc, 0, 0, SRCCOPY);
int i = 1;
int x = 1;
int y = 1;
SetCursorPos(x, y);
red = (int)bitPointer[i];
green = (int)bitPointer[i + 1];
blue = (int)bitPointer[i + 2];
cout << red << " " << green << " " << blue << endl;
DeleteDC(hdc);
}
void get_pixel()
{
int x = 1;
int y = 1;
COLORREF hex_color;
int red;
int green;
int blue;
HDC dc = GetDC(GetDesktopWindow());
hex_color = GetPixel(dc, x, y);
red = GetRValue(hex_color);
green = GetGValue(hex_color);
blue = GetBValue(hex_color);
cout << "Super Slow RGB cout!" << endl;
cout << red << " " << green << " " << blue << endl;
}
You are declaring bitPointer as a pointer to an array of BYTE values. You are thus doing 8-bit indexing when getting a pixel from the array. However, you are creating a 32-bit DIB, which means its pixels are 32-bit, not 8-bit. You need to declare bitPointer as a RGBQUAD* instead.
You also need to take the DIB width into account when indexing to a pixel on the 2nd or later line.
You also have to take into account that you are creating a bottom-up DIB instead of a top-down DIB. That affects how the pixel data is laid out in memory.
GetPixel() handles all of these details for you, but since you want to access the pixels directly, you have to do it all manually.
Also, you are not releasing the HDC and HBITMAP objects correctly.
Try something more like this instead:
#include <iostream>
#include <Windows.h>
using namespace std;
void cout_colour(int x, int y)
{
HWND hWnd = GetDesktopWindow();
HDC hdc = GetDC(hWnd);
RECT rect;
GetWindowRect(hWnd, &rect);
int MAX_WIDTH = rect.right - rect.left;
int MAX_HEIGHT = rect.bottom - rect.top;
cout << "MAX_WIDTH " << MAX_WIDTH << " MAX_HEIGHT " << MAX_HEIGHT << endl;
HDC hdcTemp = CreateCompatibleDC(hdc);
BITMAPINFO bitmap;
bitmap.bmiHeader.biSize = sizeof(bitmap.bmiHeader);
bitmap.bmiHeader.biWidth = MAX_WIDTH;
bitmap.bmiHeader.biHeight = -MAX_HEIGHT;
bitmap.bmiHeader.biPlanes = 1;
bitmap.bmiHeader.biBitCount = 32;
bitmap.bmiHeader.biCompression = BI_RGB;
bitmap.bmiHeader.biSizeImage = 0;
bitmap.bmiHeader.biClrUsed = 0;
bitmap.bmiHeader.biClrImportant = 0;
LPRGBQUAD bitPointer;
HBITMAP hBitmap2 = CreateDIBSection(hdcTemp, &bitmap, DIB_RGB_COLORS, (void**)&bitPointer, 0, 0);
HBITMAP hbmpOld = (HBITMAP) SelectObject(hdcTemp, hBitmap2);
BitBlt(hdcTemp, 0, 0, MAX_WIDTH, MAX_HEIGHT, hdc, 0, 0, SRCCOPY);
LPRGBQUAD hex_color = &bitPointer[(MAX_WIDTH*y)+x];
int red = hex_color->rgbRed;
int green = hex_color->rgbGreen;
int blue = hex_color->rgbBlue;
cout << red << " " << green << " " << blue << endl;
SelectObject(hdcTemp, hbmpOld);
DeleteObject(hBitmap2);
DeleteDC(hdcTemp);
ReleaseDC(hWnd, hdc);
}
void get_pixel(int x, int y)
{
HWND hWnd = GetDesktopWindow();
HDC hdc = GetDC(wnd);
COLORREF hex_color = GetPixel(hdc, x, y);
int red = GetRValue(hex_color);
int green = GetGValue(hex_color);
int blue = GetBValue(hex_color);
cout << "Super Slow RGB cout!" << endl;
cout << red << " " << green < " " << blue << endl;
ReleaseDC(hWnd, hdc);
}
int main()
{
cout_colour(1, 1);
get_pixel(1, 1);
return 0;
}
This code is eating up my RAM at 1 to 2 percent a second (6 GB total).
Could anyone tell me what's wrong? Thanks in advance. I'm new to this, so if I sound like a complete idiot, I am. I'd like an answer fast.
#include <windows.h>
#include <iostream>
#include <stdio.h>
using namespace std;
/* Globals */
int ScreenX = 0;
int ScreenY = 0;
BYTE* ScreenData = 0;
void ScreenCap()
{
HDC hScreen = GetDC(GetDesktopWindow());
//hScreen2 = hScreen;
if (ScreenX == 0)
{
ScreenX = GetDeviceCaps(hScreen, HORZRES);
ScreenY = GetDeviceCaps(hScreen, VERTRES);
}
HDC hdcMem = CreateCompatibleDC (hScreen);
HBITMAP hBitmap = CreateCompatibleBitmap(hScreen, ScreenX, ScreenY);
HGDIOBJ hOld = SelectObject(hdcMem, hBitmap);
BitBlt(hdcMem, 0, 0, ScreenX, ScreenY, hScreen, 0, 0, SRCCOPY);
SelectObject(hdcMem, hOld);
BITMAPINFOHEADER bmi = {0};
bmi.biSize = sizeof(BITMAPINFOHEADER);
bmi.biPlanes = 1;
bmi.biBitCount = 32;
bmi.biWidth = ScreenX;
bmi.biHeight = -ScreenY;
bmi.biCompression = BI_RGB;
bmi.biSizeImage = 0;// 3 * ScreenX * ScreenY;
if(ScreenData)
free(ScreenData);
ScreenData = (BYTE*)malloc(4 * ScreenX * ScreenY);
GetDIBits(hdcMem, hBitmap, 0, ScreenY, ScreenData, (BITMAPINFO*)&bmi, DIB_RGB_COLORS);
ReleaseDC(GetDesktopWindow(),hScreen);
DeleteDC(hdcMem);
}
inline int PosB(int x, int y)
{
return ScreenData[4*((y*ScreenX)+x)];
}
inline int PosG(int x, int y)
{
return ScreenData[4*((y*ScreenX)+x)+1];
}
inline int PosR(int x, int y)
{
return ScreenData[4*((y*ScreenX)+x)+2];
}
bool ButtonPress(int Key)
{
bool button_pressed = false;
while(GetAsyncKeyState(Key))
button_pressed = true;
return button_pressed;
}
int main()
{
while (true)
{
ScreenCap();
/*for (int x = 1; x < ScreenX; x++)
{
for (int y = 1; y < ScreenY; y++)
{
int Red = PosR(x, y);
int Green = PosG(x, y);
int Blue = PosB(x, y);
if (Red == 22 && Green == 58 && Blue == 89)
{
cout << ">:D";
POINT pos;
GetCursorPos(&pos);
int DX = 683 - x;
int DY = 683 - y;
/*COLORREF col = GetPixel(hScreen2, DX - pos.x + 1, pos.y - DY + 1);
int red = GetRValue(col);
int blue = GetBValue(col);
int green = GetGValue(col);
if (red == 22 && green == 58 && blue == 89)
{
break;
}
//SetCursorPos(x + DX, y + DY);
SetCursorPos(DX - pos.x + 1, pos.y - DY + 1);
cout << DX - pos.x << ", " << pos.y - DY + 1 << endl;
break;
}
}
}*/
}
system("PAUSE");
return 0;
}
You keep creating new bitmaps and never delete them.
Even better than freeing them each time would be to reuse the previous bitmap unless the screen size actually changed. Ditto for ScreenData. Reallocating unnecessarily is a performance killer.
You also aren't selecting the original object back in before destroying the DC, which is a problem.
my pixel grabber (I modified it from online source) But the RGB values are off.. Could someone take a look at this, and maybe fix it.
I'm trying to grab all pixels from the screen and turn values into RGB as fast as possible.
#include "iostream"
#include <Windows.h>
using namespace std;
HDC hdc, hdcTemp;
int x, y;
void PixelFunction(); // Get the pixel rgb function
int main()
{
PixelFunction();
ReleaseDC(HWND_DESKTOP, hdc);
cout<<"done";
getchar();
return 0;
}
void PixelFunction()
{
BYTE* bitPointer;
int red, green, blue, alpha;
hdc = GetDC(HWND_DESKTOP);
int MAX_WIDTH = GetDeviceCaps(hdc, HORZRES);
int MAX_HEIGHT = GetDeviceCaps(hdc, VERTRES);
hdcTemp = CreateCompatibleDC(hdc);
BITMAPINFO bitmap;
bitmap.bmiHeader.biSize = sizeof(bitmap.bmiHeader);
bitmap.bmiHeader.biWidth = MAX_WIDTH;
bitmap.bmiHeader.biHeight = MAX_HEIGHT;
bitmap.bmiHeader.biPlanes = 1;
bitmap.bmiHeader.biBitCount = 32;
bitmap.bmiHeader.biCompression = BI_RGB;
bitmap.bmiHeader.biSizeImage = MAX_WIDTH * 4 * MAX_HEIGHT;
bitmap.bmiHeader.biClrUsed = 0;
bitmap.bmiHeader.biClrImportant = 0;
HBITMAP hBitmap2 = CreateDIBSection(hdcTemp, &bitmap, DIB_RGB_COLORS, (void**)(&bitPointer), NULL, NULL);
SelectObject(hdcTemp, hBitmap2);
BitBlt(hdcTemp, 0, 0, MAX_WIDTH, MAX_HEIGHT, hdc, 0, 0, SRCCOPY);
for (int i=0; i<MAX_HEIGHT; i ++)
{
for (int ii=0; ii<MAX_WIDTH; ii++)
{
{
blue = (int)bitPointer[ii];
green = (int)bitPointer[ii+1];
red = (int)bitPointer[ii+2];
alpha = (int)bitPointer[ii+3];
cout << "Red " << red << ".\n";
cout << "Green " << green << ".\n";
cout << "Blue " << blue << ".\n";
SetCursorPos(ii, i);
Sleep(500);
}
}
}
}
You're dereferencing the bitmap pointer with nonsensical offsets.
I'm not really familiar with the bitmap file format, but you'll probably need something like:
blue = (int)bitPointer[i*MAX_WIDTH + ii];
green = (int)bitPointer[i*MAX_WIDTH + ii + 1];
red = (int)bitPointer[i*MAX_WIDTH + ii + 2];
alpha = (int)bitPointer[i*MAX_WIDTH + ii + 3];
Currently, you will only ever address the top row.
This code works fine for 32, 24, 16, 8, 4 bpp images. But not for 1 bpp.
#include <stdio.h>
#include <windows.h>
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "gdi32.lib")
void GetWindowBitmapBitsAndSave(const HWND& hWnd, int nBitCount, char *szFilePath);
void EnumerateBits(LPBYTE pBits, int nBitCount, int nWidth, int nHeight);
int main(int argc, char **argv)
{
//GetWindowBitmapBits(HWND_DESKTOP, 32);
//32, 24, 16, 8, 4 works fine...
GetWindowBitmapBitsAndSave(HWND_DESKTOP, 1, "test.bmp");
return 0;
}
void EnumerateBits(LPBYTE pBits, int nBitCount, int nWidth, int nHeight)
{
int nPixels = nWidth * nHeight;
WORD wByteCount = nBitCount / 8;
if(wByteCount == 0)
wByteCount = 1;
int nBytes = nPixels * wByteCount;
for(int i = 0; i < nBytes; i += wByteCount)
{
int r = (int)(*(pBits+i));
//int g = (int)(*(pBits+i+1));
//int b = (int)(*(pBits+i+2));
//just for test
if(r != 0 /*&& g != 0 && b != 0*/)
if(r != 255 /*&& g != 255 && b != 255*/)
//printf("(%d, %d, %d)\n", r, g, b);
printf("%d\n", r);
}
}
void GetWindowBitmapBitsAndSave(const HWND& hWnd, int nBitCount, char* szFilePath)
{
HWND hScreenWnd = hWnd;
if(!hScreenWnd)
hScreenWnd = HWND_DESKTOP;
//calculate the number of color indexes in the color table
int nColorTableEntries = -1;
switch(nBitCount)
{
case 1:
nColorTableEntries = 2;
break;
case 4:
nColorTableEntries = 16;
break;
case 8:
nColorTableEntries = 256;
break;
case 16:
case 24:
case 32:
nColorTableEntries = 0;
break;
default:
nColorTableEntries = -1;
break;
}
if(nColorTableEntries == -1)
{
printf("bad bits-per-pixel argument\n");
return;
}
HDC hDC = GetDC(hScreenWnd);
HDC hMemDC = CreateCompatibleDC(hDC);
int nWidth = 0;
int nHeight = 0;
if(hScreenWnd != HWND_DESKTOP)
{
RECT rect;
GetClientRect(hScreenWnd, &rect);
nWidth = rect.right - rect.left;
nHeight = rect.bottom - rect.top;
}
else
{
nWidth = ::GetSystemMetrics(SM_CXSCREEN);
nHeight = ::GetSystemMetrics(SM_CYSCREEN);
}
HBITMAP hBMP = CreateCompatibleBitmap(hDC, nWidth, nHeight);
SelectObject(hMemDC, hBMP);
BitBlt(hMemDC, 0, 0, nWidth, nHeight, hDC, 0, 0, SRCCOPY);
int nStructLength = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * nColorTableEntries;
BITMAPINFOHEADER BitmapInfoHeader;
BitmapInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
BitmapInfoHeader.biWidth = nWidth;
BitmapInfoHeader.biHeight = nHeight;
BitmapInfoHeader.biPlanes = 1;
BitmapInfoHeader.biBitCount = nBitCount;
BitmapInfoHeader.biCompression = BI_RGB;
BitmapInfoHeader.biXPelsPerMeter = 0;
BitmapInfoHeader.biYPelsPerMeter = 0;
BitmapInfoHeader.biClrUsed = nColorTableEntries;
BitmapInfoHeader.biClrImportant = nColorTableEntries;
DWORD dwBytes = ((DWORD) nWidth * nBitCount) / 32;
if(((DWORD) nWidth * nBitCount) % 32) {
dwBytes++;
}
dwBytes *= 4;
DWORD dwSizeImage = dwBytes * nHeight;
BitmapInfoHeader.biSizeImage = dwSizeImage;
BITMAPINFO* bitmapInfo = new BITMAPINFO[sizeof(BITMAPINFO) + sizeof(RGBQUAD) * nColorTableEntries];
bitmapInfo->bmiHeader = BitmapInfoHeader;
if(nBitCount < 16)
{
for(int i = 0; i != nColorTableEntries; ++i)
{
bitmapInfo->bmiColors[i].rgbRed =
bitmapInfo->bmiColors[i].rgbGreen =
bitmapInfo->bmiColors[i].rgbBlue = (BYTE)(i*(255/(nColorTableEntries-1)));
bitmapInfo->bmiColors[i].rgbReserved = 0;
}
}
LPBYTE lpDibBits = 0;
HBITMAP hBitmap = ::CreateDIBSection(hMemDC, bitmapInfo, DIB_RGB_COLORS, (void**)&lpDibBits, NULL, 0);
SelectObject(hMemDC, hBitmap);
BitBlt(hMemDC, 0, 0, nWidth, nHeight, hDC, 0, 0, SRCCOPY);
ReleaseDC(hScreenWnd, hDC);
//save bitmap
BITMAPFILEHEADER bmfh;
bmfh.bfType = 0x4d42; // 'BM'
int nHeaderSize = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * nColorTableEntries;
bmfh.bfSize = 0;
bmfh.bfReserved1 = bmfh.bfReserved2 = 0;
bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * nColorTableEntries;
FILE *pFile = 0;
fopen_s(&pFile, szFilePath, "wb");
if(pFile)
{
fwrite(&bmfh, sizeof(BITMAPFILEHEADER), 1, pFile);
fwrite(bitmapInfo, nHeaderSize,1,pFile);
fwrite(lpDibBits, dwSizeImage, 1, pFile);
fclose(pFile);
}
EnumerateBits(lpDibBits, nBitCount, nWidth, nHeight);
delete[]bitmapInfo;
::DeleteObject(hBMP);
::DeleteObject(hBitmap);
}
First question: Why when bit count is 1 there are colors other than black and white? (but image is monochrome. Just comment EnumerateBits call in GetWindowBitmapBitsAndSave function).
Second question: How correctly calculate offset for color bits array?
IN THE END OF THE QUESTION MY LAST EDIT
Hi all,
I have to implement a function that compares two shots of a portion of the screen in order to know if there are differences/variations. I wrote something like the following code but I can't manage it to work. In the code COORDINATES_RECT is a struct
typedef struct _COORDINATES_RECT {
int x;
int y;
int sizeX;
int sizeY;
} COORDINATES_RECT;
that in input holds data to know which is the portion of the screen to analyze, and in output returns the data of the biggest rectangle in which the function found variations. To better explain the problem, I saw that if construct in the end:
if(lpbitmap1[(i*bmpScreen1.bmWidth)+j] != lpbitmap2[(i*bmpScreen1.bmWidth)+j])
never get executed. I don't know if it is the right way to compare two bitmaps (converted into char arrays). I googled and searched in msdn but with no result.
Full code follows:
void testBitmapVariations(COORDINATES_RECT *c)
{
HDC hdcScreen = GetDC(NULL);
HDC hdcMemDC1 = CreateCompatibleDC(hdcScreen);
HDC hdcMemDC2 = CreateCompatibleDC(hdcScreen);
HBITMAP hBmpScreen1 = NULL;
HBITMAP hBmpScreen2 = NULL;
BITMAP bmpScreen1;
BITMAP bmpScreen2;
if(!hdcMemDC1 || !hdcMemDC2)
{
MessageBox(NULL,L"CreateCompatibleDC failed", L"Failed", MB_OK);
ReleaseDC(NULL, hdcMemDC1);
ReleaseDC(NULL, hdcMemDC2);
return;
}
hBmpScreen1 = CreateCompatibleBitmap(hdcMemDC1, c->sizeX, c->sizeY);
hBmpScreen2 = CreateCompatibleBitmap(hdcMemDC2, c->sizeX, c->sizeY);
SelectObject(hdcMemDC1,hBmpScreen1);
if(!BitBlt(hdcMemDC1,
0,0,
c->sizeX, c->sizeY,
hdcScreen,
c->x,c->y,
SRCCOPY))
{
MessageBox(NULL,L"BitBlt failed", L"Failed", MB_OK);
ReleaseDC(NULL, hdcMemDC1);
ReleaseDC(NULL, hdcMemDC2);
return;
}
GetObject(hBmpScreen1,sizeof(BITMAP),&bmpScreen1);
BITMAPFILEHEADER bmfHeader;
BITMAPINFOHEADER bi;
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bmpScreen1.bmWidth;
bi.biHeight = bmpScreen1.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 = ((bmpScreen1.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmpScreen1.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.
char *lpbitmap1 = (char *)malloc(dwBmpSize);
// Gets the "bits" from the bitmap and copies them into a buffer
// which is pointed to by lpbitmap1.
GetDIBits(hdcScreen, hBmpScreen1, 0,
(UINT)bmpScreen1.bmHeight,
lpbitmap1,
(BITMAPINFO *)&bi, DIB_RGB_COLORS);
Sleep(200);
SelectObject(hdcMemDC2,hBmpScreen2);
if(!BitBlt(hdcMemDC2,
0,0,
c->sizeX, c->sizeY,
hdcScreen,
c->x,c->y,
SRCCOPY))
{
MessageBox(NULL,L"BitBlt failed", L"Failed", MB_OK);
ReleaseDC(NULL, hdcMemDC1);
ReleaseDC(NULL, hdcMemDC2);
return;
}
GetObject(hBmpScreen2,sizeof(BITMAP),&bmpScreen2);
char *lpbitmap2 = (char *)malloc(dwBmpSize);
// Gets the "bits" from the bitmap and copies them into a buffer
// which is pointed to by lpbitmap2.
GetDIBits(hdcScreen, hBmpScreen2, 0,
(UINT)bmpScreen2.bmHeight,
lpbitmap2,
(BITMAPINFO *)&bi, DIB_RGB_COLORS);
int i, j, minX = bmpScreen1.bmWidth, minY = bmpScreen1.bmHeight, maxX = 0, maxY = 0;
bool changed = false;
for(i = 0; i < bmpScreen1.bmHeight; i++)
{
for(j = 0; j < bmpScreen1.bmWidth; j++)
{
// I don't know why this if never get executed
if(lpbitmap1[(i*bmpScreen1.bmWidth)+j] != lpbitmap2[(i*bmpScreen1.bmWidth)+j])
{
changed = true;
if(i < minY)
minY = i;
if(i > maxY)
maxY = i;
if(j < minX)
minX = j;
if(j > maxY)
maxY = j;
}
}
}
if(changed)
{
c->x = minX;
c->y = minY;
c->sizeX = maxX - minX;
c->sizeY = maxY - minY;
}
else
{
c->sizeX = 0;
c->sizeY = 0;
}
//Frees from the heap
free(lpbitmap1);
free(lpbitmap2);
ReleaseDC(NULL, hdcMemDC1);
ReleaseDC(NULL, hdcMemDC2);
}
Thanks
Francesco
Ps. Variables declarations are put next to the block they refers to only to achieve more clarity in this question..
EDIT:
I rewrote it like this and it seems to work :) Thanks to all, however any correction is appreciated
void testBitmapVar(COORDINATES_RECT *c)
{
HDC screenDC = GetDC(0),
memDC = CreateCompatibleDC(screenDC);
HBITMAP hBm = CreateCompatibleBitmap(screenDC, c->sizeX, c->sizeY),
oldHBm;
BITMAP bm;
BITMAPFILEHEADER bmfHeader;
BITMAPINFOHEADER bi;
UINT *pixels = (UINT*) malloc ((c->sizeX*c->sizeY) * sizeof(UINT));
std::ostringstream ss;
std::wstring str;
int i, j, minX, maxX, minY, maxY;
if(!pixels)
{
c->sizeX = 0;
c->sizeY = 0;
return;
}
memset(pixels, 0, (c->sizeX*c->sizeY) * sizeof(UINT));
oldHBm = (HBITMAP) SelectObject(memDC, hBm);
// copies to bitmap
BitBlt(memDC, 0, 0, c->sizeX, c->sizeY, screenDC, c->x, c->y, SRCCOPY);
Sleep(500);
BitBlt(memDC, 0, 0, c->sizeX, c->sizeY, screenDC, c->x, c->y, SRCINVERT);
GetObject(hBm, sizeof(BITMAP), &bm);
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bm.bmWidth;
bi.biHeight = bm.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;
GetDIBits(memDC, hBm, 0,
(UINT)bm.bmHeight,
pixels,
(BITMAPINFO *)&bi, DIB_RGB_COLORS);
for(i = 0, minY = c->sizeY, maxY = -1; i < c->sizeY; i++)
{
for(j = 0, minX = c->sizeX, maxX = -1; j < c->sizeX; j++)
{
if(pixels[(i*c->sizeX)+j])
{
if(i < minY)
minY = i;
if(i > maxY)
maxY = i;
if(j < minX)
minX = j;
if(j > maxX)
maxX = j;
}
}
}
if(maxX != -1 && maxY != -1)
{
c->x = minX;
c->y = minY;
c->sizeX = maxX - minX;
c->sizeY = maxY - minY;
}
else
{
c->sizeX = 0;
c->sizeY = 0;
}
free(pixels);
SelectObject(memDC, oldHBm);
DeleteObject(hBm);
ReleaseDC(0, screenDC);
DeleteDC(memDC);
}
Rather than comparing the two bitmaps entirely on your own, consider using BitBlt to combine them using the SRCINVERT operator, which XORs the two together, so the parts that are identical will show up as zeros, and all the non-zero areas will be differences.
gc5, thanks for example! I'll add 2bit of mine:
you should define bi as:
BITMAPINFO bi;
memset(&bi, 0, sizeof(BITMAPINFO));
bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bi.bmiHeader.biWidth = bm.bmWidth;
bi.bmiHeader.biHeight = bm.bmHeight;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = 32;
bi.bmiHeader.biCompression = BI_RGB;
and then no need to define a type:
GetDIBits(memDC, hBm, 0, (UINT)bm.bmHeight, pixels, &bi, DIB_RGB_COLORS);