Thanks for the reply. I had no idea Gdip.ahk existed, that's good to know. I'm using Win7, but I'm actually reading pixels from the window of a game (Dragon Age: Inquisition), which is running in windowed fullscreen mode, so I don't know if desktop composition plays much of a role here. In any case, it's become clear that going through a DC and using GetPixel is not a good idea for what I'm trying to do here, which is to gain as much performance as possible (the script should ideally do this operation as many times a second as possible).
I decided to bite the bullet and try to access the bitmap directly, which is much faster, and probably the right way to go in this situation. I'm using the following code to obtain the array of pixels:
Code: Select all
HDC scrdc = GetDC(FindWindowA("Dragon Age: Inquisition", NULL));
HBITMAP bmp = CreateCompatibleBitmap(scrdc, scrw, scrh);
HDC memdc = CreateCompatibleDC(scrdc);
SelectObject(memdc, bmp);
BitBlt(memdc, 0, 0, scrw, scrh, scrdc, 0, 0, SRCCOPY);
BITMAPINFO bmi = {0};
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
GetDIBits(memdc, bmp, 0, 0, NULL, &bmi, DIB_RGB_COLORS);
RGBQUAD *pixels = new RGBQUAD[scrw * scrh];
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biHeight = abs(bmi.bmiHeader.biHeight);
GetDIBits(memdc, bmp, 0, bmi.bmiHeader.biHeight, pixels, &bmi, DIB_RGB_COLORS);
That's working beautifully, but the pixels in the array don't seem to have the colors I expect them to, which I imagine is probably because they are not organized the way I think they are. I've saved the raw pixel data to a file, as well as a proper .bmp file, and then compared the two. I opened the .bmp file in an image editor, and verified that a certain pixel was black, as expected. I then located that pixel in the raw data file, and it was some random color instead of black.
I'm working with the assumption that the pixels are organized in consecutive lines, starting from top to bottom (unless BITMAPINFO::bmiHeader.biHeight is negative, in which case it begins from the bottom). This is the code/logic I'm using to access a pixel of (x,y) coordinates:
Code: Select all
const int ix = scrw * y + x - (y>0);
if(!pixels[ix].rgbBlue && !pixels[ix].rgbGreen && !pixels[ix].rgbRed)
ret = 1;
I'm currently in the process of trying to figure out what's going on. Any idea what that might be?
Edit: Gdip.ahk opened my eyes to the wonders of GDI+, so I've constructed a Bitmap object from the BITMAPINFO and the pixel data, and now I'm using its GetPixel method to read the pixels. It works great! The GDI+ overhead seems minimal, and it seems to be OK with concurrency. When using sequential calls to GetPixel with a DC, the whole thing took about 380ms on average. Now it's about 40ms on average, and I've discovered that as fast as possible is actually too fast, so I've put it on a 100ms timer within the script. Anyway, thanks for the help!
2nd edit: In case anyone cares, the problem was that the bitmap was bottom-up after all (I misread the documentation). I am now reading the pixel colors directly from the array, and I've dropped the multithreading since it's pointless.