使用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程序