Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

PixelGetColor gets the wrong color


  • Please log in to reply
11 replies to this topic
Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
Show a Gui window with transparent background, but opaque controls. PixelGetColor returns the color of the pixel under the control (not the color of the control), which is not what we see on screen. It needs to be clarified in the help.
CoordMode Mouse, Screen

Gui Color,012345
Gui Add, Button, W60 H60
Gui Show, X200 Y0 W82 H80, xxx
Winset Transcolor, 012345, xxx

Loop
{
   MouseGetPos X, Y
   PixelGetColor Color, X, Y
   TrayTip,,<%Color%>
   Sleep 100
}

Is there an easy way to get the color of a visible pixel belonging to a partially transparent window?

Chris
  • Administrators
  • 10727 posts
  • Last active:
  • Joined: 02 Mar 2004
PixelGetColor is simply a wrapper for the OS's GetPixel() function. Here is the code behind it (converted to DllCall). Maybe you can tweak it do better things by giving it a different HDC (such as a window's).
hdc := DllCall("GetDC", "uint", 0)
if hdc
{
	ColorBGR := DllCall("GetPixel", "uint", hdc, "int", 100, "int", 10) ; Specify the pixel's screen coords.
	DllCall("ReleaseDC", "uint", 0, "uint", hdc)
	MsgBox %ColorBGR%
}
Concerning the docs, this would be a case of documenting something that isn't even documented at MSDN, so the behavior might vary from system to system (depending on video driver, for example). Maybe some kind of non-specific cautionary wording can be added. Suggestions are welcome.

PhiLho
  • Moderators
  • 6850 posts
  • Last active: Jan 02 2012 10:09 PM
  • Joined: 27 Dec 2005
Interesting.
Actually, I am not sure if that is tied to transparency.
If I put, for example, w300 and remove transparency, I get random results over the GUI area (outside the button), and even outside the GUI.
#Persistent
CoordMode Mouse, Screen

SetTimer ShowColor, 500

ShowColor:
   MouseGetPos x, y
   PixelGetColor color, x, y
   ToolTip %color%
Return
I have often 0xFFFFFF and sometime 0xFFFFFFFF (32bit value). Oh, the last value is CLR_INVALID (-1).
Over a SciTE window, I have CLR_INVALID everywhere...
I never tested this command before, but it seems quite unreliable... At least on my system (WinXP Home SP2, ATI Radeon 9250).
Posted Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")

PhiLho
  • Moderators
  • 6850 posts
  • Last active: Jan 02 2012 10:09 PM
  • Joined: 27 Dec 2005
I searched how others pick colors on screen.
I found a CodeProject article explaining one technique: it uses GetPixel, indeed, but it creates a DC using hDC = CreateDC("DISPLAY",0,0,0);. Perhaps that's the main difference.
I tested the provided exe and it works quite well, including over SciTE...
#SingleInstance Force

#Persistent
CoordMode Mouse, Screen

offsetX = -40
offsetY = 0

hDC := DllCall("CreateDC", "Str", "DISPLAY", "UInt", 0, "UInt", 0, "UInt", 0)
If hDC = 0
{
	MsgBox 16, GetPixel, Cannot create DISPLAY's DC
	ExitApp
}

SetTimer ShowColor, 500

ShowColor:
	MouseGetPos x, y
	SetFormat Integer, D
	coords :=" (" . (x + offsetX) . ", " . (y + offsetY) . ")"
	SetFormat Integer, Hex
	PixelGetColor color, x + offsetX, y + offsetY, RGB
	If (color = 0xFFFFFFFF)
		color = Invalid!
	colorBGR := DllCall("GetPixel", "UInt", hDC, "Int", x + offsetX, "Int", y + offsetY)
	If (colorBGR = 0xFFFFFFFF)
	{
		ToolTip %coords% Invalid! / %color%
	}
	Else
	{
		colorBGR += 0x1000000
		StringUpper colorBGR, colorBGR
;~ 		StringTrimLeft colorBGR, colorBGR, 3
;~ 		ToolTip %colorBGR%
		 StringMid b, colorBGR, 4, 2
		 StringMid g, colorBGR, 6, 2
		 StringMid r, colorBGR, 8, 2
		 ToolTip %coords% %r% %g% %b% / %color%
	}
Return

Escape::
DllCall("DeleteDC", "UInt", hDC)
ExitApp

Posted Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")

Chris
  • Administrators
  • 10727 posts
  • Last active:
  • Joined: 02 Mar 2004
It could be that the cursor is blocking the mouse somehow. You might try using PixelGetColor on a pixel that is definitely not under the mouse cursor.

If PixelGetColor is unreliable as you suggest, that would be a pretty big surprise because it has been a command since the beta versions of AHK in December 2003, yet there have been no complaints about its reliability (except in certain games, where a few have said it always gets a black pixel).

By contrast, there have been complaints about the performance of PixelGetColor. So I'd be hesitant to change it to a potentially slower method, especially if there's a chance it would break existing scripts by extracting different colors from games and other apps.

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
PhiLho's script works more reliably than PixelgetColor in normal windows, but on the button in my partially transparent Gui window, it fails, too.

It could be that the cursor is blocking the mouse somehow. You might try using PixelGetColor on a pixel that is definitely not under the mouse cursor.

It is not the cursor. Even if I get the pixel color from x-60, y-60 of the cursor coordinates, it is the same, getting the pixel colors underneath, not the visible one.

If PixelGetColor is unreliable as you suggest, that would be a pretty big surprise because it has been a command since the beta versions of AHK in December 2003, yet there have been no complaints about its reliability...

Why don't you just try the script I posted to demonstrate the problem. If you think, getting the color of a covered pixel (instead of the visible one) is the right behavior, it has to be documented, because most of us would expect otherwise.

I tried the script on different computers (all XP SP2). They behave identically, so it is unlikely a video driver problem.

PhiLho
  • Moderators
  • 6850 posts
  • Last active: Jan 02 2012 10:09 PM
  • Joined: 27 Dec 2005
I forgot to test again your GUI problem...
Well, it acts like all the GUI is transparent, including the title bar... Perhaps Windows see the whole window as transparent (for GetPixel at least), even if it displays some parts as opaque. Strange...
Posted Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")

Chris
  • Administrators
  • 10727 posts
  • Last active:
  • Joined: 02 Mar 2004
Laszlo, I should clarify that my previous post was in response to PhiLho's two posts, not yours. Sorry if it caused any misunderstanding.

Why don't you just try the script I posted to demonstrate the problem.

I never doubted that what you said was true; sorry if I gave you another impression.

If you think, getting the color of a covered pixel (instead of the visible one) is the right behavior, it has to be documented, because most of us would expect otherwise.

All I said was that I don't know what the correct behavior is because MSDN doesn't document it. :)

I tried the script on different computers (all XP SP2). They behave identically, so it is unlikely a video driver problem.

Thanks. I'll document this as a known limitation.

If anyone else has noticed unreliability with PixelGetColor in normal windows (not games or transparent windows), please let me know.

Thanks.

Micha
  • Members
  • 539 posts
  • Last active: Dec 31 2011 01:43 PM
  • Joined: 15 Nov 2005
Hi PhiLho,
i've tried your script:

black -> 0 0 0
red ->00 00 ff
cyan ->00 ff ff
blue -> 00 00 ff
green ->00 00 80

Red and blue have the same values. When changing the tooltip to show
ToolTip, %colorBGR%
it shows the correct values 0xff and 0x0000ff

Just what I have noticed

Ciao
Micha

PhiLho
  • Moderators
  • 6850 posts
  • Last active: Jan 02 2012 10:09 PM
  • Joined: 27 Dec 2005
Micha, you were right, there was a strange bug I didn't care to fully understand. Anyway, I wanted to use a trick given by Laszlo, giving a simplier code, giving correct results.
I updated the code above. Thanks for pointing that out.
Mmm, I even updated the code to show in parallel the results of the DllCall and those of PixelGetColor.

If anyone else has noticed unreliability with PixelGetColor in normal windows (not games or transparent windows), please let me know.

I already pointed out a problem with SciTE, where all results are "CLR_INVALID" or 0xFFFFFF.
With my new version, I tested in Win98SE, with an offset to be sure of no interference with the cursor (although you mention it should make no difference outside games).
The results are very strange...
For example, over the AutoHotkey Help window, the results are consistent when the window is active, but when it becomes inactive, PixelGetColor (PGC) gives seemingly random results, mostly 0xFFFFFF.
Starting Wordpad, over the title bar, the result of PGC varies depending where the bar is...
Sometime, both results are stuck on 0xFFFFFF, then restart of behave correctly.

I can't test on WinXP right now, but I will update this post when I will get the opportunity.

Please, try and test my little snippet, to see if there is a problem only on my systems/applications/themes/color schemes/whatever.
Posted Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")

cqcqcqn
  • Members
  • 1 posts
  • Last active: Jan 06 2010 01:37 AM
  • Joined: 06 Jan 2010
....俺一点也没看懂

svi
  • Members
  • 237 posts
  • Last active: Mar 09 2015 06:34 PM
  • Joined: 09 Oct 2006
Since this old thread has been bumbed, I'd like to tell my opinion about the reliability of PixelGetColor:
It seems that no one of those famous posters didn't notice a simple thing although...

For example, over the AutoHotkey Help window, the results are consistent when the window is active, but when it becomes inactive, PixelGetColor (PGC) gives seemingly random results, mostly 0xFFFFFF.

For if you specify
CoordMode Mouse, Screen
, you should also specify
CoordMode Pixel, Screen
.
I found this months ago, but didn't want to bump it (to be not regarded as a "besserwisser") :roll:
Pekka Vartto