c++ GetPixel returning wrong values [duplicate] - c++

This is my first post on this forum, please don't go hard on me if I didn't post it in the right place or if I did something wrong, I don't post in forums very much. So, I have this problem with GetPixel function. Basically, it should return the color decimal at x, y. The code I am about to post works perfectly on windows 7 32bit, but recently I bought a new laptop y50-70 with windows 8.1 64bit and the same code works completely different. I can't find any solution to the problem, can't even describe it. I think it could have something to do with desktop handle, HDC, GetDC(), GetPixel(), maybe even with my computer resolution, refresh rate or something like that... I have even recorded some videos which could help you understand the problem I am having because I can't even describe it correctly. It is like the real color is x = 219, y = 407 away from the place, where my mouse is pointing. The new laptop is 3 weeks old, I even tried to do system restore 1 time, but that didn't solve the problem.
Feel free to use this code, hope it will work fine for you:
#include <iostream>
#include <Windows.h>
using namespace std;
void Detect();
int main()
{
Detect();
return 0;
}
void Detect()
{
POINT p;
HDC hDC = GetDC(0);
int x, y;
while (!GetAsyncKeyState(VK_INSERT)) // Press insert to stop
{
GetCursorPos(&p);
x = p.x;
y = p.y;
hDC = GetDC(0);
cout << x << " " << y << " " << GetPixel(hDC, x, y) << endl;
Sleep(50);
}
ReleaseDC(0, hDC);
}
Links to the problem below:
https://youtu.be/q2H2M8WLHVI
https://youtu.be/UcneHwXaGoM
If anyone could at least help somehow or tell what to do, where to go, I would very, very much appreaciate it. One of the main reasons why I started programming is because something like this, working with colours, conditions, etc... and now I can't advance further which is really sad. Hope to hear a reply. Thank you.

This is probably an issue with DPI scaling.
If your new monitor has a higher-than-average number of dots per inch, then Windows, by default, will stretch the graphics. By default, Windows assumes that programs ignore the DPI. If Windows didn't stretch the graphics, then programs that didn't adjust for the DPI would have tiny text in tiny windows on high-density displays.
This is a bit of a hack. Some of the Windows APIs and messages that let you ask about the display and windows will translate the coordinates between an "average" 96 pixels-per-inch and whatever the actual DPI is for the monitor. Likewise, the APIs that let you size things do the opposite transformation. So this is all largely transparent to the program. But it's not perfect because not all the APIs can do the scaling in a consistent manner.
So my guess is that your laptop has a high-resolution display, GetPixel doesn't translate coordinates for DPI scaling, and the mouse position is transformed for DPI scaling. The result is that you're asking for a pixel that doesn't really line up with the mouse.
My suggested solution is the tell windows that your program is "DPI-aware". There are several ways to do this. The easiest in your case might be to call SetProcessDPIAware right at the beginning of your program. You could also do this be marking your program in the manifest. Depending on the compiler you're using, there might be a command line option to create the manifest you need automatically.

Another alternative that has worked for me, is to change a setting in the Control Panel, to disable per-device DPI Scaling. Are you running multiple monitors?
Win 8.1 introduced a new setting in the Control Panel, which says "Let me choose one DPI scaling for all displays". By defualt this is turned off. Turning it on has worked for me.
See this video to find the setting:
https://www.youtube.com/watch?v=sE3IUTPy1WA
I'm curious, so let me know if that works for you, when you don't use SetProccesDPIAware()

Related

GetPixel returns incorrect values

This is my first post on this forum, please don't go hard on me if I didn't post it in the right place or if I did something wrong, I don't post in forums very much. So, I have this problem with GetPixel function. Basically, it should return the color decimal at x, y. The code I am about to post works perfectly on windows 7 32bit, but recently I bought a new laptop y50-70 with windows 8.1 64bit and the same code works completely different. I can't find any solution to the problem, can't even describe it. I think it could have something to do with desktop handle, HDC, GetDC(), GetPixel(), maybe even with my computer resolution, refresh rate or something like that... I have even recorded some videos which could help you understand the problem I am having because I can't even describe it correctly. It is like the real color is x = 219, y = 407 away from the place, where my mouse is pointing. The new laptop is 3 weeks old, I even tried to do system restore 1 time, but that didn't solve the problem.
Feel free to use this code, hope it will work fine for you:
#include <iostream>
#include <Windows.h>
using namespace std;
void Detect();
int main()
{
Detect();
return 0;
}
void Detect()
{
POINT p;
HDC hDC = GetDC(0);
int x, y;
while (!GetAsyncKeyState(VK_INSERT)) // Press insert to stop
{
GetCursorPos(&p);
x = p.x;
y = p.y;
hDC = GetDC(0);
cout << x << " " << y << " " << GetPixel(hDC, x, y) << endl;
Sleep(50);
}
ReleaseDC(0, hDC);
}
Links to the problem below:
https://youtu.be/q2H2M8WLHVI
https://youtu.be/UcneHwXaGoM
If anyone could at least help somehow or tell what to do, where to go, I would very, very much appreaciate it. One of the main reasons why I started programming is because something like this, working with colours, conditions, etc... and now I can't advance further which is really sad. Hope to hear a reply. Thank you.
This is probably an issue with DPI scaling.
If your new monitor has a higher-than-average number of dots per inch, then Windows, by default, will stretch the graphics. By default, Windows assumes that programs ignore the DPI. If Windows didn't stretch the graphics, then programs that didn't adjust for the DPI would have tiny text in tiny windows on high-density displays.
This is a bit of a hack. Some of the Windows APIs and messages that let you ask about the display and windows will translate the coordinates between an "average" 96 pixels-per-inch and whatever the actual DPI is for the monitor. Likewise, the APIs that let you size things do the opposite transformation. So this is all largely transparent to the program. But it's not perfect because not all the APIs can do the scaling in a consistent manner.
So my guess is that your laptop has a high-resolution display, GetPixel doesn't translate coordinates for DPI scaling, and the mouse position is transformed for DPI scaling. The result is that you're asking for a pixel that doesn't really line up with the mouse.
My suggested solution is the tell windows that your program is "DPI-aware". There are several ways to do this. The easiest in your case might be to call SetProcessDPIAware right at the beginning of your program. You could also do this be marking your program in the manifest. Depending on the compiler you're using, there might be a command line option to create the manifest you need automatically.
Another alternative that has worked for me, is to change a setting in the Control Panel, to disable per-device DPI Scaling. Are you running multiple monitors?
Win 8.1 introduced a new setting in the Control Panel, which says "Let me choose one DPI scaling for all displays". By defualt this is turned off. Turning it on has worked for me.
See this video to find the setting:
https://www.youtube.com/watch?v=sE3IUTPy1WA
I'm curious, so let me know if that works for you, when you don't use SetProccesDPIAware()

Unable to Draw in C++ on Raspberry Pi

I have, thanks to some help, managed to get the program below to compile and run but although it keeps on chugging away I cannot see anything drawn on the Pi's screen.
I don't think that it is a problem unique to the use of openvg and ajstarks code as, during the problem I had compiling the test progam, I tried a different way of writing images (sorry, all I remember was that it was low level and didn't need the includes for openvg). It took a bit of searching and re-writing to get it to compile and when it did the same thing happened.
I persevered for a while, but got no where. There were some references to some sort of limitation with Raspberry Pi and X Windows leading to the same problem. You draw something but it doesn't display. Given that there were several comments suggesting that openvg worked, I went back to that and (thanks to a guy called Ross) eventually worked out why I couldn't compile the code.
So now I am at a point where I can compile code that others have got to run successfully, but it doesn't draw anything on the screen. I know that the code runs - it chews CPU cycles (well the official demo does, mine less so although it's still definitly going) and the code can be quit with
Another method of working with graphics has come across the same no-output-display problem, so I think the problem is somewhere on my Pi but I have drawn a blank on how to address the X Windows (or it might have been X11, wish I had kept the tabs open!) not wanting to draw issue.
Any help greatly appreciated, thanks in advance!
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
extern "C" {
#include "VG/openvg.h"
#include "VG/vgu.h"
#include "fontinfo.h"
#include "shapes.h"
}
using namespace std;
int main (void) {
int width, height;
VGfloat w2, h2, w;
char s[3];
init(&width, &height); // Graphics initialization
w2 = (VGfloat)(width/2);
h2 = (VGfloat)(height/2);
w = (VGfloat)w;
Start(width, height); // Start the picture
Background(0, 0, 0); // Black background
Fill(44, 77, 232, 1); // Big blue marble
Circle(w2, 0, w); // The "world"
Fill(255, 255, 255, 1); // White text
TextMid(w2, h2, "hello, world", SerifTypeface, width/10); // Greetings
End(); // End the picture
fgets(s, 2, stdin); // Pause until RETURN]
finish(); // Graphics cleanup
exit(0);
}
Ok...
Thanks to a stroke of luck I have found the answer and it's odd. To me anyway...
In case anyone else encouters the problem, here is the (partial) solution which leads to another question to be posted shortly.
I am trying to run a programming club in my school and it's not practical to physically connect the Pi's to kb, mouse and monitor so they all auto-run VNC and we connect to the machines using Ultra-VNC. The programs are written in a shared directory and Eclipse C++ runs on the host; therefore all program output is viewed via VNC.
I had been continuing to try to solve the problem and at one point connected a keyboard and mouse and noticed that they seemed to be recognised (laser came on, Caps Lock toggled, etc.) but they didn't do anything when moved/typed on.
Eventually the penny began to teater on the edge as I got increasingly confused as to why no one else was having this problem. Is seemed odd that no one else had the issue and then I began to wonder more about the kb/mouse issue.
I tried plugging the HDMI output into a monitor at home (shool ones are still analogue d-sub!) and lo and behold, the physical kb and mouse worked. Then it got really strange!
Somehow I have 2 desktops running at the same time. The physical keyboard and mouse control one and VNC controls the other. Interestingly, VNC has the title Pi's X Desktop suggesting that the graphics problem might be something to do with X, but I am not sure for the reason below.
If I start a terminal window on 'Physical' desktop, it doesn't show up on 'VNC' desktop and vice versa - they seem to be independent, although that's not quite true.
When I run the test file on 'Physical' desktop, it works fine and can be controlled only using the physical kb. When I run it on 'VNC' desktop, it can be controlled only with the VNC kb but the output displays on the physical screen.
I really don't get this!
So, this answers the original question as the program does run on the Pi.
Off to post (hopefully a final) question on how to either get VNC to show the 'Physical' desktop or how to target the graphics output to the 'correct' desktop.

How to change screen resolution in DirectX 9

I'm trying to write a program using DirectX 9. As a part of this program I need a way to change screen resolution i.e. height and width for the DirectX device. I have a pointer to my LPDIRECT3DDEVICE9 stored, and I need a function that looks like this:
void SetResolution(int x, int y) {
// some code that actually changes the resolution
}
Surprisingly, I failed to find it on the internet. I also found this thread on this site, but the accepted answer is very vague and looks like a mix of WinAPI and DirectX.
You can recreate the device and pass updated params (see http://msdn.microsoft.com/en-us/library/windows/desktop/bb172588(v=vs.85).aspx)
It means you need to reload all your resources onto the graphics card though.

Is it possible to modify the origin of a display? (win32)

I have a number of applications which I cannot modify(no source), they are hard coded to draw at 0,0. Normally this is not a problem however a new project(kiosk) has come along where I need to draw a boarder around the outside of these applications. I am looking for a way to change display range from:
X: 0 to 1200
Y: 0 to 900
to something like:
X: -100 to 1100
Y: -100 to 800
I've seen a couple functions on MSDN like SetViewportExtEx, SetWorldTransform which fit the need however if I understand them correctly they don't do a system wide change. They are for the current process only.
I am programming in C++ but if there are settings in the registry/control panel/etc that would also work.
Has anyone else done anything like this before?
Edit 1: Window position is hard coded to 0,0
This might be overkill, but if it's something you really want to have complete control over, you could always use API hooking to intercept the Window creation by hooking CreateWindow, CreateWindowEx in the target process and altering the X Y coordinates before passing control back to the system.
Popular API hooking libraries include: Microsoft Detours, Madshi's madCodeHook, and the free, open source EasyHook.
Could you clarify what you mean by 'the applications are hard coded to draw at 0,0'? Does this mean that the position of their windows is set to 0,0, or do they have code to paint at 0,0?
Solution #1
One possible solution would be to use SetWindowPosition to simply move each of the applications to whatever position you desire.
All you would need to do is enumerate the list of HWNDS calling SetWindowPosition on each as necessary.
Solution #2
Set the working area of the desktop to be smaller. This should cause your applications to take up the working area, not the entire screen. You would then be free to put up any additional windows you need, manually position them, and draw your border.
In fact you might consider registering your border windows as 'app bars' which would automatically resize the working area.
The route I might take is making a shell application with a window and then setting the parent of the other using "SetParent"
for instance, in C# I did this...
var info = new ProcessStartInfo {FileName = "NotePad.exe", WindowStyle = ProcessWindowStyle.Normal};
var runProcess = Process.Start(info);
Thread.Sleep(1000); // ugly, but more just proving a point
SetParent(runProcess.MainWindowHandle, Handle);
and it hosted notepad in my forms window
So, Simply host the window, resize your host to the clients size + a bit, position the client in your host window where you want, and then draw around the outside.
easy peasy :)

How do I determine if a window is off-screen?

In Windows XP and above, given a window handle (HWND), how can I tell if the window position and size leaves the window irretrievably off screen? For example, if the title bar is available to the cursor, then the window can be dragged back on screen. I need to discover if the window is in fact visible or at least available to the user. I guess I also need to know how to detect and respond to resolution changes and how to deal with multiple monitors. This seems like a fairly big deal. I'm using C++ and the regular SDK, so please limit your answers to that platform rather than invoking C# or similar.
Windows makes it relatively simple to determine the size of a user's working area on the primary monitor (i.e., the area of the screen not obscured by the taskbar). Call the SystemParametersInfo function and specify the SPI_GETWORKAREA flag for the first parameter (uiAction). The pvParam parameter should point to a RECT structure that will receive the coordinates of the working area in virtual screen coordinates.
Once you've got the coordinates that describe the working area, it's a simple matter of comparing those to the current position of your application's window to determine if it lies within those bounds.
The desire to support multiple monitors makes things slightly more complicated. The documentation for SystemParametersInfo suggests that you need to call the GetMonitorInfo function instead to get the working area of a monitor other than the primary. It fills in a structure called MONITORINFOEX that contains the member rcWork that defines the working area of that monitor, again expressed in virtual screen coordinates as a RECT structure.
To do this right, you'll need to enumerate all of the monitors a user has connected to the system and retrieve the working area of each using GetMonitorInfo.
There are a few samples of this to be found around the Internet:
MSDN has some sample code for Positioning Objects on a Multiple Display Setup.
If you're using MFC, here's what looks to be an excellent example of multiple monitor support.
Even if you're not using MFC, that article refers the following link which looks be a real gem as far as explaining how multiple monitor supports works in Windows, even if it's a little bit old school. Like it or not, very little of this has changed in later versions of Windows.
Finally, you mentioned wanting to detect resolution changes. This is much simpler than you probably imagined. As you know if you've done any Windows programming, the primary way that the operating system communicates with your application is by sending messages to your WindowProc function.
In this case, you'll want to watch for the WM_DISPLAYCHANGE message, which is sent to all windows when the display resolution has changed. The wParam contains the new image depth in bits per pixel; the low-order word of the lParam specifies the horizontal resolution and the high-order word of the lParam specifies the vertical resolution of the screen.
You can use MonitorFromRect or MonitorFromPoint to check if window's top left point or bottom right point isn't contained within any display monitor (off screen).
POINT p;
p.x = x;
p.y = y;
HMONITOR hMon = MonitorFromPoint(p, MONITOR_DEFAULTTONULL);
if (hMon == NULL) {
// point is off screen
}
Visibility check is really easy.
RECT rtDesktop, rtView;
GetWindowRect( GetDesktopWindow(), &rtDesktop );
GetWindowRect( m_hWnd, &rtView );
HRGN rgn = CreateRectRgn( rtDesktop.left, rtDesktop.top, rtDesktop.right, rtDesktop.bottom );
BOOL viewIsVisible = RectInRegion( rgn, &rtView );
DeleteObject(rgn);
You don't have to use RectInRegion, I used for shorten code.
Display, resolution change monitoring is also easy if you handle WM_SETTINGCHANGE message.
http://msdn.microsoft.com/en-us/library/ms725497(v=vs.85).aspx
UPDATE
As #Cody Gray noted, I think WM_DISPLAYCHANGE is more appropriate than WM_SETTINGCHANGE. But MFC 9.0 library make use of WM_SETTINGCHANGE.