当前位置: 首页 > news >正文

[Python]用Qt6和Pillow实现截图小工具

        本文章主要讲述的内容是,使用python语言借助PyQt6和Pillow库进行简单截图工具的开发,含义一个简单的范围裁剪和软件界面。

        主要解决的问题是,在高DPI显示屏下,坐标点的偏差导致QWidget显示图片不全、剪裁范围偏差问题。

        适合有一点点基础的朋友来看,使用的工具有:Qt Designer、PyUIC、Qt6、Pillow

截图与剪裁功能设计思路

一般截图功能的步骤是:

  1. 启用截图功能
  2. 将整个屏幕进行截取,保存截取的全屏图片
  3. 呈现出刚刚截取的全屏,由用户选择截取的范围。并对所选的范围进行剪裁
  4. 保存剪裁的图片,删除截取的全屏

利用QtDesigner对软件前端的简单制作

mainWindow-主界面

这里不是重点,就新建一个Main Window后放置一个pushButton就好了。

并使用PyUIC对保存后的ui转换成.py格式

 minorWindow-副界面

创建一个简单的Widget就好了,副界面主要是作用是:呈现原图,提供剪裁的平台。

并使用PyUIC对保存后的ui转换成.py格式

主界面代码编写

主要是作用是:

  1. 为截图功能提供一个启动方法
  2. 保存截取的全屏幕截图。
import timefrom PIL import ImageGrab
from PyQt6 import QtWidgetsfrom shDemo import mainWindow
from shDemo import minorWindow# 继承我们前面编写的主界面的前端.py,以及对应的QMainWindow
class screenshot(QtWidgets.QMainWindow, mainWindow.Ui_MainWindow):def __init__(self):super().__init__()self.setupUi(self)  # 调用主界面的setupUIself.pushButton.clicked.connect(self.screenshot)  # 绑定pushButton按钮到screenshot事件上# 按钮被点击后触发此方法def screenshot(self):# 把当前窗口最小化self.showMinimized()# 等待1秒,给窗口最小化的时间time.sleep(1)# 截取全屏img = ImageGrab.grab()# 暂存全屏图片 保存到本地img.save('屏幕快照.png')# 生成副窗口self.childWidget = minorWindow.Ui_jieping()# 展示副窗口self.childWidget.show()# 完成剪裁工作,恢复主窗口self.showNormal()if __name__ == '__main__':app = QtWidgets.QApplication([])window = screenshot()window.show()app.exec()

副界面代码编写

因为此处的副界面是被调用的,我们直接在其ui转换后的.py文件上进行编写,拓展其方法

继承一下QWidget,调用一下setupUi

class Ui_jieping(QtWidgets.QWidget):def __init__(self):super().__init__()self.setupUi(self)

原截图呈现、范围绘制与范围截取

要注意的就是,呈现的像素比率,截取的坐标点

主要思路是,将保存好的原截图,呈现到一个QWidget(副界面)上进行显示。

这里有一个问题,就是关于屏幕DPI不同

重写一下paintEvent方法,这是一个QWidget类中原有方法,是一个绘制组件的事件。被调用的情况有如下:

  1. 窗口初始化和显示
  2. 部件大小或位置发生变化
  3. 强制重绘,使用update()或repaint()时
  4. 系统事件触发,如窗口激活

像素比率 

像素比率 = 物理像素尺寸 / 逻辑像素尺寸

         为了适应不同应用,获得更好的视觉感官,一般可以调整缩放与布局。调整到比较高的DPI,获得一个更好体验。

        屏幕缩放比例为125%,意味着逻辑像素将比物理像素更大,以便内容在屏幕上看起来更大。缩放比例125%可以表示为1.25的倍数。

        在缩放比例为125%的情况下,1920*1080的显示屏中逻辑像素的分辨率将变为1536x864。 

        显示图片时需要转换为逻辑尺寸,以确保在不同DPI的显示器上图像显示的尺寸一致。然而,截图抓取的坐标点是物理像素坐标的,因为截图本质上是对屏幕上实际像素的捕捉。

        所以在显示的时候,按照屏幕的逻辑尺寸进行展示。实际抓取的时候,要转成物理尺寸进行截取,根据像素比率对图片显示进行对应调整后就不影响图片的显示或坐标点的偏差

import typingfrom PIL import ImageGrab
from PyQt6 import QtCore, QtGui, QtWidgets
from PyQt6.QtGui import QPainter, QPixmap, QPen, QColorclass Ui_jieping(QtWidgets.QWidget):def __init__(self):super().__init__()self.setupUi(self)# 记录截取的第一个坐标点self.firstPoint = QtCore.QPoint()# 记录截取的第二个坐标点self.endPoint = QtCore.QPoint()# 将子窗口设置在屏幕最上层# self.setWindowFlag(QtCore.Qt.WindowType.WindowStaysOnTopHint)# 让其全屏显示self.setWindowState(QtCore.Qt.WindowState.WindowFullScreen)# 重写QWidget的painEvent方法,这个在初始启动的时候会调用def paintEvent(self, a0: typing.Optional[QtGui.QPaintEvent]) -> None:# 生成一个画板painter = QPainter(self)# 读取本地先前在主界面截图的图像# 在QT中图片放到组件上一般要转成pixmappixmap = QPixmap('./屏幕快照.png')# 获取主屏幕对象screen = QtGui.QGuiApplication.primaryScreen()# 获取设备像素比率  物理像素与逻辑像素之间的比率self.device_pixel_ratio = screen.devicePixelRatio()# 计算实际绘制尺寸# 在显示和编程的时候,是按照逻辑像素取进行展示与设计# 逻辑尺寸= 物理尺寸 / 像素比  计算出符合当前屏幕的尺寸actual_width = pixmap.width() / self.device_pixel_ratioactual_height = pixmap.height() / self.device_pixel_ratio# 绘制图片# 0,0的意思是,从屏幕左上角作为起始点,如果此时的逻辑尺寸与屏幕的一致,就作为全屏展示painter.drawPixmap(0, 0, int(actual_width), int(actual_height), pixmap)# 将截图画框显示为红色pen = QPen(QColor(255, 0, 0))painter.setPen(pen)# 绘制矩形的方法,其中的参数来自鼠标事件 显示要截图的范围 在绘制的时候还会调用update来触发paintEvent方法# 从第一个记录点开始# 记住0,0是屏幕最坐上角# 向右self.endPoint.x() - self.firstPoint.x()个像素 作为长# 向下self.endPoint.y() - self.firstPoint.y()个像素 作为高# 得到负数也没关系噢,x方向上负数就是往左, y方向上负数是向上painter.drawRect(self.firstPoint.x(), self.firstPoint.y(), self.endPoint.x() - self.firstPoint.x(),self.endPoint.y() - self.firstPoint.y())# 在鼠标按下的时候触发此事件def mousePressEvent(self, a0: typing.Optional[QtGui.QMouseEvent]) -> None:# 记录按下的第一个坐标点self.firstPoint = a0.pos()# 在鼠标移动的时候触发此事件def mouseMoveEvent(self, a0: typing.Optional[QtGui.QMouseEvent]) -> None:# 记录移动过程中的当前鼠标的坐标点self.endPoint = a0.pos()self.update()  # 触发paintEvent,在移动鼠标的时候不断重绘截图边框# 在鼠标松开的时候触发此事件def mouseReleaseEvent(self, a0: typing.Optional[QtGui.QMouseEvent]) -> None:self.endPoint = a0.pos()  # 锁定最后松开的坐标self.update()  # 更新在Widget上的所选范围矩形# 在原图上进行对所选区域的截取# 此处截图的时候,也要记得调整一下 从逻辑像素转换成为物理像素进行抓取# 不然截图出来会有偏差# 物理像素 = 逻辑像素 * 像素比率self.firstPoint.setX(int(self.firstPoint.x() * self.device_pixel_ratio))self.firstPoint.setY(int(self.firstPoint.y() * self.device_pixel_ratio))self.endPoint.setX(int(self.endPoint.x() * self.device_pixel_ratio))self.endPoint.setY(int(self.endPoint.y() * self.device_pixel_ratio))# 最后借助PIL进行对屏幕固定范围进行抓取# 这里有一个坑 在从右向左,从下到上进行画范围截图的时候,会有一个报错# 因为grab的参数是,左上角和右下角坐标点的x和y值# firstPoint和endPoint又是一开始写死的# 可以比较一下两者的位置,如果endPoint比firstPoint小,就可以互换一下if self.firstPoint.x() > self.endPoint.x() and self.firstPoint.y() > self.endPoint.y():self.firstPoint, self.endPoint = self.endPoint, self.firstPointimage = ImageGrab.grab(bbox=(self.firstPoint.x() + 1, self.firstPoint.y() + 1, self.endPoint.x() - 1, self.endPoint.y() - 1))# 将范围截取下来的进行保存image.save('hello.png')# 就可以将先前截的全屏删掉了# os.remove('./屏幕快照.png')# 关闭全屏显示的子窗口self.close()def setupUi(self, jieping):jieping.setObjectName("jieping")jieping.resize(400, 300)self.retranslateUi(jieping)QtCore.QMetaObject.connectSlotsByName(jieping)def retranslateUi(self, jieping):_translate = QtCore.QCoreApplication.translatejieping.setWindowTitle(_translate("jieping", "Form"))

在不同的DPI下截取出来的图片都是一样滴,大家可以去试一下

相关文章:

[Python]用Qt6和Pillow实现截图小工具

本文章主要讲述的内容是,使用python语言借助PyQt6和Pillow库进行简单截图工具的开发,含义一个简单的范围裁剪和软件界面。 主要解决的问题是,在高DPI显示屏下,坐标点的偏差导致QWidget显示图片不全、剪裁范围偏差问题。 适合有一点…...

Podman和Docker的区别

Podman 和 Docker 都是用于容器化的工具,但它们在架构、安全性、容器编排以及一些设计理念上有显著的区别: 架构设计: Docker 使用客户端-服务器(C/S)架构,包含一个名为 dockerd 的守护进程,该进程以 root …...

Go微服务: 分布式Cap定理和Base理论

分布式中的Cap定理 CAP理论 C: 一致性,是站在分布式的角度,要么读取到数据,要么读取失败,比如数据库主从,同步时的时候加锁,同步完成才能读到同步的数据,同步完成,才返回数据给程序&…...

Mysql学习(四)——SQL通用语法之DQL

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 DQLDQL-语法基本查询条件查询聚合函数分组查询排序查询分页查询 DQL DQL数据查询语言,用来查询数据库中表的记录。 DQL-语法 select 字段列表 from 表…...

【ARFoundation自学05】人脸追踪(AR Face manager)实现

1. 修改摄像机朝向渲染方式-选中user 这个方式就会调用前置摄像头 2 创建 AR Session、XR Origin,然后在XR Origin上面添加组件 注意:XR Origin 老版本仍然叫 AR Session Origin 接下来在XR Origin上面添加AR Face Manager组件,如下图&am…...

Vulnhub-DC-2

靶机IP:192.168.20.135 网络有问题的可以看下搭建Vulnhub靶机网络问题(获取不到IP) kaliIP:192.168.20.128 扫描靶机端口及服务版本 发现开放了80和7744端口 并且是wordpress建站 dirsearch扫描目录 访问前端界面,发现存在重定向 在hosts文件中增加192.168.2…...

VNC server ubuntu20 配置

介绍 最近想使用实验室的4卡服务器跑一些深度学习实验,因为跑的是三维建图实验,需要配上可视化界面,本来自带的IPMI可以可视化,但分辨率固定在640*480,看起来很别扭,就捣鼓服务器远程可视化访问了两天&…...

c++--priority_queue和仿函数

目录 1.priority_queue 实现: 2.仿函数 priority_queue仿函数 实现代码 1.priority_queue 优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的,其实就是个堆,默认是大根堆。…...

Harmony os Next——关系型数据库relationalStore.RdbStore的使用

Harmony os Next——关系型数据库relationalStore.RdbStore的使用 描述数据库的使用建表定义表信息创建数据库表 创建数据库操作对象增更新查询删数据库的初始化 描述 本文通过存储一个简单的用户信息到数据库中为例,进行阐述relationalStore.RdbStore数据库的CRUD…...

快手直播限流怎么办?

直播限流怎么办?这期把直播间限流的所有原因都讲得明明白白,如果你直播间昨天还播的好好的,今天突然间贴地飞行,按照这个思路框架去排查,准没问题。 第一件事情肯定是排查一下评分问题, 信用分、口碑分、…...

【MySQL】数据库入门基础

文章目录 一、数据库的概念1. 什么是数据库2. 主流数据库3. mysql和mysqld的区别 二、MySQL基本使用1. 安装MySQL服务器在 CentOS 上安装 MySQL 服务器在 Ubuntu 上安装 MySQL 服务器验证安装 2. 服务器管理启动服务器查看服务器连接服务器停止服务器重启服务器 3. 服务器&…...

cannot allocate memory in static TLS block

如果不是内存太小,那是不是因为glibc太旧呢? 考虑 glibc 2.22 以后的版本。 glibc-2.22 中加入了如下commit:f8aeae347377f3dfa8cbadde057adf1827fb1d44 https://sourceware.org/git/?pglibc.git;acommit;hf8aeae347377f3dfa8cbadde057adf1…...

Leetcode 654:最大二叉树

给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点,其值为 nums 中的最大值。递归地在最大值 左边 的 子数组前缀上 构建左子树。递归地在最大值 右边 的 子数组后缀上 构建右子树。 返回 nums 构建的 最大二叉树…...

uniapp小程序src引用服务器图片时全局变量与图片路径拼接

理论上&#xff0c;应该在main.js中定义一个全局变量&#xff0c;然后在页面的<image>标签上的是src直接使用即可 main.js 页面上 看上去挺靠谱的&#xff0c;实际上小程序后台会报一个错 很明显这种方式小程序是不认的&#xff0c;这就头疼了&#xff0c;还想过另外一个…...

比较PWM调光和无极调光

在比较PWM调光和无极调光哪种方式更节能时&#xff0c;需要综合考虑多个因素&#xff0c;如灯具类型、光源效率、调光范围以及使用场景等。 PWM调光系统通过调节LED驱动电流的占空比来实现LED亮度的调节&#xff0c;具有高精度、高稳定性、无闪烁现象以及适用范围广等优点。其节…...

【高校科研前沿】新疆生地所陈亚宁研究员团队在GeoSus发文:在1.5°C和2°C全球升温情景下,中亚地区暴露于极端降水的人口增加

目录 文章简介 1.研究内容 2.相关图件 3.文章引用 文章简介 论文名称&#xff1a;Increased population exposures to extreme precipitation in Central Asia under 1.5 ◦C and 2 ◦C global warming scenarios&#xff08;在1.5C和2C全球变暖情景下&#xff0c;中亚地区…...

使用 OKhttp3 实现 智普AI ChatGLM HTTP 调用(SSE、异步、同步)

SSE 调用 SSE&#xff08;Sever-Sent Event&#xff09;&#xff0c;就是浏览器向服务器发送一个HTTP请求&#xff0c;保持长连接&#xff0c;服务器不断单向地向浏览器推送“信息”&#xff08;message&#xff09;&#xff0c;这么做是为了节约网络资源&#xff0c;不用一直…...

智慧校园教学模式的崛起:优化学习体验

在当今数字化时代&#xff0c;智慧校园教学模式正在成为教育界的热门话题。随着科技的不断发展&#xff0c;传统的教学方式已经无法满足现代学生的需求。智慧校园教学模式以其灵活性、互动性和个性化的特点&#xff0c;正逐渐改变着教育的面貌。 首先&#xff0c;智慧校园教学模…...

ffmpeg视频编码原理和实战-(5)对编码过程进行封装并解决丢帧问题

头文件&#xff1a; xencode.h #pragma once #include <mutex> #include<vector> struct AVCodecContext; struct AVPacket; struct AVFrame; class XEncode { public:///// 创建编码上下文/// para codec_id 编码器ID号&#xff0c;对应ffmpeg/// return 编码上…...

halo进阶-主题插件使用

开始捣鼓捣鼓halo&#xff0c;换换主题&#xff0c;加个页面 可参考&#xff1a;Halo 文档 安装/更新主题 主题如同壁纸&#xff0c;萝卜青菜各有所爱&#xff0c;大家按需更换即可&#xff1b; Halo好在一键更换主题&#xff0c;炒鸡方便。 安装/更新插件 此插件还扩展了插件…...

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...

设计模式和设计原则回顾

设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)

HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望

文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例&#xff1a;使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例&#xff1a;使用OpenAI GPT-3进…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)

文章目录 1.什么是Redis&#xff1f;2.为什么要使用redis作为mysql的缓存&#xff1f;3.什么是缓存雪崩、缓存穿透、缓存击穿&#xff1f;3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版​分享

平时用 iPhone 的时候&#xff0c;难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵&#xff0c;或者买了二手 iPhone 却被原来的 iCloud 账号锁住&#xff0c;这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

【第二十一章 SDIO接口(SDIO)】

第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例

文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI

前一阵子在百度 AI 开发者大会上&#xff0c;看到基于小智 AI DIY 玩具的演示&#xff0c;感觉有点意思&#xff0c;想着自己也来试试。 如果只是想烧录现成的固件&#xff0c;乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外&#xff0c;还提供了基于网页版的 ESP LA…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)

🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...