I would like to get the RGB values of a pixel at different x, y coordinates on the screen.
How would I go about this in C++?
I'm trying to create my own gaussian blur effect.
This would be in Windows 7.
Edit
What libraries need to be included for this to run?
What I have going:
#include <iostream>
using namespace std ;
int main(){
HDC dc = GetDC(NULL);
COLORREF color = GetPixel(dc, 0, 0);
ReleaseDC(NULL, dc);
cout << color;
}
You can use GetDC on the NULL window to get a device context for the whole screen, and can follow that up with a call to GetPixel:
HDC dc = GetDC(NULL);
COLORREF color = GetPixel(dc, x, y);
ReleaseDC(NULL, dc);
Of course, you'd want to only acquire and release the device context once while doing all the pixel-reading for efficiency.
As mentioned in a previous post, you want the GetPixel function from the Win32 API.
GetPixel sits inside gdi32.dll, so if you have a proper environment setup, you should be able to include windows.h (which includes wingdi.h) and you should be golden.
If you have a minimal environment setup for whatever reason, you could also use LoadLibrary on gdi32.dll directly.
The first parameter to GetPixel is a handle to the device context, which can be retrieved by calling the GetDC function(which is also available via <windows.h>).
A basic example that loads GetPixel from the dll and prints out the color of the pixel at your current cursor position is as follows.
#include<windows.h>
#include<stdio.h>
typedef WINAPI COLORREF (*GETPIXEL)(HDC, int, int);
int main(int argc, char** argv)
{
HINSTANCE _hGDI = LoadLibrary("gdi32.dll");
if(_hGDI)
{
while(true) {
GETPIXEL pGetPixel = (GETPIXEL)GetProcAddress(_hGDI, "GetPixel");
HDC _hdc = GetDC(NULL);
if(_hdc)
{
POINT _cursor;
GetCursorPos(&_cursor);
COLORREF _color = (*pGetPixel) (_hdc, _cursor.x, _cursor.y);
int _red = GetRValue(_color);
int _green = GetGValue(_color);
int _blue = GetBValue(_color);
printf("Red: 0x%02x\n", _red);
printf("Green: 0x%02x\n", _green);
printf("Blue: 0x%02x\n", _blue);
}
FreeLibrary(_hGDI);
}
}
return 0;
}
Related
I am unable to manage memory for Bitmap and CLSID objects I have created in a screenshot object class. Both of these are from the GDI+ library. The header lists the following private variables in Screenshot.h
#include <gdiplus.h>
#include <iostream>
#include <fstream>
#include <string>
#include "windows.h"
#pragma once
#pragma comment(lib, "gdiplus.lib")
using namespace std;
using namespace Gdiplus;
class Screenshot
{
private:
HDC dc, memdc, fontdc;
HBITMAP membit;
Bitmap* bmpPtr;
CLSID clsid;
ULONG_PTR gdiplusToken;
int GetEncoderClsid(const WCHAR* format, CLSID* pClsid);
public:
Screenshot();
~Screenshot();
void TakeScreenshot(string userAction, string winName, long xMousePos, long yMousePos, long long tStamp);
void SaveScreenshot(string filename);
void memoryManagement();
};
Then when my main program takes a screenshot, the values are filled in with TakeScreenshot(), but not yet saved to disk
void Screenshot::TakeScreenshot(//redacted for readibility) {
GdiplusStartupInput gdiplusStartupInput;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
HWND hwnd = GetDesktopWindow();
dc = ::GetDC(0);
int scaleHeight, scaleWidth = 0;
int Height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
int Width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
scaleHeight = Height + (0.1 * Height);
memdc = CreateCompatibleDC(dc);
membit = CreateCompatibleBitmap(dc, Width, scaleHeight);
HBITMAP bmpContainer = (HBITMAP)SelectObject(memdc, membit);
BitBlt(memdc, 0, 0, Width, Height, dc, 0, 0, SRCCOPY);
//Other code that adds fonts, etc. Does not invoke bmpPtr
bmpPtr = new Bitmap(membit, NULL);
GetEncoderClsid(L"image/jpeg", &clsid);
If the screenshot is saved, another function SaveScreenshot() uses bmpPtr->Save() and Gdiplus shutdown is called inside of it. However, some of the screenshots get popped off from a queue (STL queue) and out of memory instead of saved, as follows:
void ManageQueue(Screenshot& ssObj)
{
//If queue contains 30 screenshots, pop off first element and push new object
//Else just push new object
if (screenshotQueue.size() == MAX_SCREENSHOTS)
{
screenshotQueue.front().memoryManagement();
screenshotQueue.pop();
screenshotQueue.push(ssObj);
}
else
{
screenshotQueue.push(ssObj);
}
}
I wrote a MemoryManagement() function to perform the necessary releases and deletes before the Screenshot is popped off. This function is not called if the screenshot has been saved:
void Screenshot::memoryManagement()
{
delete bmpPtr;
delete &clsid;
ReleaseDC(NULL, memdc);
DeleteObject(fontdc);
DeleteObject(memdc);
DeleteObject(membit);
}
When either the delete on bmpPtr or clsid is called, whether it is from this function or in the deconstructor, the program is crashing. I am experiencing significant memory leaks with the program now and without running a windows equivalent of Valgrind I'm assuming it's coming from here. How can I successfully delete these objects? I will credit any answer in my source code as a contributing programmer. Please leave any suggestions for improving my question if needed.
scaleHeight = Height + (0.1 * Height);
This seems to be an attempt to fix the problem with DPI scaling. It will work if DPI settings is at 10%, but that's usually not the case. You have to make your program DPI aware through the manifest file. Use SetProcessDPIAware for a quick fix.
Don't declare dc, memdc, etc. as class members. These are GDI handles (not GDI+) which you can hold for a short time, usually during the duration of the function. You have to release them as soon as possible.
Also other variables like clsid don't need to be declared as class members. You can declare them as class member if you wish, but there is nothing to gain.
If you have a multi-monitor setup you also need SM_XVIRTUALSCREEN/Y to get the top-left corner of the monitor setup.
//call this once on start up
SetProcessDPIAware();
HDC dc = ::GetDC(0);
int x = GetSystemMetrics(SM_XVIRTUALSCREEN);
int y = GetSystemMetrics(SM_YVIRTUALSCREEN);
int Height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
int Width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
HDC memdc = CreateCompatibleDC(dc);
HBITMAP membit = CreateCompatibleBitmap(dc, Width, Height);
HBITMAP bmpContainer = (HBITMAP)SelectObject(memdc, membit);
BitBlt(memdc, 0, 0, Width, Height, dc, x, y, SRCCOPY);
Bitmap* bmpPtr = new Bitmap(membit, NULL);
// or just Bitmap bmp(membit, NULL);
CLSID clsid;
GetEncoderClsid(L"image/jpeg", &clsid);
bmpPtr->Save(L"output.jpg", &clsid);
//cleanup:
delete bmpPtr;
SelectObject(memdc, bmpContainer);
DeleteObject(membit);
DeleteDC(memdc);
ReleaseDC(0, dc);
The solution for this problem was to use the namespace delete instead of regular delete. Switching to this prevented the break point trigger during debug and has sealed the memory leak.
void Screenshot::memoryManagement()
{
::delete bmpPtr;
ReleaseDC(NULL, memdc);
DeleteObject(fontdc);
DeleteObject(memdc);
DeleteObject(membit);
GdiplusShutdown(gdiplusToken);
}
I enjoy making "animations" in c++ such as a MandelBrot Set zoomer, Game of Life simulator etc. by setting pixels directly to the screen frame-by-frame. The SetPixel() command makes this incredibly easy, although unfortunately it's also painfully slow. Here is the sort of set-up I use for each frame, if I wanted to paint the entire screen with the contents of the array R:
#include <windows.h>
using namespace std;
int main()
{
int xres = 1366;
int yres = 768;
char *R = new char [xres*yres*3];
/*
R is a char array containing the RGB value of each pixel sequentially
Arithmetic operations done to each element of R here
*/
HWND window; HDC dc; window = GetActiveWindow(); dc = GetDC(window);
for (int j=0 ; j<yres ; j++)
for (int i=0 ; i<xres ; i++)
SetPixel(dc,i,j,RGB(R[j*xres+3*i],R[j*xres+3*i+1],R[j*xres+3*i+2]));
delete [] R;
return 0;
}
On my machine this takes almost 5 seconds to execute for the obvious reason that SetPixel() is being called over a million times. Best case scenario I could get this to run 100x faster and get a smooth 20fps animation.
I hear that converting R into a bitmap file in some way and then using BitBlt to display the frame in one clean command is the way to go, but I have no idea how to implement this for my setup and would greatly appreciate any help.
If it is relevant, I am running on Windows 7 and using Code::Blocks as my IDE.
Following Remy's advices I ended up with this way of showing pixel array (for guys, who needs some code as an example):
COLORREF *arr = (COLORREF*) calloc(512*512, sizeof(COLORREF));
/* Filling array here */
/* ... */
// Creating temp bitmap
HBITMAP map = CreateBitmap(512 // width. 512 in my case
512, // height
1, // Color Planes, unfortanutelly don't know what is it actually. Let it be 1
8*4, // Size of memory for one pixel in bits (in win32 4 bytes = 4*8 bits)
(void*) arr); // pointer to array
// Temp HDC to copy picture
HDC src = CreateCompatibleDC(hdc); // hdc - Device context for window, I've got earlier with GetDC(hWnd) or GetDC(NULL);
SelectObject(src, map); // Inserting picture into our temp HDC
// Copy image from temp HDC to window
BitBlt(hdc, // Destination
10, // x and
10, // y - upper-left corner of place, where we'd like to copy
512, // width of the region
512, // height
src, // source
0, // x and
0, // y of upper left corner of part of the source, from where we'd like to copy
SRCCOPY); // Defined DWORD to juct copy pixels. Watch more on msdn;
DeleteDC(src); // Deleting temp HDC
I have window handle and I need get pixel color.
#include "Globals.h"
void MainHamsterDlg::OnTimer(UINT nIDEvent)
{
Sleep(4000);
HDC hDC = ::GetDC(tempHWND);
COLORREF rgb = GetPixel(hDC,351,515);
if(GetPixel(hDC,351,515) == RGB(33,30,28))
AfxMessageBox(L"Please select or write correct name!");
::ReleaseDC(tempHWND, hDC);
CDialog::OnTimer(nIDEvent);
}
Debuging says that the COLORREF rgb = GetPixel(hDC,351,515); gets the value 3225917 do i need convert to rgb to check for compare?
I dont uderstund what wrong there because i'm new in mfc.
#include "Globals.h"
void WaitProcessDlg::OnTimer(UINT nIDEvent)
{
if(::FindWindow(NULL, str)){
tempHWND = ::FindWindow(NULL, str);
::SetWindowText(tempHWND, L"Weather");
EndDialog( 0 );
KillTimer(IDC_PROGRESS1);
}
CDialog::OnTimer(nIDEvent);
}
Here window handle and its handles window. I checked with changing title.
I'm using Globals to transfer window handle from one dialog box to another.
Globals.h
-------------------
#pragma once
extern HWND tempHWND;
--------------------
So my question is do I need convert to RGB to check for compare? and how?
I use different code to make that and its work!
HDC hDC = CreateDC(L"DISPLAY",0,0,0);
COLORREF rgb5 = GetPixel(hDC,24,507);
In C++ using Code::Blocks v10.05, how do I draw a single pixel on the console screen? Is this easy at all, or would it be easier to just draw a rectangle? How do I color it?
I'm sorry, but I just can't get any code from SOF, HF, or even cplusplus.com to work. This is for a Super Mario World figure on the screen. The game I think is 16-bit, and is for the SNES system. C::B says I need SDK for C::B. It says "afxwin.h" doesn't exist. Download maybe?
This is what I'm trying to make:
It depends on your OS. I suppose you are programming in a Windows platform, therefore you can use SetPixel but you have to use "windows.h" to get a console handle, so here an example for drawing the cos() function:
#include<windows.h>
#include<iostream>
#include <cmath>
using namespace std;
#define PI 3.14
int main()
{
//Get a console handle
HWND myconsole = GetConsoleWindow();
//Get a handle to device context
HDC mydc = GetDC(myconsole);
int pixel =0;
//Choose any color
COLORREF COLOR= RGB(255,255,255);
//Draw pixels
for(double i = 0; i < PI * 4; i += 0.05)
{
SetPixel(mydc,pixel,(int)(50+25*cos(i)),COLOR);
pixel+=1;
}
ReleaseDC(myconsole, mydc);
cin.ignore();
return 0;
}
You can also use some others libraries like: conio.h allegro.h sdl, etc.
If you're willing to have the image look blocky, you could take advantage of the block characters from the console code page.
█ = '\xDB' = U+2588 FULL BLOCK
▄ = '\xDC' = U+2584 LOWER HALF BLOCK
▀ = '\xDF' = U+2580 UPPER HALF BLOCK
and space
By using the half-blocks in combination with colored text, you can turn an 80×25 console window into an 80×50 16-color display. (This was the approach used by the QBasic version of Nibbles.)
Then, you just need to convert your image to the 16-color palette and a reasonably small size.
windows.h provides a function SetPixel() to print a pixel at specified location of a window. The general form of the function is
SetPixel(HDC hdc, int x, int y, COLORREF& color);
where, x and y are coordinates of pixel to be display and color is the color of pixel.
Important: to print the pixel in your machine with Code::blocks IDE, add a link library libgdi32.a (it is usually inside MinGW\lib ) in linker setting.
Console is a text device, so in general you don't write to individual pixels. You can create a special font and select it as a font for console, but it will be monochromatic. There are libraries which simplify writing console UI (e.g. Curses), but I believe that you also have more gamelike functionality in mind besides just showing a sprite.
if you want to write a game, I suggest taking a look at some of the graphics/game frameworks/libs, e.g. SDL
I have drawn the straight line using windows.h in code::blocks. I can't explain it in details, but I can provide you a code and procedure to compile it in code::blocks.
go to setting menu and select compiler and debugger.
Click on linker tab and add a link library libgdi32.a which is at C:\Program Files\CodeBlocks\MinGW\lib directory.
Now compile this program
#include <windows.h>
#include <cmath>
#define ROUND(a) ((int) (a + 0.5))
/* set window handle */
static HWND sHwnd;
static COLORREF redColor=RGB(255,0,0);
static COLORREF blueColor=RGB(0,0,255);
static COLORREF greenColor=RGB(0,255,0);
void SetWindowHandle(HWND hwnd){
sHwnd=hwnd;
}
/* SetPixel */
void setPixel(int x,int y,COLORREF& color=redColor){
if(sHwnd==NULL){
MessageBox(NULL,"sHwnd was not initialized !","Error",MB_OK|MB_ICONERROR);
exit(0);
}
HDC hdc=GetDC(sHwnd);
SetPixel(hdc,x,y,color);
ReleaseDC(sHwnd,hdc);
return;
// NEVERREACH //
}
void drawLineDDA(int xa, int ya, int xb, int yb){
int dx = xb - xa, dy = yb - ya, steps, k;
float xIncrement, yIncrement, x = xa, y = ya;
if(abs(dx) > abs(dy)) steps = abs(dx);
else steps = abs(dy);
xIncrement = dx / (float) steps;
yIncrement = dy / (float) steps;
setPixel(ROUND(x), ROUND(y));
for(int k = 0; k < steps; k++){
x += xIncrement;
y += yIncrement;
setPixel(x, y);
}
}
/* Window Procedure WndProc */
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam){
switch(message){
case WM_PAINT:
SetWindowHandle(hwnd);
drawLineDDA(10, 20, 250, 300);
break;
case WM_CLOSE: // FAIL THROUGH to call DefWindowProc
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
break; // FAIL to call DefWindowProc //
}
return DefWindowProc(hwnd,message,wParam,lParam);
}
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int iCmdShow){
static TCHAR szAppName[] = TEXT("Straight Line");
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW|CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
// Register the window //
if(!RegisterClass(&wndclass)){
MessageBox(NULL,"Registering the class failled","Error",MB_OK|MB_ICONERROR);
exit(0);
}
// CreateWindow //
HWND hwnd=CreateWindow(szAppName,"DDA - Programming Techniques",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
if(!hwnd){
MessageBox(NULL,"Window Creation Failed!","Error",MB_OK);
exit(0);
}
// ShowWindow and UpdateWindow //
ShowWindow(hwnd,iCmdShow);
UpdateWindow(hwnd);
// Message Loop //
MSG msg;
while(GetMessage(&msg,NULL,0,0)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
/* return no error to the operating system */
return 0;
}
In this program I have used DDA line drawing algorithm. Pixel drawing tasks is done by setPixel(ROUND(x), ROUND(y)) function.
This is windows programing which you can learn details here
To use in CodeBlocks I found this (you have to add a linker option -lgdi32):
//Code Blocks: Project Build Options Linker settings Othoer linker options: add -lgdi32
I forgot: You have to put this before including windows.h:
#define _WIN32_WINNT 0x0500
The whole cosine code again. Ready to compile:
//Code Blocks: Project Build Options Linker settings Othoer linker options: add -lgdi32
#define _WIN32_WINNT 0x0500
#include "windows.h"
#include <iostream>
#include <cmath>
using namespace std;
#define PI 3.14
int main(){
HWND myconsole = GetConsoleWindow();
HDC mydc = GetDC(myconsole);
int pixel =0;
COLORREF COLOR= RGB(255,255,255);
//Draw pixels
for(double i = 0; i < PI * 4; i += 0.05)
{
SetPixel(mydc,pixel,(int)(50+25*cos(i)),COLOR);
pixel+=1;
}
ReleaseDC(myconsole, mydc);
cin.ignore();
return 0;
}
I'm facing quite a dilemma. I've injected my DLL into other process as well as hooked few
WinAPI calls from there, ExtTextOutW#GDI32, DrawTextExW#GDI32 and AlphaBlend#Msimg32 to be specific. Now, the problem is that when the other application writes something with those two GDI32 functions, i don't know the exact location where it comes up. This is because the DC which contains the text gets processed with AlphaBlend, which also eventually puts it to the window's DC.
So, how can I track certain HDC? In pseudo code, here's how the other application draws
text to the screen:
HDC h = DrawTextW("STRING")
Do something with h. The "STRING" gets new HDC, say h2.
Pass h2 to AlphaBlend, which draws it to the screen.
Like I said, I loose track with the original h as the string gets new DC before AlphaBlend.
Any idea, how I can make a connection from h > h2 with certain string in it?
I don't know if I was able to explain the problem properly, please ask if you've got any questions...
static BOOL (WINAPI *AlphaBlend_t)(
HDC hdcDest,
int nXOriginDest,
int nYOriginDest,
int nWidthDest,
int nHeightDest,
HDC hdcSrc,
int nXOriginSrc,
int nYOriginSrc,
int nWidthSrc,
int nHeightSrc,
BLENDFUNCTION blendFunction
) = AlphaBlend;
BOOL MyAlphaBlend(
HDC hdcDest,
int nXOriginDest,
int nYOriginDest,
int nWidthDest,
int nHeightDest,
HDC hdcSrc,
int nXOriginSrc,
int nYOriginSrc,
int nWidthSrc,
int nHeightSrc,
BLENDFUNCTION blendFunction
)
{
// modify hdcDest to hdcDest2
return AlphaBlend_t(hdcDest2, ...);
}
That should do the trick. Put in any code to modify the HDC in the latter function.