使用python实现简易截图功能
Published in:2024-08-19 |
Words: 1.5k | Reading time: 7min | reading:

使用python实现简易截图功能

技术方案

pyautogui

pyautogui 模块,使用screenshot() 函数和save() 函数实现

基础demo

  • 需要先安装pyautogui库
1
pip install pyautogui
  • 代码如下
1
2
3
4
5
6
7
import pyautogui

# 获取截图
image = pyautogui.screenshot()
#保存图片
image.save("test.jpg")

pyautogui和opencv

基础demo

pyautogui截取图片,opencv保存图片

  • 需要先安装pyautogui、opencv库
1
2
pip install pyautogui 
pip install opencv-python
  • 代码如下
1
2
3
4
5
6
7
8
9
10
11
12
import pyautogui
import numpy
import cv2

# 获取屏幕截图
image = pyautogui.screenshot()
# 转换图片
image = cv2.cvtColor(x.array(demo_image),cv2.COLOG_RGB2BGR)
# 写入图片
cv2.imwrite("test.png", image)
# 显示图片
cv2.imshow("test", image)

pillow

使用ImageGrap捕获捕捉屏幕的一部分

基础demo

  • 需要先安装pillow库
1
pip install pillow
  • 代码如下
1
2
3
4
5
6
7
8
from PIL import ImageGrab

# 设置获取的截图坐标
location = (60,60,60,60)
# 获取截图
screenshot = ImageGrab.grab(location)
# 保存图片到本地
screenshot.save("result.png")

pyscreenshot

较少使用

基础demo

  • 需要先安装pyscreenshot库
1
pip install pyscreenshot
  • 代码如下
1
2
3
4
5
6
import pyscreenshot

# 获取截图
demo = pyscreen.grab(location)
# 保存图片到本地
demo.save("result.png")

图片数据转移到剪贴板

使用windows系统API pywin32库

实现方法

安装pywin32库

1
pip install pywin32
  • 代码如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import win32clipboard as w
import win32con

# 打开剪贴
w.OpenClipboard()

# 清空剪切板
w.EmptyClipboard()

# 将图片数据设置到剪贴板
w.SetClipboardData(win32con.CF_DIB, data)

# 获取剪贴板内容
result = w.GetClipboardData(win32con.CF_TEXT)

# 解码数据
clipboard_content = d.decode('utf-8')

# 关闭剪贴板
w.CloseClipboard()

实际应用

简介

本案例通过按钮截取指定窗口内容并写入剪贴板,通过快捷键ctrl+v可粘贴到微信、qq、office等软件中。

代码

  • 截图至剪贴板功能实现
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
import pygetwindow as gw
from PIL import ImageGrab
import win32clipboard as w
import win32con
import io

from loguru import logger


@logger.catch
def get_win_screenshot():
"""
get screenshot
:return:
"""
try:
# 获取当前激活的窗口
active_window = gw.getActiveWindow()

# 获取窗口的边界框
box = active_window._getWindowRect()

# 根据边界框截取屏幕截图
screenshot = ImageGrab.grab(box)

size = screenshot.size

# 将Image转换为字节流,以便存储到剪贴板
img_bytes = io.BytesIO()
screenshot.convert("RGB").save(img_bytes, "BMP")
# image.convert("RGB").save(output_buffer, 'BMP')
data = img_bytes.getvalue()[14:]
img_bytes.seek(0)

# 打开剪贴
w.OpenClipboard()
w.EmptyClipboard()

# 将图片数据设置到剪贴板
w.SetClipboardData(win32con.CF_DIB, data)

# 关闭剪贴板
w.CloseClipboard()
logger.success(f"Screenshot success, image size: {size}")
return True
except Exception as e:
logger.error(f"Screen shot error, detail: {e}")
return False

  • 按钮触发事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QLineEdit, QTextEdit, QPushButton, QMenu, \
QMenuBar, QTabWidget, QMainWindow, QAction, QHBoxLayout, QLabel

def ui_init(self, _=None):
"""

:param self:
:param _:
:return:
"""
layout_main = QVBoxLayout()
layout_hon = QHBoxLayout()
self.screenshot_btn = QPushButton("screenshot", self)
layout_hon.addWidget(self.screenshot_btn)
self.screenshot_btn.clicked.connect(self.screenshot_method)

进阶使用-自由选择截图区域

简述

通过结合pyqt5与pillow可实现自由选择截图区域,选择完成后通过enter键保存图片至剪贴板,抑或使用esc键取消截图,自由度较高

实现

  • code
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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
import io
import sys
# import keyboard
import threading

import win32con
from PIL import ImageGrab
from PyQt5.QtWidgets import QApplication, QWidget, QDialog
from PyQt5.QtCore import Qt, qAbs, QRect
from PyQt5.QtGui import QPen, QPainter, QColor, QGuiApplication
from loguru import logger
import win32clipboard as w

from run import constants


# from utils.image_process import screenshot_img_save


class CaptureScreen(QDialog):
# 初始化变量
beginPosition = None
endPosition = None
fullScreenImage = None
captureImage = None
isMousePressLeft = None
painter = QPainter()

def __init__(self):
super(QWidget, self).__init__()
self.initWindow() # 初始化窗口
self.captureFullScreen() # 获取全屏

def initWindow(self):
self.setMouseTracking(True) # 鼠标追踪
self.setCursor(Qt.CrossCursor) # 设置光标
self.setWindowFlag(Qt.FramelessWindowHint) # 窗口无边框
self.setWindowState(Qt.WindowFullScreen) # 窗口全屏

def captureFullScreen(self):
self.fullScreenImage = QGuiApplication.primaryScreen().grabWindow(QApplication.desktop().winId())

def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.beginPosition = event.pos()
self.isMousePressLeft = True
if event.button() == Qt.RightButton:
# 如果选取了图片,则按一次右键开始重新截图
if self.captureImage is not None:
self.captureImage = None
self.paintBackgroundImage()
self.update()
else:
self.close()

def mouseMoveEvent(self, event):
if self.isMousePressLeft is True:
self.endPosition = event.pos()
self.update()

def mouseReleaseEvent(self, event):
self.endPosition = event.pos()
self.isMousePressLeft = False

def mouseDoubleClickEvent(self, event):
if self.captureImage is not None:
self.saveImage()
self.close()

def keyPressEvent(self, event):
if event.key() == Qt.Key_Escape:
constants.select_screenshot_flag = False
logger.debug("Screenshot cancel.")
self.close()
if event.key() == Qt.Key_Enter or event.key() == Qt.Key_Return:
if self.captureImage is not None:
self.saveImage()
self.close()

def paintBackgroundImage(self):
shadowColor = QColor(0, 0, 0, 100) # 黑色半透明
self.painter.drawPixmap(0, 0, self.fullScreenImage)
self.painter.fillRect(self.fullScreenImage.rect(), shadowColor) # 填充矩形阴影

def paintEvent(self, event):
self.painter.begin(self) # 开始重绘
self.paintBackgroundImage()
penColor = QColor(30, 144, 245) # 画笔颜色
self.painter.setPen(QPen(penColor, 1, Qt.SolidLine, Qt.RoundCap)) # 设置画笔,蓝色,1px大小,实线,圆形笔帽
if self.isMousePressLeft is True:
pickRect = self.getRectangle(self.beginPosition, self.endPosition) # 获得要截图的矩形框
self.captureImage = self.fullScreenImage.copy(pickRect) # 捕获截图矩形框内的图片
self.painter.drawPixmap(pickRect.topLeft(), self.captureImage) # 填充截图的图片
self.painter.drawRect(pickRect) # 画矩形边框
self.painter.end() # 结束重绘

def getRectangle(self, beginPoint, endPoint):
pickRectWidth = int(qAbs(beginPoint.x() - endPoint.x()))
pickRectHeight = int(qAbs(beginPoint.y() - endPoint.y()))
pickRectTop = beginPoint.x() if beginPoint.x() < endPoint.x() else endPoint.x()
pickRectLeft = beginPoint.y() if beginPoint.y() < endPoint.y() else endPoint.y()
pickRect = QRect(pickRectTop, pickRectLeft, pickRectWidth, pickRectHeight)
# 避免高度宽度为0时候报错
if pickRectWidth == 0:
pickRect.setWidth(2)
if pickRectHeight == 0:
pickRect.setHeight(2)

return pickRect

def saveImage(self):
# self.captureImage.save('picture.png', quality=95) # 保存图片到当前文件夹中
# self.captureImage.save
if constants.select_screenshot_flag:
# constants.select_screenshot_flag = True
save_img_threading_obj = threading.Thread(
target=screenshot_img_save,
args=(self,))
save_img_threading_obj.start()
# logger.info(f"Start save screenshot, {constants.select_screenshot_flag}")
return True
else:
logger.error("save screenshot ing, please wait.")
return False


@logger.catch
def screenshot_img_save(self):
"""

:param self:
:return:
"""
try:
# logger.debug("3424234")
if self.beginPosition.x() < self.endPosition.x():
x1 = self.beginPosition.x()
x2 = self.endPosition.x()
else:
x2 = self.beginPosition.x() + 2
x1 = self.endPosition.x()
if self.beginPosition.y() < self.endPosition.y():
y1 = self.beginPosition.y()
y2 = self.endPosition.y()
else:
y2 = self.beginPosition.y() + 2
y1 = self.endPosition.y()
box = [x1, y1, x2, y2]
screenshot = ImageGrab.grab(box)
# size = screenshot.size

img_bytes = io.BytesIO()
screenshot.convert("RGB").save(img_bytes, "BMP")
# image.convert("RGB").save(output_buffer, 'BMP')
data = img_bytes.getvalue()[14:]
img_bytes.seek(0)
# logger.debug("3133131")

# 打开剪贴
w.OpenClipboard()
w.EmptyClipboard()

# 将图片数据设置到剪贴板
w.SetClipboardData(win32con.CF_DIB, data)

# 关闭剪贴板
w.CloseClipboard()
logger.success(f"Screenshot success, image select region: {self.beginPosition} : {self.endPosition}")
constants.select_screenshot_flag = False
except Exception as e:
logger.error(f"Unknown error, detail: {e}")
constants.select_screenshot_flag = False


@logger.catch
def screenshot_select():
"""

:return:
"""
# keyboard.wait(hotkey='f4') # 按F4开始截图
# app = QApplication(sys.argv)
windows = CaptureScreen()
windows.show()
windows.exec()
# sys.exit(app.exec_())

效果如下图所示:

  • 效果图

img

Prev:
python 使用tesseract实现实时监控桌面
Next:
使用clion工具编写cpp qt demo程序