PySideで範囲スクリーンショットを作る

以前Blogで書いていた記事が色々古かったのでPySide2で書き直してみました。
とりあえず全コード。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# -*- coding: utf-8 -*-
"""
範囲指定でScreenShotを撮影するスクリプト
"""
import sys
from PySide2.QtWidgets import (QWidget, QApplication)
from PySide2.QtGui import (QPixmap, QPainter, QPainterPath, QColor, QBrush)
from PySide2.QtCore import (Qt, QRect)


class ScreenShot(QWidget):

    def __init__(self, parent=None):

        super().__init__(parent)

        # 現在の画面をキャプチャー
        screen = QApplication.primaryScreen()
        self.originalPixmap = screen.grabWindow(QApplication.desktop().winId())

        self.endpos = None
        self.stpos = None

    def paintEvent(self, event):

        p = QPainter()
        p.begin(self)
        p.setPen(Qt.NoPen)

        rectSize = QApplication.desktop().screenGeometry()
        p.drawPixmap(rectSize, self.originalPixmap)

        if self.endpos and self.stpos:

            pp = QPainterPath()
            pp.addRect(rectSize)
            pp.addRoundRect(QRect(self.stpos, self.endpos), 0, 0)
            p.setBrush(QBrush(QColor(0, 0, 100, 100)))
            p.drawPath(pp)

        p.end()

    def mouseMoveEvent(self, event):

        self.endpos = event.pos()
        # マウスが動いたときに、再度描画処理を実行する
        self.repaint()

    def mousePressEvent(self, event):

        self.stpos = event.pos()

    def mouseReleaseEvent(self, event):

        self.endpos = event.pos()
        self.screenShot()

    def screenShot(self):

        # 切り取り処理をして保存後、ツールを終了する
        pmap = self.originalPixmap.copy(QRect(self.stpos, self.endpos))
        pmap.save("E:/test.jpg")
        self.close()


if __name__ == '__main__':

    app = QApplication(sys.argv)
    wid = ScreenShot()
    wid.showFullScreen()
    sys.exit(app.exec_())

まず、スクリーンキャプチャを作るためには QWidgetsまたはQMainWindowを使用します。
PySideの各種イベントはGUIの上でないと発生しないというトラップがあるので
表示を show()ではなく showFullScreen() にすることで全画面にします。

それだとただの全画面GUIになってしまうので
現在のWindowのスクリーンの画像を取得して、それをpaintEvent内で画面全体に対して描画します。

1
2
3
        # 現在の画面をキャプチャー
        screen = QApplication.primaryScreen()
        self.originalPixmap = screen.grabWindow(QApplication.desktop().winId())

現在の画面をキャプチャし、QPixmapを取得します。

1
2
        rectSize = QApplication.desktop().screenGeometry()
        p.drawPixmap(rectSize, self.originalPixmap)

そしてその画像をpaintEventで描画させます。

画面のキャプチャー方法は、以前とは多少変わっていて

1
QtGui.QPixmap.grabWindow(QtGui.QApplication.desktop().winId())

QPixmapにある glabWindowを使っていましたが、今は非推奨で
上のサンプルのように、 QScreenからgrabWindowで取得するのが正解とのこと。

あとは、マウスをDrag&Dropしている間、切り抜く矩形範囲がわかりやすいように
addRect で矩形を描画しています。
矩形の開始位置はマウスをクリック瞬間にセットして、
それ以降はマウスが動くたびに右下の位置をアップデートさせるようにしています。

あとはマウスの範囲でQPixmapを切り抜いて jpg で保存すれば完了です。

全画面にして現在のWindowを描画するというのはわりと応用が利くので
paintEvent での Qpainter の使い方と併せて勉強すればいろんな事が出来そうです。