[Tcl/Tk] Tkウィンドウ上でマウスポインタの下の色を取得する

Tcler's Wikiには以下のページで2通りの方法が紹介されています。

http://wiki.tcl.tk/15339

1つ目はキャンバスアイテムがimageの場合は、中身の画像に対してgetコマンドを使用してピクセルのRGB値を取得し、それ以外のアイテムに対してはitemcget -fillの値を取得するという方法で、2つ目はウィンドウのキャプチャを取得して、それに対してgetコマンドを発行する方法になっています。

が、いずれもいまいちでした。
まず、1つ目の方法ではimage以外の図形のフチの色が取得できません。
2つ目の方法はめちゃくちゃ遅いので実用的ではありません。

以下を参考にして、GDIを使う方法にしました。

http://www.csharp411.com/c-getpixel-and-setpixel/

この方法だと別にcanvasに限らず色が取得できます。

ただし、Windows専用になります。Tkのウィンドウの外に出るとマウスの動きをキャプチャできなくなるので一般的なカラーピッカーみたいなのを作りたければ、そこのところを作りこむ必要があります。

本当はそこまでやりたかったけど、TclでWM_MOUSEMOVEメッセージを処理する方法が分からないので保留。

SetPixelはおまけです。
Ffidlはこちらからダウンロードできます。

package require Tk
package require Ffidl
 
namespace eval Win32 {
	variable HWND_DESKTOP 0
	ffidl::callout GetDC {pointer} pointer [ffidl::symbol user32.dll GetDC]
	ffidl::callout ReleaseDC {pointer pointer} int [ffidl::symbol user32.dll ReleaseDC]
}
namespace eval Gdi32 {
	ffidl::callout GetPixel {pointer int int} int [ffidl::symbol gdi32.dll GetPixel]
	ffidl::callout SetPixel {pointer int int int} int [ffidl::symbol gdi32.dll SetPixel]
}
 
proc GetPixel {hdc x y} {
	set c [Gdi32::GetPixel $hdc $x $y]
 
	set R [expr {($c & 0x000000FF)}]
	set G [expr {($c & 0x0000FF00) >>  8}]
	set B [expr {($c & 0x00FF0000) >> 16}]
 
	return [list $R $G $B]
}
 
proc SetPixel {hdc x y r g b} {
	set c [expr {(int($r & 0x00FF0000) >> 16)
	           | (int($g & 0x0000FF00))
	           | (int($b & 0x000000FF) << 16)
	}]
 
	Gdi32::SetPixel $hdc $x $y $c
}
 
# demo
set c [canvas .c]
pack $c
 
$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> {
	set x [winfo pointerx .]
	set y [winfo pointery .]
 
	set hdc [Win32::GetDC $::Win32::HWND_DESKTOP]
	foreach {R G B} [GetPixel $hdc $x $y] break
	Win32::ReleaseDC $::Win32::HWND_DESKTOP $hdc
 
	wm title . "(x, y) = ($x, $y) : ($R, $G, $B)"
}
console show

コメントを残す