Install following packages:
pip install pillow opencv-python pyside2
Run the following code:
import sys
from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *
import numpy as np
import cv2
from PIL import ImageGrab
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
if not MainWindow.objectName():
MainWindow.setObjectName(u"MainWindow")
MainWindow.resize(1000, 1000)
sizePolicy = QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth())
MainWindow.setSizePolicy(sizePolicy)
MainWindow.setMinimumSize(QSize(1000, 1000))
MainWindow.setMaximumSize(QSize(16777215, 16777215))
MainWindow.setTabShape(QTabWidget.Rounded)
self.centralwidget = QWidget(MainWindow)
self.centralwidget.setObjectName(u"centralwidget")
sizePolicy1 = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
sizePolicy1.setHorizontalStretch(0)
sizePolicy1.setVerticalStretch(0)
sizePolicy1.setHeightForWidth(self.centralwidget.sizePolicy().hasHeightForWidth())
self.centralwidget.setSizePolicy(sizePolicy1)
self.centralwidget.setMinimumSize(QSize(1000, 1000))
self.gridLayout = QGridLayout(self.centralwidget)
self.gridLayout.setObjectName(u"gridLayout")
self.pushButton_area = QPushButton(self.centralwidget)
self.pushButton_area.setObjectName(u"pushButton_area")
self.pushButton_area.setMinimumSize(QSize(800, 0))
self.gridLayout.addWidget(self.pushButton_area, 0, 0, 1, 1)
self.label = QLabel(self.centralwidget)
self.label.setObjectName(u"label")
sizePolicy2 = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
sizePolicy2.setHorizontalStretch(0)
sizePolicy2.setVerticalStretch(0)
sizePolicy2.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth())
self.label.setSizePolicy(sizePolicy2)
self.label.setMinimumSize(QSize(800, 800))
self.label.setMaximumSize(QSize(4096, 4096))
self.gridLayout.addWidget(self.label, 2, 0, 2, 1)
self.pushButton_full = QPushButton(self.centralwidget)
self.pushButton_full.setObjectName(u"pushButton_full")
self.pushButton_full.setMinimumSize(QSize(800, 0))
self.gridLayout.addWidget(self.pushButton_full, 1, 0, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"Snipping Tool", None))
MainWindow.setAccessibleName(QCoreApplication.translate("MainWindow", u"Snipping Tool", None))
self.pushButton_area.setText(QCoreApplication.translate("MainWindow", u"Select Area", None))
self.pushButton_full.setText(QCoreApplication.translate("MainWindow", u"Fullscreen", None))
# Refer to https://github.com/harupy/snipping-tool
class SnippingWidget(QWidget):
is_snipping = False
def __init__(self, parent=None, app=None):
super(SnippingWidget, self).__init__()
self.parent = parent
self.setWindowFlags(Qt.WindowStaysOnTopHint)
self.screen = app.primaryScreen()
self.setGeometry(0, 0, self.screen.size().width(), self.screen.size().height())
self.begin = QPoint()
self.end = QPoint()
self.onSnippingCompleted = None
def fullscreen(self):
img = ImageGrab.grab(bbox=(0, 0, self.screen.size().width(), self.screen.size().height()))
try:
img = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
except:
img = None
if self.onSnippingCompleted is not None:
self.onSnippingCompleted(img)
def start(self):
SnippingWidget.is_snipping = True
self.setWindowOpacity(0.3)
QApplication.setOverrideCursor(QCursor(Qt.CrossCursor))
self.show()
def paintEvent(self, event):
if SnippingWidget.is_snipping:
brush_color = (128, 128, 255, 100)
lw = 3
opacity = 0.3
else:
self.begin = QPoint()
self.end = QPoint()
brush_color = (0, 0, 0, 0)
lw = 0
opacity = 0
self.setWindowOpacity(opacity)
qp = QPainter(self)
qp.setPen(QPen(QColor('black'), lw))
qp.setBrush(QColor(*brush_color))
rect = QRectF(self.begin, self.end)
qp.drawRect(rect)
def mousePressEvent(self, event):
self.begin = event.pos()
self.end = self.begin
self.update()
def mouseMoveEvent(self, event):
self.end = event.pos()
self.update()
def mouseReleaseEvent(self, event):
SnippingWidget.is_snipping = False
QApplication.restoreOverrideCursor()
x1 = min(self.begin.x(), self.end.x())
y1 = min(self.begin.y(), self.end.y())
x2 = max(self.begin.x(), self.end.x())
y2 = max(self.begin.y(), self.end.y())
self.repaint()
QApplication.processEvents()
img = ImageGrab.grab(bbox=(x1, y1, x2, y2))
try:
img = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
except:
img = None
if self.onSnippingCompleted is not None:
self.onSnippingCompleted(img)
self.close()
class MainWindow(QMainWindow):
useQThread = True
def __init__(self):
super(MainWindow, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.setAcceptDrops(True)
self.snippingWidget = SnippingWidget(app=QApplication.instance())
self.snippingWidget.onSnippingCompleted = self.onSnippingCompleted
self.ui.pushButton_area.clicked.connect(self.snipArea)
self.ui.pushButton_full.clicked.connect(self.snipFull)
self._pixmap = None
def onSnippingCompleted(self, frame):
self.setWindowState(Qt.WindowActive)
if frame is None:
return
image = QImage(frame, frame.shape[1], frame.shape[0], frame.strides[0], QImage.Format_RGB888)
pixmap = QPixmap.fromImage(image)
self._pixmap = self.resizeImage(pixmap)
self.ui.label.setPixmap(self._pixmap)
def snipArea(self):
self.setWindowState(Qt.WindowMinimized)
self.snippingWidget.start()
def snipFull(self):
self.setWindowState(Qt.WindowMinimized)
self.snippingWidget.fullscreen()
def dragEnterEvent(self, event):
event.acceptProposedAction()
def dropEvent(self, event):
urls = event.mimeData().urls()
filename = urls[0].toLocalFile()
self.loadFile(filename)
self.decodeFile(filename)
event.acceptProposedAction()
def resizeImage(self, pixmap):
lwidth = self.ui.label.width()
pwidth = pixmap.width()
lheight = self.ui.label.height()
pheight = pixmap.height()
wratio = pwidth * 1.0 / lwidth
hratio = pheight * 1.0 / lheight
if pwidth > lwidth or pheight > lheight:
if wratio > hratio:
lheight = pheight / wratio
else:
lwidth = pwidth / hratio
scaled_pixmap = pixmap.scaled(lwidth, lheight)
return scaled_pixmap
else:
return pixmap
def showMessageBox(self, title, content):
msgBox = QMessageBox()
msgBox.setWindowTitle(title)
msgBox.setText(content)
msgBox.exec_()
def closeEvent(self, event):
msg = "Close the app?"
reply = QMessageBox.question(self, 'Message',
msg, QMessageBox.Yes, QMessageBox.No)
if reply == QMessageBox.Yes:
event.accept()
else:
event.ignore()
def main():
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
