Version 1 of Get the color of the pixel under the pointer

Updated 2006-01-27 02:07:07

HJG I have some images on a canvas, and I want to get the color of the pixel under the cursor.

CLN Not to be too pendantic but you mean the pointer, right? The pointer is where the mouse is, the cursor is where text is placed.

HJG: Yupp, it is the mouse-pointer.

Right now, this works only for an image placed on the canvas at 0,0 :

  package require Img

  proc int x { expr int($x) }

  proc ShowPixel {x y i} {
    set c "- - -"
    catch { set c [$::img1 get $x $y] }
    wm title . "$x $y #$i : $c"

  proc ShowColor {w x y} {
  # idea: RS
    set color ""
    set id [$w find withtag current]
    if {$id>0} {
      set xx $x
      set yy $y
      foreach {x0 y0 x1 y1} [$w bbox $id] break
      incr xx -$x0
      incr yy -$x0
     #wm title . "$x $y #$id : $x0 $y0  $x1 $y1 : $xx $yy"

      switch -- [$w type $id] {
        image {set color [[$w itemcget $id -image] get $xx $yy]}
        line - polygon - rectangle - oval - text {
            set cName [$w itemcget $id -fill]
            set color [winfo rgb $w $cName]
      wm title . "$x $y #$id $xx $yy = $color"
    } else {
      wm title . "$x $y"

    #return $color

  set fn gosmall.gif
  set img1 [image create photo -file $fn]

  pack [canvas .c]
  .c create image  0  0 -image $img1 -anchor nw -tag Copy1
  .c create image 80 80 -image $img1 -anchor nw -tag Copy2

  .c create text  55  95  -text "ABC"     -fill white
  .c create rect 125  25  145  45         -fill red 
  .c create oval  25 125   45 145         -fill green
  .c create line  15 100   70 125         -fill blue
  .c create poly 100  65  130  65 100  20 -fill cyan -outline black

 #bind .c <Motion> { ShowPixel    [int [%W canvasx %x]] [int [%W canvasy %y]] [%W find withtag current] }
  bind .c <Motion> { ShowColor %W [int [%W canvasx %x]] [int [%W canvasy %y]] }

Using proc ShowPixel, the RGB-values of the pixel under the mouse-pointer are shown only for the first copy of the image...

I can query the coordinates of an item/image on the canvas with bbox (to adjust coordinates within the image vs. the screen-coordinates given by the pointer), but how do I pass the item (as opposed to its id) to the proc ShowPixel ?

RS: Pass in the widget name. For images you can retrieve the name as -image attribute.

HJG: Ok - proc ShowColor now does mostly what I wanted, but gives an error "coordinates out of range" at the edge of the images.

And for rect / oval etc. it would be nice to also get the RGB-values... - RS: That's precisely the job winfo rgb does :^)

HJG: Ok, but winfo returns 16-bit values, e.g. for white I get "65535 65535 65535".

MG It's very kludgy, and probably the worst solution anyone'll come up with, but what the hell. ;) For the sake of completeness...

You can also create an image of the window, and then check the colour of that pixel in the image. I believe this could would do it...

  package require Tk
  package require Img
  pack [canvas .c -bg red -height 100 -width 100]
  .c create rectangle 20 20 60 60 -fill blue
  bind .c <Button-1> {puts "RGB of [getPixel %W %x %y] at %x,%y"}
  catch {console show}
  proc getPixel {w x y} {
     set img [image create photo -data $w -format window]
     set rgb [$img get [scan $x %d] [scan $y %d]]
     image delete $img
     return $rgb;

HJG: This gives the machine as much work as taking a whole screenshot for querying a single pixel :-)

Category Graphics - Category Image Processing