PythonからWindowsのクリップボードに画像をコピーする

PythonのPillowモジュールのイメージオブジェクトを、Windows10のクリップボードにビットマップ画像としてコピーします。

目次

  1. Python for windows extensions
  2. Pillow ImageオブジェクトをWindows bitmapに変換する
  3. クリップボードへ画像をコピーする例

Python for windows extensions

Pillowやtkinterにクリップボードへのアクセスの方法があるようなのですが、画像をクリップボードからダウンロードする方法はドキュメントを見ても見つかりませんでした。

そこで、 Pywin32(Python for windows extensions) を使ってクリップボードにアクセスします。

GitHubのreadmeにはpipでのインストールはexperimental(Release 224時点)と書かれていたので、 ダウンロードサイト から適当なものをダウンロードしてインストールしました。

Pywin32をインストールすると、win32clipboardというモジュールを使えるようになります。このモジュールに含まれているメソッドを使って

  1. クリップボードを開く。
  2. クリップボードをクリアする。
  3. クリップボードにデータをセットする。
  4. クリップボードを閉じる。

ということをします。

データをセットするメソッドはこのようなものです。詳しくは マニュアル を参照してください。

ret = win32clipboard.SetClipboardData(format, hMem )
変数 内容
format   クリップボードにセットするデータの書式。
hMem int/buffer セットするデータ。
ret int データのハンドル。

画像をコピーする場合は、formatはCF_DIBのようです。

Pillow ImageオブジェクトをWindows bitmapに変換する

PillowのImageオブジェクトをそのままセットしようとすると(たぶん)エラーになります。ndarrayですからね。

ところが、PillowにはBitmapオブジェクトに変換するコマンドが見当たりません。

そこで、メモリストリームにbitmap形式で出力して、そのメモリストリーム上のデータを読み込んでから、SetClipboardDataメソッドに渡すことにします。

こんな感じですね。

import io
from PIL import Image

output = io.BytesIO()
image.convert('RGB').save(output, 'BMP')
data = output.getvalue()[14:]
output.close()

オープンしたものはクローズすることを忘れずに。

クリップボードへ画像をコピーする例

プロ生ちゃん の画像をtkinterで表示して、クリップボードにコピーして、ペイントにペーストしてみました。

クリップボードにデータをセットする側のコードはこんな感じです。

import tkinter
import tkinter.ttk
from PIL import Image, ImageTk
import win32clipboard
import io

class Application(tkinter.Frame):
    def __init__(self, master=None):
        super().__init__(master)
        self.master = master
        self.master.title('clipboard trial')
        self.pack()
        self.create_widgets()

    def create_widgets(self):
        # ボタン
        self.original_button = tkinter.ttk.Button(self, text='Copy to Clipboard')
        self.original_button.grid(row=0, column=1)
        self.original_button.bind('<Button-1>', copy_to_clipboard)

        # canvas
        self.test_canvas = tkinter.Canvas(self, width=original_image.width, height=original_image.height)
        self.test_canvas.grid(row=0, column=0)

        # canvasに初期画像を表示
        self.test_canvas.photo = ImageTk.PhotoImage(original_image)
        self.image_on_canvas = self.test_canvas.create_image(0, 0, anchor='nw', image=self.test_canvas.photo)

def copy_to_clipboard(event):
    # メモリストリームにBMP形式で保存してから読み出す
    output = io.BytesIO()
    original_image.convert('RGB').save(output, 'BMP')
    data = output.getvalue()[14:]
    output.close()
    send_to_clipboard(win32clipboard.CF_DIB, data)

def send_to_clipboard(clip_type, data):
    # クリップボードをクリアして、データをセットする
    win32clipboard.OpenClipboard()
    win32clipboard.EmptyClipboard()
    win32clipboard.SetClipboardData(clip_type, data)
    win32clipboard.CloseClipboard()

# 画像ファイル読み込み
original_image = Image.open('test_figure.png')

# アプリケーション起動
root = tkinter.Tk()
app = Application(master=root)
app.mainloop()

copy_to_clipboardという関数で、PillowのImageオブジェクトからビットマップへ変換します。

send_to_clipboardという関数で、データをクリップボードにセットします。

動かしてみるとこんな感じです。

広告

PythonでGUIカテゴリの投稿