2024/05/22(水) [n年前の日記]
#1 [python] Pythonで色取得ツールを作れそうか試してみた
Python + tkinter を使って色取得ツール? カラーピッカー? を作れそうか試してみた。環境は、Windows10 x64 22H2 + Python 3.10.10 64bit。
OpenGL関係のプログラムを書いていた際に、RGB値を 0.0 - 1.0 で指定するのが面倒で…。一般的な色管理ツール/カラーピッカーは、RGB値を 0 - 255 で扱うので、変換が面倒で…。あらかじめ 0.0 - 1.0 で扱える色管理ツールがないかと探してみたけど、これが全然見つからない。自分で作るしかないのかなあ、と…。
OpenGL関係のプログラムを書いていた際に、RGB値を 0.0 - 1.0 で指定するのが面倒で…。一般的な色管理ツール/カラーピッカーは、RGB値を 0 - 255 で扱うので、変換が面倒で…。あらかじめ 0.0 - 1.0 で扱える色管理ツールがないかと探してみたけど、これが全然見つからない。自分で作るしかないのかなあ、と…。
◎ PyAutoGUIをインストール :
デスクトップ上の一点を指定して色を取得できるライブラリ(モジュール)は何があるのかとググってみたところ、PyAutoGUI が使えるらしいと知った。
pyautogui.pixel(x, y)、もしくは、pyautogui.screenshot().getpixel((x, y)) で、指定座標の (r, g, b) を取得できるらしい。ちなみに、デスクトップ全体のスクリーンショットを取ってから、該当位置のドットを調べる仕組みらしい…。
また、この PyAutoGUI を使うと、マウスカーソル座標も常時取得できる。x, y = pyautogui.position() で得られる模様。
ひとまず、PyAutoGUI をインストール。
PyAutoGUI 0.9.54 がインストールされた。
pyautogui.pixel(x, y)、もしくは、pyautogui.screenshot().getpixel((x, y)) で、指定座標の (r, g, b) を取得できるらしい。ちなみに、デスクトップ全体のスクリーンショットを取ってから、該当位置のドットを調べる仕組みらしい…。
また、この PyAutoGUI を使うと、マウスカーソル座標も常時取得できる。x, y = pyautogui.position() で得られる模様。
ひとまず、PyAutoGUI をインストール。
pip install PyAutoGUI
PyAutoGUI 0.9.54 がインストールされた。
◎ pyperclipをインストール :
得られたRGB値を、OpenGL用のRGB値に ―― 各RGB値が 0.0 - 1.0 の値で示される状態に変換して、クリップボードに入れたい。Python からクリップボードを扱えるライブラリがないかググったところ、pyperclip というライブラリが使えると知った。
pyperclip.copy("hoge") で、クリップボードに "hoge" が入る。
このライブラリもインストール。
pyperclip 1.8.2 がインストールされた。
※ 2024/05/28追記。もし、tkinter を使っているなら、tkinter自体にクリップボードを操作する機能があるので、pyperclip を別途インストールして使わなくても済む。
pyperclip.copy("hoge") で、クリップボードに "hoge" が入る。
このライブラリもインストール。
pip install pyperclip
pyperclip 1.8.2 がインストールされた。
※ 2024/05/28追記。もし、tkinter を使っているなら、tkinter自体にクリップボードを操作する機能があるので、pyperclip を別途インストールして使わなくても済む。
◎ 常時色を取得する版を書いてみた :
一定の時間間隔でtkinterが関数を呼んで、常時、マウスカーソル位置と、その位置の色を取得する版を書いてみた。以下のサンプルを参考にさせてもらいました。ありがたや。
_Pythonでマウス座標をリアルタイムで取得して表示するGUIアプリを作る
Windows10 x64 22H2 + Python 3.10.10 64bit + PyAutoGUI 0.9.54 + pyperclip 1.8.2 で動作確認。
以下のような感じになった。
下のほうに、クリップボードの内容をリアルタイム表示する GhostBoard というアプリのウインドウも出しているけれど、値を取得(クリップボードにコピー)するたびに、ちゃんとクリップボードの内容が変わってることも分かるかと。
ソースは以下。
_02_get_color1.py
本当はマウスクリックで色を取得するようにしたかったのだけど、tkinter のウインドウ外でマウスクリックされたかどうかを判別する方法が分からなくて…。仕方なく、tkinter のアプリウインドウがアクティブになってる時に、キーが押されたかどうかを判別して、色を取得するようにしてみた。
余談。tkinter でアプリウインドウを最前面にする時は、.attributes("-topmost", True) を指定すればいいらしい。
また、.after(ミリ秒, 関数名) を使うことで、指定時間後に関数を呼ぶことができる。呼ばれた関数の中で、再度 .after() を呼べば、一定の時間間隔で処理をすることができるようになる。
_Pythonでマウス座標をリアルタイムで取得して表示するGUIアプリを作る
Windows10 x64 22H2 + Python 3.10.10 64bit + PyAutoGUI 0.9.54 + pyperclip 1.8.2 で動作確認。
以下のような感じになった。
- Cキー、またはスペースキー、またはEnterキーを叩くと、そのタイミングでマウスカーソル位置の色をクリップボードにコピーする。
- ESCキー、またはQキーで終了。
下のほうに、クリップボードの内容をリアルタイム表示する GhostBoard というアプリのウインドウも出しているけれど、値を取得(クリップボードにコピー)するたびに、ちゃんとクリップボードの内容が変わってることも分かるかと。
ソースは以下。
_02_get_color1.py
import pyautogui as ag import tkinter as tk import pyperclip DELAYMS = 100 # milliseconds def display_pos_rgb(x, y, rgb): r = float(rgb[0]) / 255.0 g = float(rgb[1]) / 255.0 b = float(rgb[2]) / 255.0 rgbftext = "%.4f, %.4f, %.4f" % (r, g, b) root.poslabel.config(text=f"Pos : {x}, {y}") root.rgblabel.config(text=f"RGB : {rgb}") root.rgbflabel.config(text=rgbftext) root.collabel.config(bg="#%02x%02x%02x" % rgb) return rgbftext def set_clipboard(e): global cnt x, y = ag.position() rgb = ag.pixel(x, y) rgbftext = display_pos_rgb(x, y, rgb) # to clipboard pyperclip.copy(rgbftext) root.reslabel.config(text="copied!") root.reslabel.after(750, clear_msg) def clear_msg(): root.reslabel.config(text="") def update(): global cnt x, y = ag.position() # get mouse position rgb = ag.pixel(x, y) # get color display_pos_rgb(x, y, rgb) root.after(DELAYMS, update) def close(e): root.destroy() # initialize tkinter root = tk.Tk() root.attributes("-topmost", True) root.title("Color picker") # root.geometry("320x240") root.reslabel = tk.Label(text="", font=("Arial", 16)) root.poslabel = tk.Label(text="Pos : ") root.rgblabel = tk.Label(text="RGB : ") root.rgbflabel = tk.Label(text="") root.msglabel = tk.Label(text="C / Enter / Space key : get color") root.collabel = tk.Label( text="", width=15, height=4, bg="green", borderwidth=1, relief=tk.SOLID ) root.reslabel.pack() root.poslabel.pack() root.rgblabel.pack() root.rgbflabel.pack() root.msglabel.pack(padx=10) root.collabel.pack(padx=10, pady=10) # bind key root.bind("<Escape>", close) root.bind("<q>", close) root.bind("<c>", set_clipboard) root.bind("<space>", set_clipboard) root.bind("<Return>", set_clipboard) root.after(DELAYMS, update) root.mainloop()
本当はマウスクリックで色を取得するようにしたかったのだけど、tkinter のウインドウ外でマウスクリックされたかどうかを判別する方法が分からなくて…。仕方なく、tkinter のアプリウインドウがアクティブになってる時に、キーが押されたかどうかを判別して、色を取得するようにしてみた。
余談。tkinter でアプリウインドウを最前面にする時は、.attributes("-topmost", True) を指定すればいいらしい。
root.attributes("-topmost", True)
また、.after(ミリ秒, 関数名) を使うことで、指定時間後に関数を呼ぶことができる。呼ばれた関数の中で、再度 .after() を呼べば、一定の時間間隔で処理をすることができるようになる。
◎ マウスクリックで取得する版を書いてみた :
tkinter のウインドウ外でマウスクリックを検出する方法が無いか Microsoft Copilot に尋ねてみたら、「pynputを使えばできらあ」と言ってきたのでググってみた。マウスカーソルが移動してるかどうかを検出したり、マウスボタンが押されたかどうかを検出できるらしい。とりあえずインストール。
pynput 1.7.6 がインストールされた。
pynput を使って、マウスクリックで色を取得するようにしてみた。ボタンを押してから、デスクトップ上のどこかしらをクリックすると、その位置の色を取得して、クリップボードにRGB値が入る。
_03_get_color2.py
一見上手くいったように思えたのだけど、マウスクリックで色を取得するのはよろしくないことに気づいた。マウスクリックした場所に別のアプリがあったりして、そのアプリのその位置をクリックすることで何かしらの処理が行われてしまう場合は、ちょっとマズいことになる。例えば、WebブラウザでWebページを開いていて、該当位置をクリックして色を取得したら、たまたまそこにリンクが貼ってあって、無意味にリンクを開いてしまったり等々…。
巷のカラーピッカーツールのように、マウスクリックではなく、マウスボタンのリリースで ―― マウスボタンを離したタイミングで色を取得したほうがいいのかもしれない。
pip install pynput
pynput 1.7.6 がインストールされた。
pynput を使って、マウスクリックで色を取得するようにしてみた。ボタンを押してから、デスクトップ上のどこかしらをクリックすると、その位置の色を取得して、クリップボードにRGB値が入る。
_03_get_color2.py
import tkinter as tk import pyautogui from pynput import mouse import pyperclip DEF_MSG = "Get color" listener = None getting = False def display_rgb(x, y): global rgblbl, rgbflbl, collbl r, g, b = pyautogui.screenshot().getpixel((x, y)) rf = float(r) / 255.0 gf = float(g) / 255.0 bf = float(b) / 255.0 rgbftext = "%.4f, %.4f, %.4f" % (rf, gf, bf) rgblbl.config(text="RGB : %d, %d, %d" % (r, g, b)) rgbflbl.config(text=rgbftext) collbl.config(bg="#%02x%02x%02x" % (r, g, b)) return rgbftext def on_move(x, y): display_rgb(x, y) def on_click(x, y, button, pressed): global listener, getting, btn, root if pressed: rgbftext = display_rgb(x, y) # to clipboard pyperclip.copy(rgbftext) btn.config(text="Copied !") listener.stop() getting = False root.after(1000, set_default_msg) def set_default_msg(): global btn btn.config(text=DEF_MSG) def start_get_color(): global listener, getting, btn, rgblbl listener = mouse.Listener(on_click=on_click, on_move=on_move) listener.start() btn.config(text="Please click desktop") getting = True def on_close(): global listener, getting if getting: listener.stop() root.destroy() def close(e): global listener, getting if getting: listener.stop() root.destroy() # ---------------------------------------- # main # init tkinter root = tk.Tk() root.attributes("-topmost", True) root.title("Color picker") # root.geometry("260x200") btn = tk.Button(text=DEF_MSG, command=start_get_color, font=("Arial", 13), width=25) rgblbl = tk.Label(root, text="RGB : 0, 0, 0") rgbflbl = tk.Label(root, text="0.0000, 0.0000, 0.0000") collbl = tk.Label( root, text="", width=10, height=4, bg="black", borderwidth=1, relief=tk.SOLID ) btn.pack(padx=8, pady=4) rgblbl.pack() rgbflbl.pack() collbl.pack(padx=8, pady=8) root.bind("<Escape>", close) root.bind("<q>", close) root.protocol("WM_DELETE_WINDOW", on_close) root.mainloop()
一見上手くいったように思えたのだけど、マウスクリックで色を取得するのはよろしくないことに気づいた。マウスクリックした場所に別のアプリがあったりして、そのアプリのその位置をクリックすることで何かしらの処理が行われてしまう場合は、ちょっとマズいことになる。例えば、WebブラウザでWebページを開いていて、該当位置をクリックして色を取得したら、たまたまそこにリンクが貼ってあって、無意味にリンクを開いてしまったり等々…。
巷のカラーピッカーツールのように、マウスクリックではなく、マウスボタンのリリースで ―― マウスボタンを離したタイミングで色を取得したほうがいいのかもしれない。
◎ マウスボタンを離したタイミングで色を取得する版を書いた :
マウスクリックで色取得するのはよろしくないことに気づいたので、マウスボタンを離したタイミングで色取得する版を書いてみた。アプリウインドウの中の任意の場所をマウスでドラッグして、色を取得したい場所でマウスボタンを離せば、その位置の色を取得できる。
_04_get_color3.py
これで、かなりそれらしい処理になってくれた気がする。
この後は、以下のような処理を追加してみたいなと…。
でも、車輪の再発明のような気もする…。巷で公開配布されてる色管理ツールが、0.0 - 1.0 の値でRGB値をクリップボードにコピーする機能を持ってたらそれで済んでしまうのだけどな…。
_04_get_color3.py
import tkinter as tk import pyautogui from pynput import mouse import pyperclip DEF_MSG = "Drag here. Get color" listener = None getting = False def get_rgb(x, y): global rgblbl, rgbflbl, collbl r, g, b = pyautogui.screenshot().getpixel((x, y)) rf = float(r) / 255.0 gf = float(g) / 255.0 bf = float(b) / 255.0 rgbftext = "%.4f, %.4f, %.4f" % (rf, gf, bf) rgblbl.config(text="RGB : %d, %d, %d" % (r, g, b)) rgbflbl.config(text=rgbftext) collbl.config(bg="#%02x%02x%02x" % (r, g, b)) return rgbftext def on_move(x, y): get_rgb(x, y) def on_click(x, y, button, pressed): global listener, getting, btn, root if button == mouse.Button.left: if not pressed: # button release. to clipboard pyperclip.copy(get_rgb(x, y)) btn.config(text="Copied !") listener.stop() getting = False root.after(1000, set_default_msg) def set_default_msg(): global btn btn.config(text=DEF_MSG) def start_get_color(e): global listener, getting, btn, rgblbl listener = mouse.Listener(on_click=on_click, on_move=on_move) listener.start() btn.config(text="Please release on desktop") getting = True def close_window(e): global getting if getting: return root.destroy() # ---------------------------------------- # main # init tkinter root = tk.Tk() root.title("Color picker") # root.geometry("260x200") root.attributes("-topmost", True) btn = tk.Label( text=DEF_MSG, font=("Arial", 13), width=25, borderwidth=3, relief=tk.GROOVE ) rgblbl = tk.Label(root, text="RGB : 0, 0, 0") rgbflbl = tk.Label(root, text="0.0000, 0.0000, 0.0000") collbl = tk.Label( root, text="", width=20, height=4, bg="black", borderwidth=1, relief=tk.SOLID ) btn.pack(padx=8, pady=8) rgblbl.pack() rgbflbl.pack() collbl.pack(padx=8, pady=8) btn.bind("<ButtonPress-1>", start_get_color) root.bind("<Escape>", close_window) root.bind("q", close_window) root.mainloop()
これで、かなりそれらしい処理になってくれた気がする。
この後は、以下のような処理を追加してみたいなと…。
- 色を取得するたびにリストに追加して、取得した色の履歴を並べる。
- 0 - 255 のRGB値と、0.0 - 1.0 のRGB値(OpenGL用)を相互に変換できるようにする。
- 任意の色指定形式でクリップボードにコピーする。
でも、車輪の再発明のような気もする…。巷で公開配布されてる色管理ツールが、0.0 - 1.0 の値でRGB値をクリップボードにコピーする機能を持ってたらそれで済んでしまうのだけどな…。
[ ツッコむ ]
#2 [cg_tools] Float RGBが扱えるカラーピッカーを探してみた
Windows10 x64 22H2上で利用できるカラーピッカーツールを探してみた。RGB値を取得した際に 0.0 - 1.0 の範囲にしてクリップボードにコピーすることができると嬉しい。
一応説明しておくと…。PC上で色を管理する時は、一般的にはRGB(Red, Green, Blue)の各値が 0 - 255 の値で ―― 8bitで表現できる値として管理される。 *1
ただ、OpenGL上では、RGB値を 0.0 - 1.0 の値で指定する。しかし、0.0 - 1.0 でRGB値を指定する場面は一般的にはほとんどないようで、フリーソフトとして公開されてるカラーピッカー/色管理ツールの大半は、0 - 255 でしか値をコピーすることができない。
他にも、HTML や CSS などは、「#FFFFFF」みたいな表記で色を指定したりもする。0 - 255 の値を16進数にして、RGB順で並べて、先頭に「#」をつけるとそういう表記になる。
さておき。ググっているうちに、0.0 - 1.0 で値を記述する場合、以下のような呼び方/書き方がされている時もあると知った。検索ワードに入れてやると引っ掛かりやすくなるかもしれない。
一応説明しておくと…。PC上で色を管理する時は、一般的にはRGB(Red, Green, Blue)の各値が 0 - 255 の値で ―― 8bitで表現できる値として管理される。 *1
ただ、OpenGL上では、RGB値を 0.0 - 1.0 の値で指定する。しかし、0.0 - 1.0 でRGB値を指定する場面は一般的にはほとんどないようで、フリーソフトとして公開されてるカラーピッカー/色管理ツールの大半は、0 - 255 でしか値をコピーすることができない。
他にも、HTML や CSS などは、「#FFFFFF」みたいな表記で色を指定したりもする。0 - 255 の値を16進数にして、RGB順で並べて、先頭に「#」をつけるとそういう表記になる。
さておき。ググっているうちに、0.0 - 1.0 で値を記述する場合、以下のような呼び方/書き方がされている時もあると知った。検索ワードに入れてやると引っ掛かりやすくなるかもしれない。
- RGB 0 - 1
- RGB [0,1]
- Unit RGB
- Float RGB, RGB Float
◎ Just Color Pickerを試用 :
Float RGB、0.0 - 1.0 の表記で色をクリップボードにコピーできる、Just Color Picker というツールがあると知った。
_Just Color Picker 6.0 - best free colour tool for Windows and macOS
_Just Color Picker のダウンロードと使い方 - k本的に無料ソフト・フリーソフト
jcpicker.zip を入手して解凍。任意の場所に置く。中に入っている jcpicker.exe を実行すると起動する。バージョンは 6.0 だった。
OpenGLで色を検討する時は、これで十分なのでは、という気がしてきた…。
_Just Color Picker 6.0 - best free colour tool for Windows and macOS
_Just Color Picker のダウンロードと使い方 - k本的に無料ソフト・フリーソフト
jcpicker.zip を入手して解凍。任意の場所に置く。中に入っている jcpicker.exe を実行すると起動する。バージョンは 6.0 だった。
- 「RGB [0,1]」を選ぶと、0.0 - 1.0 の値でRGB値をコピーできる。小数点以下2桁の状態で扱うらしい。
- デスクトップ上から色を取得する時は、マウスクリックではなく、ホットキーを押す。デフォルトでは Alt + X が割り当てられている。
- 右上には取得した色の履歴が並んでいる。クリックすると、その色を現在の選択色にできる。
OpenGLで色を検討する時は、これで十分なのでは、という気がしてきた…。
◎ Color Copを試用 :
RGB Float で値をコピーできる、Color Cop というカラーピッカーも見つけた。
_a free multi-purpose color picker for Windows
_download
_拡大鏡も付いてるフリーのカラーピッカーソフト・Color Copがなかなか便利 | かちびと.net
English v5.4.5 stand alone版の、colorcop.zip を入手。解凍して任意の場所に置く。中に入っている ColorCop.exe を実行すると起動する。
これでもいいんじゃないかな…。
_a free multi-purpose color picker for Windows
_download
_拡大鏡も付いてるフリーのカラーピッカーソフト・Color Copがなかなか便利 | かちびと.net
English v5.4.5 stand alone版の、colorcop.zip を入手。解凍して任意の場所に置く。中に入っている ColorCop.exe を実行すると起動する。
- ウインドウ内のどこかで右クリックすると設定を変更できる。Mode → RGB float、を選べば、0.0 - 1.0 の値をコピーできる状態になる。
- スポイトのアイコンをドラッグして、色を取得したい場所でマウスボタンを離せば、デスクトップ上の色を取得できる。
- 虫眼鏡(?)っぽいアイコンをドラッグすれば、デスクトップ上の一部を、ウインドウの右下に拡大表示することができる。
- ウインドウの右下に表示されてる部分を、マウスの左ボタンでクリックすれば、その位置の色を取得できる。
これでもいいんじゃないかな…。
◎ ぽれったカラーピッカーを試用 :
レイトレーシングで3DCG画像を作れるレンダラーのPOV-Rayも、色の指定は 0.0 - 1.0 で指定するようで、その関係で 0.0 - 1.0 で色を選べるツールが公開されていた。デスクトップ上の色を取得できるわけではないけれど、RGBの各スライダー(?)を動かすと、どんな色になるか確認することができる。
_ぽれったカラーピッカー バージョン1.0
_POV-Ray用ユーティリティー
porettaClrPicker.ZIP を入手して解凍。中に入っている、ぽれったカラーピッカー.exe を実行。Windows98時代に作られたツールらしいけれど、Windows10 x64 22H2上でも動いてくれた。と思ったけれど、稀にスライダー?が消失する時があるな…。一旦終了して再度起動すると正常になったけれど。
関連ツールとして、RGB値を 0.0 - 1.0 の値にして入力すると、どんな色なのか確認できるページも公開されていた。
_POV-Rayの色指定で背景色を変える
以下のような記述を受け付けるらしい。
_ぽれったカラーピッカー バージョン1.0
_POV-Ray用ユーティリティー
porettaClrPicker.ZIP を入手して解凍。中に入っている、ぽれったカラーピッカー.exe を実行。Windows98時代に作られたツールらしいけれど、Windows10 x64 22H2上でも動いてくれた。と思ったけれど、稀にスライダー?が消失する時があるな…。一旦終了して再度起動すると正常になったけれど。
関連ツールとして、RGB値を 0.0 - 1.0 の値にして入力すると、どんな色なのか確認できるページも公開されていた。
_POV-Rayの色指定で背景色を変える
以下のような記述を受け付けるらしい。
- 0.88, 0.60, 0.4
- rgb <0.88, 0.60, 0.4>
- color red 0.8 green 0.498039 blue 0.196078
- #declare Gold = color red 0.8 green 0.498039 blue 0.196078;
- rgbf <0.7, 0.6, 0.4, 0.100>
◎ オンラインサービスのカラーピッカーを試用 :
Webブラウザ上で色を選択できる、オンラインサービスというか、カラーピッカーツールのページにも遭遇。
_webgl colour chooser
_Color Picker
_RGB 0-1 Color Picker
どれも、RGB 0.0 - 1.0 の範囲で値を表示してくれる。
_webgl colour chooser
_Color Picker
_RGB 0-1 Color Picker
どれも、RGB 0.0 - 1.0 の範囲で値を表示してくれる。
*1: これはRGB 24bitの場合の話。RGB各値が、4bit、5bit、6bit、10bit、12bit、16bit になってる時もあるし、整数ではなく実数になってる時もあるけれど、一般的にフルカラーと称されるスペック上では 0 - 255 で管理されることが多い。
[ ツッコむ ]
以上、1 日分です。