Find color at current mouse location

Just starting out? Need help? Post your questions and find answers here.
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3943
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Find color at current mouse location

Post by wilbert »

I'm looking for a cross platform way to find the color of the pixel at the current mouse location (even outside the application window).
Does anyone have an idea how to do this ?
Especially Linux seems complicated to me :?
Last edited by wilbert on Fri Apr 08, 2016 6:47 am, edited 1 time in total.
Windows (x64)
Raspberry Pi OS (Arm64)
infratec
Always Here
Always Here
Posts: 7662
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Find color at current mouse location

Post by infratec »

Windows solution

Code: Select all

; Samplecode to get the color of a Pixel on the Desktop
; by PureLust for PureBasic-Forum - 18.09.2009 (with thanks to netmaestro)  ;)
; extended by infratec, optimized by idle

OpenWindow(0, 0, 0, 200, 20, "", #PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_ScreenCentered)

TextGadget(0, 0, 3, 200, 20, "", #PB_Text_Center)


HDC = GetDC_(0)


Repeat
 Event = WaitWindowEvent(100)
  
 x = DesktopMouseX()
 y = DesktopMouseY()
 PixelColour = GetPixel_(hDC,x,y)
 Red = Red(PixelColour)
 Green = Green(PixelColour)
 Blue = Blue(PixelColour)
 PixelColour$ = "#" + RSet(Hex(Red), 2, "0") + RSet(Hex(Green), 2, "0") + RSet(Hex(Blue), 2, "0") 
 If WindowHeight(0) > 10
  SetWindowTitle(0, "GetPixelColour")
  PixelColour$ + " (" + Str(Red) + ", " + Str(Green) + ", " + Str(Blue) + ")"
  SetGadgetText(0, Str(x) + ","+ Str(y) +" : " + PixelColour$)
 Else
  SetWindowTitle(0, PixelColour$)
 EndIf
 
Until Event = #PB_Event_CloseWindow

ReleaseDC_(0,HDC)
Bernd
Last edited by infratec on Fri Apr 08, 2016 6:49 am, edited 2 times in total.
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3943
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Find color at current mouse location

Post by wilbert »

Thanks :)
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
Keya
Addict
Addict
Posts: 1890
Joined: Thu Jun 04, 2015 7:10 am

Re: Find color at current mouse location

Post by Keya »

not sure about Linux either sorry but i got better results when adding GTK to my search!
perhaps this? http://rosettacode.org/wiki/Color_of_a_screen_pixel

Code: Select all

import gtk2, gdk2, gdk2pixbuf
gtk2.nim_init()
 
proc getPixelColor(x, y: int32): auto =
  var p = pixbufNew(COLORSPACE_RGB, false, 8, 1, 1)
  discard p.getFromDrawable(getDefaultRootWindow().Drawable,
    getDefaultScreen().getSystemColormap(), x, y, 0, 0, 1, 1)
  result = cast[tuple[r, g, b: uint8]](p.getPixels[])
 
echo getPixelColor(0, 0)

Code: Select all

def get_pixel_colour(i_x, i_y):
	import gtk # python-gtk2
	o_gdk_pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, 1, 1)
	o_gdk_pixbuf.get_from_drawable(gtk.gdk.get_default_root_window(), gtk.gdk.colormap_get_system(), i_x, i_y, 0, 0, 1, 1)
	return tuple(o_gdk_pixbuf.get_pixels_array().tolist()[0][0])
 
print get_pixel_colour(0, 0)
returns answer in GdkPixbuf arrayish object http://gtk.php.net/manual/en/gdk.gdkpix ... awable.php:

Code: Select all

GdkPixbuf get_from_drawable(GdkWindow src, GdkColormap cmap, int src_x, int src_y, int dest_x, int dest_y, int width, int height);
Google also suggests you'd be the very first person to use this API in Purebasic! but i think there might be some GdkPixbuf-based Purebasic code at least
Joris
Addict
Addict
Posts: 890
Joined: Fri Oct 16, 2009 10:12 am
Location: BE

Re: Find color at current mouse location

Post by Joris »

Wilbert ? Er is toch :

Color = Point(x, y)
Return the color of a pixel in the current output.

Supported OS
All
Yeah I know, but keep in mind ... Leonardo da Vinci was also an autodidact.
User avatar
Keya
Addict
Addict
Posts: 1890
Joined: Thu Jun 04, 2015 7:10 am

Re: Find color at current mouse location

Post by Keya »

Joris: oh yeah! :oops: :)
i had a look at a linux binary created thats just "x=Point(0,0)" but i cant see what function its using in a hex editor!
hm but i guess wilbert also needs to know not just the pixel at x,y, but also where the cursor is
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3943
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Find color at current mouse location

Post by wilbert »

Point() only works within StartDrawing() / StopDrawing() so you can't access any pixel on the desktop.

Haven't tried Linux yet but am having a lot of problems on finding a way on OSX x64 as well.
Most methods I can find like using CGWindowListCreateImage() or NSReadPixel() require structures like CGRect or NSPoint to be passed by value which PB doesn't support. :?
Capturing the whole screen might be a possibility but seems a bit much if you only need one pixel.
Windows (x64)
Raspberry Pi OS (Arm64)
Joris
Addict
Addict
Posts: 890
Joined: Fri Oct 16, 2009 10:12 am
Location: BE

Re: Find color at current mouse location

Post by Joris »

wilbert wrote:Point() only works within StartDrawing() / StopDrawing() so you can't access any pixel on the desktop....
I see, but then isn't StartDrawing not returning the DC ? Then you just need the handle.
I'm in doubt now... it's been a while.
Yeah I know, but keep in mind ... Leonardo da Vinci was also an autodidact.
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3943
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Find color at current mouse location

Post by wilbert »

I found a way for OSX x64 but it was complicated to get it working; had to use asm to work around the problem of OSX not supporting passing of structures by value.

Code: Select all

; OSX 64 bit

ImportC ""
  CGBitmapContextCreate(*bdata, width, height, bitsPerComponent, bytesPerRow, cs, bitmapInfo)
  CGColorSpaceCreateDeviceRGB()
  CGColorSpaceRelease(cs)
  CGContextRelease(c)
  CGImageRelease(image)  
EndImport

Procedure CGContextDrawImage_addr()
  ProcedureReturn ?cgcdi_start
  cgcdi_start:
  !extern _CGContextDrawImage
  !sub rsp, 40
  !movq [rsp     ], xmm0
  !movq [rsp +  8], xmm1
  !movq [rsp + 16], xmm2
  !movq [rsp + 24], xmm3
  !call _CGContextDrawImage
  !add rsp, 40
  !ret
EndProcedure

Procedure CGWindowListCreateImage_addr()
  ProcedureReturn ?cgwlci_start
  cgwlci_start:
  !extern _CGWindowListCreateImage
  !sub rsp, 40
  !movq [rsp     ], xmm0
  !movq [rsp +  8], xmm1
  !movq [rsp + 16], xmm2
  !movq [rsp + 24], xmm3
  !call _CGWindowListCreateImage
  !add rsp, 40
  !ret
EndProcedure

Prototype CGContextDrawImage_proto(c, x.d, y.d, w.d, h.d, image)
Prototype CGWindowListCreateImage_proto(x.d, y.d, w.d, h.d, listOption, windowID, imageOption)
Global CGWindowListCreateImage.CGWindowListCreateImage_proto = CGWindowListCreateImage_addr()
Global CGContextDrawImage.CGContextDrawImage_proto = CGContextDrawImage_addr()

Procedure.l GetColorUnderMouse()
  Protected.i image, csRGB, ctx, c.l
  image = CGWindowListCreateImage(DesktopMouseX(), DesktopMouseY(), 1, 1, 1, 0, 0)
  csRGB = CGColorSpaceCreateDeviceRGB()
  ctx = CGBitmapContextCreate(@c, 1, 1, 8, 4, csRGB, 1)
  CGContextDrawImage(ctx, 0, 0, 1, 1, image)
  CGColorSpaceRelease(csRGB)
  CGImageRelease(image)
  CGContextRelease(ctx)
  ProcedureReturn c
EndProcedure
or a bit shorter

Code: Select all

; OSX 64 bit

ImportC ""
  CGBitmapContextCreate(*bdata, width, height, bitsPerComponent, bytesPerRow, cs, bitmapInfo)
  CGColorSpaceCreateDeviceRGB()
  CGColorSpaceRelease(cs)
  CGContextRelease(c)
  CGImageRelease(image)  
EndImport

Procedure.l GetColorUnderMouse()
  Protected.i image, csRGB, ctx
  Protected c.l, x.d, y.d, one.d = 1
  x = DesktopMouseX()
  y = DesktopMouseY()
  csRGB = CGColorSpaceCreateDeviceRGB()
  ctx = CGBitmapContextCreate(@c, 1, 1, 8, 4, csRGB, 1)
  CGColorSpaceRelease(csRGB)
  !extern _CGContextDrawImage
  !extern _CGWindowListCreateImage
  !movsd xmm0, [p.v_x]
  !movsd xmm1, [p.v_y]
  !movsd xmm2, [p.v_one]
  !sub rsp, 32
  !movsd [rsp     ], xmm0
  !movsd [rsp +  8], xmm1
  !movsd [rsp + 16], xmm2
  !movsd [rsp + 24], xmm2
  !mov rdi, 1
  !xor rsi, rsi
  !xor rdx, rdx
  !call _CGWindowListCreateImage
  !add rsp, 32
  !mov [p.v_image], rax
  !mov rdi, [p.v_ctx]
  !mov rsi, rax
  !pxor xmm0, xmm0
  !movsd xmm2, [p.v_one]
  !sub rsp, 32
  !movupd [rsp], xmm0
  !movsd [rsp + 16], xmm2
  !movsd [rsp + 24], xmm2  
  !call _CGContextDrawImage
  !add rsp, 32
  CGImageRelease(image)
  CGContextRelease(ctx)
  ProcedureReturn c
EndProcedure
Windows (x64)
Raspberry Pi OS (Arm64)
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3943
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Find color at current mouse location

Post by wilbert »

This seems to work on Linux gtk3 except that it only works for the main screen.

Code: Select all

ImportC ""
  gdk_pixbuf_get_from_window(window, x, y, width, height)
  gdk_pixbuf_get_pixels(pixbuf)
EndImport

Procedure.l GetColorUnderMouse()
  Protected.i pixbuf, *buf.Ascii, c.l
  pixbuf = gdk_pixbuf_get_from_window(gdk_get_default_root_window_(), DesktopMouseX(), DesktopMouseY(), 1, 1)
  *buf = gdk_pixbuf_get_pixels(pixbuf)
  c = *buf\a : *buf + 1
  c | *buf\a << 8 : *buf + 1
  c | *buf\a << 16
  g_object_unref_(pixbuf)
  ProcedureReturn c
EndProcedure
If someone knows a solution that works across multiple monitors, please let me know.
Windows (x64)
Raspberry Pi OS (Arm64)
Oma
Enthusiast
Enthusiast
Posts: 312
Joined: Thu Jun 26, 2014 9:17 am
Location: Germany

Re: Find color at current mouse location

Post by Oma »

Hi Wilbert!
First of all thank you for the routines.
... it only works for the main screen. If someone knows a solution that works across multiple monitors, please let me know.
I now have tested your Linux version on many distributions.
Your picker routine works everywhere on both monitors and if you make the parent window (from picker) sticky, even on all desktops. However, the picker window must of course have the focus. I trigger the picker from the space-bar.

You are talking about monitors and screens in Linux. There are still the terms display and desktop in the API so it's slightly confusing what you mean exactly?

Best regards, Charly
PureBasic 5.4-5.7, Linux: (X/L/K)Ubuntus+Mint - Windows XP (32Bit)
PureBasic Linux-API-Library & Viewer: http://www.chabba.de
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3943
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Find color at current mouse location

Post by wilbert »

Hi Charly,
Oma wrote:Your picker routine works everywhere on both monitors and if you make the parent window (from picker) sticky, even on all desktops. However, the picker window must of course have the focus. I trigger the picker from the space-bar.
Thanks for your feedback. I forgot to post about the cause.
Shardik also confirmed it worked. My conclusion is that it has to do with the fact that I'm running Linux inside a Parallels VM.
Unfortunately this can cause unwanted limitations sometimes. :(
Windows (x64)
Raspberry Pi OS (Arm64)
Post Reply