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.
Related
I've been trying to capture the screen of my display using c++ and winapi to later convert it to a DIB for modifications. So far I've came up with this, in accordance with every guide out there:
#include "targetver.h"
#include "windows.h"
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <chrono>
void mainloop()
{
auto start = std::chrono::steady_clock::now();
HDC hdcScreen = GetDC(NULL);
if (!hdcScreen)
{
std::cout << "Couldn't get DC for screen\n";
}
auto width = GetSystemMetrics(SM_CXSCREEN);
auto height = GetSystemMetrics(SM_CYSCREEN);
HDC memDc = CreateCompatibleDC(hdcScreen);
if (!memDc)
{
std::cout << "Create compatible DC failed!\n";
}
HBITMAP hScreenBmp = CreateCompatibleBitmap(memDc, width, height);
BITMAP bmpScreen;
if (!hScreenBmp)
{
std::cout << "CreateCompatibleBitmap to screen failed\n";
}
SelectObject(memDc, hScreenBmp);
if (!BitBlt(memDc,
0, 0,
width, height,
hdcScreen,
0, 0,
SRCCOPY))
{
std::cout << "BitBlt failed\n";
}
GetObject(hScreenBmp, sizeof(BITMAP), &bmpScreen);
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;
HANDLE hDIB = GlobalAlloc(GHND, dwBmpSize);
char* lpbitmap = (char*)GlobalLock(hDIB);
GetDIBits(memDc, hScreenBmp, 0,
(UINT)bmpScreen.bmHeight,
lpbitmap,
(BITMAPINFO*)&bi, DIB_RGB_COLORS);
std::cout << "Lines: " << bi.biWidth << " x " << bi.biHeight << "px \n";
char* currPixel = (char*)lpbitmap;
for (auto j = 0; j < bi.biHeight; j++)
{
std::cout << "Line" << j << ":\n";
for (auto i = 0; i < bi.biWidth; i++)
{
std::cout << "(" << std::to_string(static_cast<unsigned char>(currPixel[0])) << "," << std::to_string(static_cast<unsigned char>(currPixel[1]))
<< "," << std::to_string(static_cast<unsigned char>(currPixel[2])) << ")\t";
currPixel += 4;
}
std::cout << std::endl;
}
GlobalUnlock(hDIB);
GlobalFree(hDIB);
DeleteDC(hdcScreen);
DeleteDC(memDc);
auto end = std::chrono::steady_clock::now();
std::cout << "Main loop completed in: " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms\n";
}
int main()
{
mainloop();
}
(and also every other variation of the above I could think of). However, the loop at the ends tries to print the values of the pixels in the DIB - and, unfortunately, all come out zeros: "(0,0,0)...". Not sure what the problem may be here and I'd love some feedback that could shed some light on this. I should probably note that the screen has a resolution of 3820x2160 pixels so the memory allocation needed for the bitmap is rather large. Also, this is a terminal-type program and not a windows-one (maybe something is not properly configured/linked - dunno - just guessing). I also tried moving the BitBlt call to every possible spot but to no avail (not sure at which time it should be called for the desired effect). Thanks for the help!
I have been struggling with this issue for the entire day and I am still not making any progress.
CONTEXT
I am trying to reproduce a virtual piano keyboard (driven with MIDI files) on LEDs attached to a physical keyboard so that my wife can learn how to play piano quicker (Christmas gift). Here is a picture of the program:
WHAT THE CODE DOES
(Or is supposed to do) I enter the coordinates of the keyboard as measured in Paint.NET after taking a screenshot of the program full-screen. The user is asked to put the software full screen. Then I calculate the coordinates of the middle of all the keys, and get the colour of the key when it is not activated. Finally I check that all white keys have the same colour, and that the black keys have the same colour (to make sure the keyboard is correctly displayed).
Later, I'll loop forever, getting the colour of each key and lighting up the corresponding LED on the physical keyboard if the colour of that key has changed from the "rest" state.
PROBLEM
I know I pick the colours at the right location, because SetPixel() displays the red pixels spot on in the middle of all keys (as seen in code). However, GetPixel still returns wrong values often times (1/4th of the time for the white keys, always for the black keys). What's happening ?
WHAT I TRIED
A added a manifest file to the project which successfully modified the size of the desktop to the correct value of 1920x1080 - but even though the RGB values changed a bit, they are still off
- I added a captureAndSave() function in case the computer "sees" a different thing than me when I do a screen capture (to obtain all the input coordinates), or than whatever does SetPixel() because this works - but the image is indeed identical, so I don't know what is happening.
- Many debugging runs...
CODE
(skip to VirtualKeyboard::init())
#include <iostream>
#include <windows.h>
using namespace std;
const unsigned int N_WHITE_KEYS = 49;
const unsigned int N_PIANO_KEYS = N_WHITE_KEYS+35;
const unsigned int N_ABSENT_BLK_KEYS = N_WHITE_KEYS*2-N_PIANO_KEYS-1;
const unsigned int ABSENT_BLK_KEYS[N_ABSENT_BLK_KEYS] = {3,7,10,14,17,21,24,28,31,35,38,42,45}; //TODO: find a formula rather than this list
const unsigned int VKxLeft = 19,
VKyTop = 150,
VKxRight = 1731,
VKyBtm = 324;
//TEMP
#include <stdio.h>
bool captureAndSave(const HWND& hWnd, int nBitCount, const char* szFilePath)
{
if(!szFilePath || !strlen(szFilePath))
{
cout << "bad function arguments\n";
return false;
}
//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)
{
cout << "bad bits-per-pixel argument\n";
return false;
}
HDC hDC = GetDC(hWnd);
HDC hMemDC = CreateCompatibleDC(hDC);
int nWidth = 0;
int nHeight = 0;
if(hWnd != HWND_DESKTOP)
{
RECT rect;
GetClientRect(hWnd, &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;
LPBITMAPINFOHEADER lpBitmapInfoHeader = (LPBITMAPINFOHEADER)new char[nStructLength];
::ZeroMemory(lpBitmapInfoHeader, nStructLength);
lpBitmapInfoHeader->biSize = sizeof(BITMAPINFOHEADER);
lpBitmapInfoHeader->biWidth = nWidth;
lpBitmapInfoHeader->biHeight = nHeight;
lpBitmapInfoHeader->biPlanes = 1;
lpBitmapInfoHeader->biBitCount = nBitCount;
lpBitmapInfoHeader->biCompression = BI_RGB;
lpBitmapInfoHeader->biXPelsPerMeter = 0;
lpBitmapInfoHeader->biYPelsPerMeter = 0;
lpBitmapInfoHeader->biClrUsed = nColorTableEntries;
lpBitmapInfoHeader->biClrImportant = nColorTableEntries;
DWORD dwBytes = ((DWORD) nWidth * nBitCount) / 32;
if(((DWORD) nWidth * nBitCount) % 32) {
dwBytes++;
}
dwBytes *= 4;
DWORD dwSizeImage = dwBytes * nHeight;
lpBitmapInfoHeader->biSizeImage = dwSizeImage;
LPBYTE lpDibBits = 0;
HBITMAP hBitmap = ::CreateDIBSection(hMemDC, (LPBITMAPINFO)lpBitmapInfoHeader, DIB_RGB_COLORS, (void**)&lpDibBits, NULL, 0);
SelectObject(hMemDC, hBitmap);
BitBlt(hMemDC, 0, 0, nWidth, nHeight, hDC, 0, 0, SRCCOPY);
ReleaseDC(hWnd, hDC);
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;
pFile = fopen(szFilePath, "wb");
if(!pFile)
{
::DeleteObject(hBMP);
::DeleteObject(hBitmap);
delete[]lpBitmapInfoHeader;
cout << "can not open file\n";
return false;
}
DWORD nColorTableSize = 0;
if (nBitCount != 24)
nColorTableSize = (1 << nBitCount) * sizeof(RGBQUAD);
else
nColorTableSize = 0;
fwrite(&bmfh, sizeof(BITMAPFILEHEADER), 1, pFile);
fwrite(lpBitmapInfoHeader, nHeaderSize,1,pFile);
if(nBitCount < 16)
{
int nBytesWritten = 0;
RGBQUAD *rgbTable = new RGBQUAD[nColorTableEntries * sizeof(RGBQUAD)];
//fill RGBQUAD table and write it in file
for(int i = 0; i < nColorTableEntries; ++i)
{
rgbTable[i].rgbRed = rgbTable[i].rgbGreen = rgbTable[i].rgbBlue = i;
rgbTable[i].rgbReserved = 0;
fwrite(&rgbTable[i], sizeof(RGBQUAD), 1, pFile);
}
delete[]rgbTable;
/*
RGBQUAD rgb;
for (DWORD i = 0; i < nColorTableEntries ; i++)
{
rgb.rgbBlue = rgb.rgbGreen = rgb.rgbRed = (BYTE)(i*(255/(nColorTableEntries-1)));
nBytesWritten = fwrite(&rgb, 1, sizeof(rgb), pFile);
if (nBytesWritten != sizeof(rgb))
{
printf("error while writing rgb header\n");
fclose(pFile);
::DeleteObject(hBMP);
::DeleteObject(hBitmap);
delete[]lpBitmapInfoHeader;
return false;
}
}
*/
}
fwrite(lpDibBits, dwSizeImage, 1, pFile);
fclose(pFile);
::DeleteObject(hBMP);
::DeleteObject(hBitmap);
delete[]lpBitmapInfoHeader;
}
//End TEMP
inline bool SameColours(COLORREF const &a, COLORREF const &b) {
bool ret = true;
ret &= GetRValue(a) == GetRValue(b);
ret &= GetGValue(a) == GetGValue(b);
ret &= GetBValue(a) == GetBValue(b);
return ret;
}
class VirtualKeyboard
{
COLORREF keyColUnpressed[N_PIANO_KEYS];
unsigned int keyX[N_PIANO_KEYS]; //White then black, from left to right
unsigned int keyY[N_PIANO_KEYS]; //White then black, from left to right
public:
bool init(unsigned int xLeft, unsigned int yTop, unsigned int xRight, unsigned yBtm) {
bool ret = true;
//Calculate parameters of the virtual keyboard
const float whtKeyHeight = (yBtm-yTop);
const float whtKeyWidth = float(xRight-xLeft)/(N_WHITE_KEYS);
//Calculate coordinates of the white keys
for(unsigned int i = 0; i < N_WHITE_KEYS ; ++i) {
keyX[i]=xLeft+(i+1.f/2)*float(whtKeyWidth);
keyY[i]=yTop+3.f/4*float(whtKeyHeight);
}
//Calculate coordinates of the black keys
unsigned int iBlkKey = 0;
for(unsigned int i = 0 ; i < N_WHITE_KEYS-1 ; ++i) {
//Determine if there is a black key
bool skip = false;
//Some black keys are absent from the offset white keys pattern - skip if applicable
for(unsigned int j = 0 ; j < N_ABSENT_BLK_KEYS ; ++j) {
if(i+1 == ABSENT_BLK_KEYS[j]) {
skip = true;
break;
}
}
//If that key exists, add it to the list
if(!skip) {
keyX[iBlkKey+N_WHITE_KEYS]=xLeft+whtKeyWidth*(i+1);
keyY[iBlkKey+N_WHITE_KEYS]=yTop+1.f/4*float(whtKeyHeight);
iBlkKey++;
}
}
//Capture the screen
HDC hdcScreen = ::GetDC(GetDesktopWindow());
captureAndSave(GetDesktopWindow(),32,"./capture.bmp");
//And fill in the colors "at rest" for all the keys
for(unsigned int i = 0 ; i < N_PIANO_KEYS ; ++i) {
keyColUnpressed[i] = ::GetPixel(hdcScreen, keyX[i], keyY[i]);
unsigned int r = GetRValue(keyColUnpressed[i]);
unsigned int g = GetGValue(keyColUnpressed[i]);
unsigned int b = GetBValue(keyColUnpressed[i]);
::SetPixel(hdcScreen, keyX[i], keyY[i], RGB(255,0,0)); //DEBUG: Breakpoint on this line, the RGB values are wrong for some keys (e.g. i=8 and all blacks)
Sleep(100);
}
ReleaseDC(GetDesktopWindow(),hdcScreen);
//Sanity check : all white keys should have the same colour, and all black keys their own colour as well
for(unsigned int i = 1 ; i < N_PIANO_KEYS ; ++i) {
if(i != 1 && i != N_WHITE_KEYS) {
if(
!SameColours(
keyColUnpressed[i],(i < N_WHITE_KEYS ? keyColUnpressed[0]
: keyColUnpressed[N_WHITE_KEYS])
)
)
{
ret = false;
break;
}
}
}
return 0;
}
};
int main()
{
VirtualKeyboard vk;
cout << "You have 3 seconds to minimize this window and maximise MidiSheetMusic" << endl;
Sleep(3000);
cout << "Result of init() : " << vk.init(VKxLeft, VKyTop, VKxRight, VKyBtm) << endl;
while(1)
{
//Get all keys pixels and reproduce on the LEDs on the physical keyboard
Sleep(10); //Runs while not Ctrl+c
}
return 0;
}
Thank you very much in advance.
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;
}
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;
}
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.