【Python】Tkinter のみで GUI アプリに画像を表示する

アプリ上に画像を表示する方法の解説ページアイキャッチ

このページでは Python で Tkinter を用いて GUI アプリに画像を表示する方法について、サンプルスクリプトを用いて紹介していきます。

このページで紹介するサンプルスクリプトを実行すれば、下のように GUI アプリが起動し、

サンプルスクリプト実行により起動するアプリ

さらに「ファイル選択」ボタンから画像ファイル(.png や .gif など)を選択することで、画面の左側に画像が表示されるようになります。

アプリに画像を表示した結果

また「縮小」ボタンを押せば、左側に表示されている画像を縮小したものが画面の右側に、「拡大」ボタンを押せば、左側に表示されている画像を拡大したものが画面の右側に表示されます。

縮小後の画像をアプリに表示した結果

Python で画像といえば Pillow や OpenCV などを利用するイメージが強いかもしれませんが、今回紹介するのは Tkinter(filedialog 含む)のみを利用して GUI アプリに表示する方法です。

サンプルスクリプトで利用している Tkinter については下記ページで、

tkinter解説ページのアイキャッtPythonでTkinterを使ってめちゃくちゃ簡単にGUIアプリを作る

ファイル選択画面を表示する方法については下記ページで紹介しています。

ファイル選択画面表示の解説ページアイキャッチPython でファイル選択画面を表示する

これらのページについても併せて読んでいただければと思います。

動作確認環境

このページで紹介するサンプルスクリプトは下記環境で動作確認を行っています

  • OS:macOS Catalina
  • Python:3.8
  • Tkinter:8.6

GUI アプリに画像を表示する方法

GUI アプリに画像を表示するには、Tkinter の PhotoImage クラスを利用します。

画像オブジェクトの生成

PhotoImage クラスのオブジェクトを生成時に画像ファイルへのファイルパスを指定すれば、その画像を Tkinter で利用するためのオブジェクトに変換することができます。

画像オブジェクトの生成
image = tkinter.PhotoImage(file="ファイルパス")

file には画像ファイルへのパスを指定します。

ただし、Tkinter のみだと PhotoImage に指定できる画像ファイルは下記の形式のみになります(2020/4/17 時点)。

  • PNG
  • PGM
  • PPM
  • GIF

Pillow を利用すればもっと多くの画像形式を利用できるようになりますが、Tkinter だけだと上記のみしかた対応していないようです。少ない!

スポンサーリンク

画像の描画

さらにその画像を Tkinter の Canvas クラスのメソッド create_image を利用して GUI アプリに画像を描画することが可能です。

画像の描画
canvas.create_image(
    0, 0, image=image
)

第1引数には描画する画像の中心の x 座標、第2引数には描画する画像の中心の y 座標を指定します。

また image には PhotoImage クラスのオブジェクトを指定します。

画像のリサイズ

PhotoImage クラスに用意されたメソッドを利用すれば、画像のリサイズを行うこともできます。

縮小

また、この PhotoImage クラスのオブジェクトに subsample メソッドを実行させることで画像を縮小することができます。、zoom メソッドを実行することで画像の拡大を行うことも可能です。

縮小
dst_image = src_image.subsample(2, 1)

第1引数には横方向の縮小率(大きい値ほど縮小される)、第2引数には縦方向の縮小率を指定します。第1引数のみを指定した場合、画像の縦横の両方向が、その縮小率に基づいて縮小されます。

ただし、引数に指定できるのは整数のみです…。細かいサイズの調整はできません…。

拡大

PhotoImage クラスのオブジェクトに zoom メソッドを実行することで画像の拡大も行うこともできます。

拡大
dst_image = src_image.zoom(2, 3)

第1引数には横方向の拡大率(大きい値ほど拡大される)、第2引数には縦方向の拡大率を指定します。

第1引数のみを指定した場合、画像の縦横の両方向が、その拡大率に基づいて縮小されます。

ただし、こちらも subsample メソッド同様に引数に指定できるのは整数のみです…。

GUI アプリに画像を表示するサンプルスクリプト

ここまで紹介してきた PhotoImage クラスを利用して GUI アプリに画像を表示するサンプルスクリプトは下記のようになります。

GUIに画像を描画するサンプル
import tkinter
import tkinter.filedialog

class Application(tkinter.Tk):
    def __init__(self):
        super().__init__()
        
        # キャンバスのサイズ
        self.canvas_width = 400
        self.canvas_height = 400

        # アプリのウィンドウのサイズ設定
        self.geometry("1000x430")

        # 1つ目のキャンバスの作成と配置
        self.before_canvas = tkinter.Canvas(
            self,
            width=self.canvas_width,
            height=self.canvas_height,
            bg="gray"
        )
        self.before_canvas.grid(row=1, column=1)

        # 2つ目のキャンバスの作成と配置
        self.after_canvas = tkinter.Canvas(
            self,
            width=self.canvas_width,
            height=self.canvas_height,
            bg="gray"
        )
        self.after_canvas.grid(row=1, column=2)

        # ボタンを配置するフレームの作成と配置
        self.button_frame = tkinter.Frame()
        self.button_frame.grid(row=1, column=3)

        # ファイル読み込みボタンの作成と配置
        self.load_button = tkinter.Button(
            self.button_frame,
            text="ファイル選択",
            command=self.push_load_button
        )
        self.load_button.pack()

        # 画像縮小ボタンの作成と配置
        self.subsample_button = tkinter.Button(
            self.button_frame,
            text="縮小",
            command=self.push_subsample_button
        )
        self.subsample_button.pack()

        # 画像拡大ボタンの作成と配置
        self.zoom_button = tkinter.Button(
            self.button_frame,
            text="拡大",
            command=self.push_zoom_button
        )
        self.zoom_button.pack()

        # 画像オブジェクトの設定(初期はNone)
        self.before_image = None
        self.after_image = None

        # キャンバスに描画中の画像(初期はNone)
        self.before_canvas_obj= None
        self.after_canvas_obj = None

    def push_load_button(self):
        'ファイル選択ボタンが押された時の処理'

        # ファイル選択画面を表示
        file_path = tkinter.filedialog.askopenfilename(
            initialdir="."
        )

        if len(file_path) != 0:

            # Tkinter用画像オブジェクトの作成
            self.before_image = tkinter.PhotoImage(file=file_path)

            # 画像の描画位置を調節
            x = int(self.canvas_width / 2)
            y = int(self.canvas_height / 2)

            # キャンバスに描画中の画像を削除
            if self.before_canvas_obj is not None:
                self.before_canvas.delete(self.before_canvas_obj)

            # 画像を1つ目のキャンバスに描画
            self.before_canvas_obj = self.before_canvas.create_image(
                x, y,
                image=self.before_image
            )

    def push_subsample_button(self):
        '縮小ボタンが押された時の処理'

        if self.before_image is not None:
            # 1つ目のキャンバスに描画している画像をコピー
            tmp_image = self.before_image.copy()

            # 画像を縮小(1/2)
            self.after_image = tmp_image.subsample(2)
            
            # 画像の描画位置を調節
            x = int(self.canvas_width / 2)
            y = int(self.canvas_height / 2)

            # キャンバスに描画中の画像を削除
            if self.after_canvas_obj is not None:
                self.after_canvas.delete(self.after_canvas_obj)

            # 画像を描画
            self.after_canvas_obj = self.after_canvas.create_image(
                x, y,
                image=self.after_image
            )

    def push_zoom_button(self):
        '拡大ボタンが押された時の処理'

        if self.before_image is not None:
            # 1つ目のキャンバスに描画している画像をコピー
            tmp_image = self.before_image.copy()

            #画像を拡大(2倍)
            self.after_image = tmp_image.zoom(2)
            
            # 画像の描画位置を調節
            x = int(self.canvas_width / 2)
            y = int(self.canvas_height / 2)

            # キャンバスに描画中の画像を削除
            if self.after_canvas_obj is not None:
                self.after_canvas.delete(self.after_canvas_obj)

            # 画像を描画
            self.after_canvas_obj = self.after_canvas.create_image(
                x, y,
                image=self.after_image
            )
    
app = Application()
app.mainloop()

このページの冒頭で説明した通り、このスクリプトを実行すると下の図のようなアプリが起動します。

サンプルスクリプト実行により起動するアプリ

アプリ起動後、「ファイル選択ボタン」から画像ファイルを選択すれば、その画像が画面の左側のキャンバスに描画されます。

アプリに画像を表示した結果

また、画像が左側のキャンバスに描画された後に、「縮小」or「拡大」ボタンを押せば、リサイズ後の画像が右側のキャンバスに描画されます。

縮小後の画像をアプリに表示した結果

キャンバスのサイズは 400×400 に設定していますので、それより大きいサイズの画像を描画した場合は画像がキャンバスはみ出てしまう(表示されない)ので注意してください。

スポンサーリンク

サンプルスクリプトの解説

ここでは PhotoImage クラスを活用している下記の3つのメソッドについて解説したいと思います。

その他の部分は主に Tkinter を利用したスクリプトになっていますので、詳しくは下記ページを参考にしていただければと思います。

tkinter解説ページのアイキャッtPythonでTkinterを使ってめちゃくちゃ簡単にGUIアプリを作る

push_load_button メソッド

この push_load_button は「ファイル選択」ボタンが押された時に実行されるメソッドです。

まず askopenfilename 関数によりファイル選択画面を表示し、ユーザーからの画像のファイルパス選択を受け付けます。

askopenfilename 関数については下記ページで解説していますので詳しく知りたい方はこちらを参考にしてください。
ファイル選択画面表示の解説ページアイキャッチPython でファイル選択画面を表示する

ファイルパスが選択されれば、下記によりそのファイルパスの画像から Tkinter 用の画像オブジェクトが生成しています。

# Tkinter用画像オブジェクトの作成
self.before_image = tkinter.PhotoImage(file=file_path)

さらにオブジェクト生成後、Canvas クラスの create_image メソッドを利用してキャンバスに画像の描画を行っています。

# 画像を1つ目のキャンバスに描画
self.before_canvas.create_image(
    self.before_image.width() / 2,
    self.before_image.height() / 2,
    image=self.before_image
)

self.before_canvas は画面左側のキャンバスのオブジェクトですので、上記により指定された画像が画面左側のキャンバスに描画されることになります。

push_subsample_button メソッド

push_subsample_button は「縮小」ボタンが押された時に実行されるメソッドです。

まず下記により、縮小する画像をコピーします。

# 1つ目のキャンバスに描画している画像をコピー
tmp_image = self.before_image.copy()

さらに下記により画像の縮小を行い、

# 画像を縮小(1/2)
self.after_image = tmp_image.subsample(2)

最後に下記により縮小後の画像をキャンバス描画しています(キャンバスの中心に画像が描画されるように xy を計算しています)。

# 画像の描画位置を調節
x = self.canvas_width / 2
y = self.canvas_height / 2

# 画像を描画
self.after_canvas.create_image(
    x, y,
    image=self.after_image
)

self.after_canvas

 は画面右側のキャンバスのオブジェクトですので、上記によりリサイズ後の画像が画面右側のキャンバスに描画されることになります。

スポンサーリンク

push_zoom_button メソッド

push_zoom_button は「拡大」ボタンが押された時に実行されるメソッドで、基本的な処理は push_subsample_button と同様です。

ただしこちらのメソッドでは画像の拡大を行いますので、subsample メソッドではなく zoom メソッドを使用しています。

# 画像を拡大(2倍)
self.after_image = tmp_image.zoom(2)

まとめ

このページでは Tkinter を利用して GUI アプリに画像を表示する方法について解説しました。

Tkinter を使って簡単な画像処理も行ってみましたが、あくまでもこのページの目的は GUI アプリに画像を表示することです。

もっと豊富な形式の画像を読み込めるようにしたり、より高度な画像処理を行うためには OpenCV や Pillow を利用する方が良いです。

ただし、画像処理アプリを作成して画像をアプリ上に表示したい場合(例えば OpenCV での画像処理前後の画像を GUI アプリに表示する等)は、このページで解説した内容は役に立つと思いますのでしっかり理解しておくのが良いと思います。

ちなみに、PhotoImage クラスには get メソッドと put メソッドが用意されており、これらを使用してピクセル単位で画像を加工することも可能です。これについては下記ページで解説していますので、こちらも是非読んでみてください!

【Python】Tkinter PhotoImage の get・put を利用してピクセル単位で画像処理を行う(透過処理も)

オススメ参考書

「GUI アプリ作成に興味のある方」や「ゲーム開発に興味のある方」にはPythonでつくる ゲーム開発 入門講座がオススメです。

この本は、このページで紹介した Tkinter を中心に、「すごろく」や「RPG」・「落ちものゲーム」を開発しながら Python プログラミングを学べる参考書になります。 初心者向け解説も多く、 Python の基本から GUI アプリの開発・ゲーム開発について学ぶ事ができます。

また初心者の方にとっては、楽しく Python を学べる点がオススメの理由です。ゲーム開発を通して Python プログラミングを学ぶ事ができ、自分の作成したプログラムの動作を実際に目で確認できるので楽しく勉強できま。

楽しいのでプログラミング学習のモチベーション低下も防ぐ事ができます。

とっつきやすさという点で、Python 入門者向け参考書としてはナンバーワンだと思います。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です