2022/04/05(火) [n年前の日記]
#1 [python] tkinterとPillowでウインドウサイズに画像サイズを合わせる
Python + tkinter + Pillow で、ウインドウサイズ(キャンバスサイズ)に画像サイズを合わせて表示する処理を試しているところ。ついでにスクロールバーもつけてみたりして。
動作確認環境は以下。
参考ページは以下。ありがたや。
_【Python/tkinter】Canvasに画像を表示する | イメージングソリューション
_Pythonの文法メモ: 【Pillow】ImageOpsモジュールによる画像拡大縮小・トリミング・パディング
_Tkinterの使い方 : スクロールバー(Scrollbar)の使い方 | だえうホームページ
自分の手元でも、たぶんできた。一応動いてるように見える。
_03_canvas_zoom2.py
使用画像は以下。
_tex_1024.png
py 03_canvas_zoom2.py で実行すると、以下のような感じで動いてくれた。
ImageOps.pad() で、パディングを考慮したサイズに変換してくれるので簡単。method=Image.LANCZOS を渡せば、Lanczos で変換してくれるようでもあるし…。Pillow は便利だなあ。ありがたや。
でも、画像表示に特化した処理を ―― キャンバスに画像を表示できて、スクロールバーがついてて、拡大縮小表示ができて、マウスドラッグでスクロールができる、みたいなクラスだかモジュールだかを誰かが既に書いてたりしないのかなという疑問も湧いた。何かの処理結果画像を画像ビューアっぽい感じで表示したい場面って結構あるのではないだろうか。毎回こんな感じのスクリプトを書かなきゃいけないのだろうか…。
動作確認環境は以下。
- Windows10 x64 21H2 + Python 2.7.18 32bit + Pillow 6.2.2
- Windows10 x64 21H2 + Python 3.9.12 64bit + Pillow 9.0.1
参考ページは以下。ありがたや。
_【Python/tkinter】Canvasに画像を表示する | イメージングソリューション
_Pythonの文法メモ: 【Pillow】ImageOpsモジュールによる画像拡大縮小・トリミング・パディング
_Tkinterの使い方 : スクロールバー(Scrollbar)の使い方 | だえうホームページ
自分の手元でも、たぶんできた。一応動いてるように見える。
_03_canvas_zoom2.py
try:
# Python 3.x
import tkinter as tk
except Exception:
# Python 2.7
import Tkinter as tk
from PIL import Image, ImageTk, ImageOps
class App(tk.Frame, object):
def __init__(self, master=None):
try:
# Python 3.x
super().__init__(master)
except Exception:
# Python 2.7
# tk.Frame.__init__(self, master)
super(App, self).__init__(master)
self.master.title("Canvas sample")
# self.master.geometry("512x512")
self.rootfrm = tk.Frame(self.master)
self.rootfrm.pack(expand=1, fill=tk.BOTH)
self.rootfrm.rowconfigure(1, weight=1)
self.rootfrm.columnconfigure(0, weight=1)
# create Button
self.btnfrm = tk.Frame(self.rootfrm)
self.btnfrm.grid(row=0, column=0, sticky=tk.W)
self.btn0 = tk.Button(self.btnfrm, text="Fit", command=lambda: self.set_zoom_fit())
self.btn0.pack(side=tk.LEFT, padx=4, ipadx=8)
self.btn1 = tk.Button(self.btnfrm, text="1:1", command=lambda: self.set_zoom_full())
self.btn1.pack(side=tk.LEFT, padx=4, ipadx=8)
# create Canvas
self.cvsfrm = tk.Frame(self.rootfrm)
self.cvsfrm.grid(row=1, column=0, sticky=tk.N + tk.S + tk.W + tk.E)
self.cvsfrm.rowconfigure(0, weight=1)
self.cvsfrm.columnconfigure(0, weight=1)
self.canvas = tk.Canvas(self.cvsfrm, bg="#666666", width=512, height=256)
self.canvas.grid(row=0, column=0, sticky=tk.N + tk.S + tk.W + tk.E)
# create Scrollbar
xbar = tk.Scrollbar(self.cvsfrm, orient=tk.HORIZONTAL, command=self.canvas.xview)
ybar = tk.Scrollbar(self.cvsfrm, orient=tk.VERTICAL, command=self.canvas.yview)
xbar.grid(row=1, column=0, sticky=tk.W + tk.E)
ybar.grid(row=0, column=1, sticky=tk.N + tk.S)
self.canvas.config(xscrollcommand=xbar.set)
self.canvas.config(yscrollcommand=ybar.set)
# set drag scroll
self.canvas.bind("<ButtonPress-1>", lambda e: self.canvas.scan_mark(e.x, e.y))
self.canvas.bind("<B1-Motion>", lambda e: self.canvas.scan_dragto(e.x, e.y, gain=1))
self.zoomfit = True
self.im = Image.open("tex_1024.png")
self.set_image()
def set_zoom_fit(self):
self.zoomfit = True
self.set_image()
def set_zoom_full(self):
self.zoomfit = False
self.set_image()
def set_image(self):
self.update()
cw = self.canvas.winfo_width()
ch = self.canvas.winfo_height()
if self.zoomfit:
# view fit
self.im_pad = ImageOps.pad(self.im, (cw - 4, ch - 4), method=Image.LANCZOS)
self.photo_image = ImageTk.PhotoImage(image=self.im_pad)
else:
# view 1:1
self.photo_image = ImageTk.PhotoImage(image=self.im)
self.canvas.create_image(0, 0, image=self.photo_image, anchor=tk.NW)
# set scroll region
iw = self.photo_image.width()
ih = self.photo_image.height()
region = (0, 0, iw, ih)
self.canvas.config(scrollregion=region)
def main():
root = tk.Tk()
app = App(master=root)
app.mainloop()
if __name__ == '__main__':
main()
使用画像は以下。
_tex_1024.png
py 03_canvas_zoom2.py で実行すると、以下のような感じで動いてくれた。
ImageOps.pad() で、パディングを考慮したサイズに変換してくれるので簡単。method=Image.LANCZOS を渡せば、Lanczos で変換してくれるようでもあるし…。Pillow は便利だなあ。ありがたや。
でも、画像表示に特化した処理を ―― キャンバスに画像を表示できて、スクロールバーがついてて、拡大縮小表示ができて、マウスドラッグでスクロールができる、みたいなクラスだかモジュールだかを誰かが既に書いてたりしないのかなという疑問も湧いた。何かの処理結果画像を画像ビューアっぽい感じで表示したい場面って結構あるのではないだろうか。毎回こんな感じのスクリプトを書かなきゃいけないのだろうか…。
[ ツッコむ ]
以上です。