Python+PyQt5开发一个图片尺寸修改器

 更新时间:2025年03月03日 14:10:44   作者:一晌小贪欢  
我们在日常办公时,经常需要将图片进行修改尺寸,本文将使用python和PyQt5开发一个方便图片修改尺寸工具,感兴趣的小伙伴可以了解一下

1、库的介绍

我们在日常办公时,经常需要将图片进行修改尺寸,比如上一些网址非常的不便捷,可以利用python+PyQt5写一个方便图片修改尺寸的代码

2、库的安装

用途安装
PyQt5界面设计pip install PyQt5 -i https://pypi.tuna.tsinghua.edu.cn/simple/
pillow图片处理pip install pillow -i https://pypi.tuna.tsinghua.edu.cn/simple/

3、代码结构

1. init

  • 初始化窗口组件和变量。
  • 设置窗口标题、最小宽度,并调用 initUI 方法初始化用户界面。
  • 初始化一些状态变量,如 width_connected 和 height_connected(用于控制宽度和高度输入框之间的联动),以及图片路径和原始尺寸。

2. initUI

构建主窗口的布局和控件。

包括:

  • 文件选择区域(按钮和标签)。
  • 图片显示区域(支持拖放功能)。
  • 宽度和高度输入框。
  • 锁定比例复选框。
  • 保存按钮和状态标签。
  • 设置布局并初始化锁定比例功能。

3. dragEnterEvent

处理拖拽事件,判断是否允许文件拖放到图片显示区域。

如果拖拽的是文件,则接受该操作。

4. dropEvent

处理文件拖放到图片显示区域后的事件。

检查文件类型是否为图片(支持 .png, .jpg, .jpeg, .bmp),如果是,则加载图片。

5. loadImage

加载指定路径的图片。

使用 Pillow 库读取图片的原始尺寸,并更新预览图片。

初始化宽度和高度输入框的值为图片的原始尺寸。

启用保存按钮,并在状态标签中显示“图片已加载”。

6. selectImage

打开文件对话框,让用户选择图片文件。

如果用户选择了有效文件,则调用 loadImage 方法加载图片。

7. updatePreview

更新图片预览区域。

根据当前图片路径生成缩略图,并保持宽高比。

8. onLockAspectRatioChanged

处理锁定比例复选框的状态变化。

如果勾选了锁定比例:

连接宽度输入框和高度输入框的 textChanged 信号,实现两者联动。

如果取消勾选:

断开宽度和高度输入框的信号连接。

9. updateHeightFromWidth

当宽度输入框的值发生变化时,根据锁定比例计算并更新高度输入框的值。

防止递归调用导致死循环(通过临时断开高度输入框的信号连接)。

10. updateWidthFromHeight

当高度输入框的值发生变化时,根据锁定比例计算并更新宽度输入框的值。

同样防止递归调用导致死循环。

11. saveImage

保存调整后的图片。

获取用户输入的宽度和高度,检查其有效性。

使用 Pillow 库调整图片大小,并通过文件对话框选择保存路径。

如果保存成功,在状态标签中显示保存路径,并弹出提示框。

12. main

程序入口。

创建 QApplication 实例,初始化 ResizeImageTool 窗口,并进入主事件循环。

4、完整代码

# -*- coding: UTF-8 -*-
'''
@Project :测试 
@File    :test1.py
@IDE     :PyCharm 
@Author  :一晌小贪欢(278865463@qq.com)
@Date    :2025/3/1 21:07 
'''

import sys
from PyQt5.QtWidgets import (QApplication, QWidget, QVBoxLayout, QPushButton,
                             QLabel, QLineEdit, QFileDialog, QHBoxLayout,
                             QCheckBox, QMessageBox, QSpacerItem, QSizePolicy)
from PyQt5.QtGui import QPixmap, QIntValidator, QDragEnterEvent, QDropEvent
from PyQt5.QtCore import Qt
from PIL import Image


class ResizeImageTool(QWidget):
    def __init__(self):
        super().__init__()
        self.width_connected = False
        self.height_connected = False
        self.preview_size = 400  # 预览图片的最大尺寸
        self.initUI()

    def initUI(self):
        self.setWindowTitle('图片大小调整工具')
        self.setMinimumWidth(500)

        # 设置主布局
        self.layout = QVBoxLayout()
        self.layout.setSpacing(10)

        # 添加文件选择区域
        file_layout = QHBoxLayout()
        self.selectBtn = QPushButton('选择图片', self)
        self.selectBtn.clicked.connect(self.selectImage)
        self.filePathLabel = QLabel('未选择文件', self)
        file_layout.addWidget(self.selectBtn)
        file_layout.addWidget(self.filePathLabel)
        self.layout.addLayout(file_layout)

        # 显示图片的Label
        self.imageLabel = QLabel(self)
        self.imageLabel.setAlignment(Qt.AlignCenter)
        self.imageLabel.setMinimumHeight(self.preview_size)
        self.imageLabel.setAcceptDrops(True)  # 启用拖放功能
        self.imageLabel.dragEnterEvent = self.dragEnterEvent
        self.imageLabel.dropEvent = self.dropEvent
        self.layout.addWidget(self.imageLabel)

        # 设置尺寸输入区域
        size_layout = QHBoxLayout()

        # 宽度输入
        width_layout = QVBoxLayout()
        self.widthLabel = QLabel('宽度:', self)
        self.widthInput = QLineEdit(self)
        self.widthInput.setValidator(QIntValidator(1, 9999))
        width_layout.addWidget(self.widthLabel)
        width_layout.addWidget(self.widthInput)

        # 高度输入
        height_layout = QVBoxLayout()
        self.heightLabel = QLabel('高度:', self)
        self.heightInput = QLineEdit(self)
        self.heightInput.setValidator(QIntValidator(1, 9999))
        height_layout.addWidget(self.heightLabel)
        height_layout.addWidget(self.heightInput)

        size_layout.addLayout(width_layout)
        size_layout.addLayout(height_layout)
        self.layout.addLayout(size_layout)

        # 添加锁定比例复选框
        self.lockAspectRatioCheckBox = QCheckBox('锁定比例', self)
        self.lockAspectRatioCheckBox.setChecked(True)
        self.lockAspectRatioCheckBox.stateChanged.connect(self.onLockAspectRatioChanged)
        self.layout.addWidget(self.lockAspectRatioCheckBox)

        # 添加保存按钮
        self.saveBtn = QPushButton('保存调整后的图片', self)
        self.saveBtn.clicked.connect(self.saveImage)
        self.saveBtn.setEnabled(False)
        self.layout.addWidget(self.saveBtn)

        # 添加状态标签
        self.statusLabel = QLabel('', self)
        self.statusLabel.setAlignment(Qt.AlignCenter)
        self.layout.addWidget(self.statusLabel)

        # 设置主窗口的布局
        self.setLayout(self.layout)

        # 初始化变量
        self.imagePath = None
        self.originalWidth = None
        self.originalHeight = None

        # 初始状态下启用锁定比例
        self.onLockAspectRatioChanged(Qt.Checked)

    def dragEnterEvent(self, event: QDragEnterEvent):
        if event.mimeData().hasUrls():
            event.acceptProposedAction()

    def dropEvent(self, event: QDropEvent):
        if event.mimeData().hasUrls():
            filePath = event.mimeData().urls()[0].toLocalFile()
            if filePath.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp')):
                self.loadImage(filePath)

    def loadImage(self, filePath):
        try:
            self.imagePath = filePath
            self.filePathLabel.setText(filePath)

            # 使用Pillow库读取图片原始尺寸
            img = Image.open(filePath)
            self.originalWidth, self.originalHeight = img.size

            # 更新预览图片
            self.updatePreview()

            # 初始化输入框
            self.widthInput.setText(str(self.originalWidth))
            self.heightInput.setText(str(self.originalHeight))

            # 启用保存按钮
            self.saveBtn.setEnabled(True)
            self.statusLabel.setText('图片已加载')

        except Exception as e:
            QMessageBox.critical(self, '错误', f'加载图片时出错:{str(e)}')

    def selectImage(self):
        filePath, _ = QFileDialog.getOpenFileName(
            self, '选择图片', '',
            'Images (*.png *.xpm *.jpg *.jpeg *.bmp)'
        )
        if filePath:
            self.loadImage(filePath)

    def updatePreview(self):
        if not self.imagePath:
            return

        pixmap = QPixmap(self.imagePath)
        scaled_pixmap = pixmap.scaled(
            self.preview_size,
            self.preview_size,
            Qt.KeepAspectRatio,
            Qt.SmoothTransformation
        )
        self.imageLabel.setPixmap(scaled_pixmap)

    def onLockAspectRatioChanged(self, state):
        if state == Qt.Checked:
            if not self.width_connected:
                self.widthInput.textChanged.connect(self.updateHeightFromWidth)
                self.width_connected = True
            if not self.height_connected:
                self.heightInput.textChanged.connect(self.updateWidthFromHeight)
                self.height_connected = True
        else:
            if self.width_connected:
                self.widthInput.textChanged.disconnect(self.updateHeightFromWidth)
                self.width_connected = False
            if self.height_connected:
                self.heightInput.textChanged.disconnect(self.updateWidthFromHeight)
                self.height_connected = False

    def updateHeightFromWidth(self):
        if not self.originalWidth or not self.originalHeight:
            return

        try:
            if self.height_connected:
                self.heightInput.textChanged.disconnect(self.updateWidthFromHeight)

            width = int(self.widthInput.text() or 0)
            if width > 0:
                height = int((self.originalHeight / self.originalWidth) * width)
                self.heightInput.setText(str(height))

            if self.height_connected:
                self.heightInput.textChanged.connect(self.updateWidthFromHeight)
        except ValueError:
            pass

    def updateWidthFromHeight(self):
        if not self.originalWidth or not self.originalHeight:
            return

        try:
            if self.width_connected:
                self.widthInput.textChanged.disconnect(self.updateHeightFromWidth)

            height = int(self.heightInput.text() or 0)
            if height > 0:
                width = int((self.originalWidth / self.originalHeight) * height)
                self.widthInput.setText(str(width))

            if self.width_connected:
                self.widthInput.textChanged.connect(self.updateHeightFromWidth)
        except ValueError:
            pass

    def saveImage(self):
        if not self.imagePath:
            return

        try:
            width = int(self.widthInput.text())
            height = int(self.heightInput.text())

            if width <= 0 or height <= 0:
                raise ValueError("尺寸必须大于0")

            img = Image.open(self.imagePath)
            img = img.resize((width, height), Image.Resampling.LANCZOS)

            savePath, _ = QFileDialog.getSaveFileName(
                self, '保存图片', '',
                'PNG (*.png);;JPEG (*.jpg *.jpeg);;BMP (*.bmp)'
            )

            if savePath:
                img.save(savePath)
                self.statusLabel.setText(f'图片已保存到: {savePath}')
                QMessageBox.information(self, '成功', '图片保存成功!')

        except ValueError as e:
            QMessageBox.warning(self, '警告', f"输入错误:{str(e)}")
        except Exception as e:
            QMessageBox.critical(self, '错误', f"保存失败:{str(e)}")


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = ResizeImageTool()
    window.show()
    sys.exit(app.exec_())

效果如下

以上就是Python+PyQt5开发一个图片尺寸修改器的详细内容,更多关于Python图片尺寸修改的资料请关注脚本之家其它相关文章!

相关文章

  • python常用request库与lxml库操作方法整理总结

    python常用request库与lxml库操作方法整理总结

    一路学习,一路总结,技术就是这样,应用之后,在进行整理,才可以加深印象。本篇文字为小节篇,核心总结 requests 库与 lxml 库常用的操作
    2021-08-08
  • Python语法概念基础详解

    Python语法概念基础详解

    这篇文章主要为大家介绍了Python语法概念基础,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-01-01
  • python中关于tqdm的用法

    python中关于tqdm的用法

    这篇文章主要介绍了python中关于tqdm的用法及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • 利用Python绘制随机游走图的详细过程

    利用Python绘制随机游走图的详细过程

    随机游走(random walk)也称随机漫步,随机行走等,是以随机的方式采取连续步骤的过程,下面这篇文章主要给大家介绍了关于利用Python绘制随机游走图的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-02-02
  • Python代码使用 Pyftpdlib实现FTP服务器功能

    Python代码使用 Pyftpdlib实现FTP服务器功能

    FTP 服务器,在此之前我都是使用Linux的vsftpd软件包来搭建FTP服务器的,现在发现了利用pyftpdlib可以更加简单的方法即可实现FTP服务器的功能 ,需要的朋友可以参考下
    2019-07-07
  • Conda国内镜像源及配置过程

    Conda国内镜像源及配置过程

    文章介绍Conda镜像源使用方法,涵盖临时指定单个/多个源、永久配置及恢复默认设置,同时说明main(官方稳定)、free(逐渐弃用)、conda-forge(社区更新快)等仓库的区别与适用场景
    2025-08-08
  • Python实现截取PDF文件中的几页代码实例

    Python实现截取PDF文件中的几页代码实例

    今天小编就为大家分享一篇关于Python实现截取PDF文件中的几页代码实例,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-03-03
  • 在 Django/Flask 开发服务器上使用 HTTPS

    在 Django/Flask 开发服务器上使用 HTTPS

    使用 Django 或 Flask 这种框架开发 web app 的时候一般都会用内建服务器开发和调试程序,等程序完成后再移交到生产环境部署。问题是这些内建服务器通常都不支持 HTTPS,那么我们来探讨下开启https吧
    2014-07-07
  • 一文带你搞懂Python如何解析CSV文件

    一文带你搞懂Python如何解析CSV文件

    CSV(Comma-Separated Values)是一种以纯文本格式存储表格数据的文件格式,本文主要为大家详细介绍了如何使用Python解析CSV文件,有需要的小伙伴可以了解下
    2026-03-03
  • 使用Python发送HTML格式邮件的步骤详解

    使用Python发送HTML格式邮件的步骤详解

    在现代通信中,电子邮件是一种常见的沟通方式,通过Python编程语言,您可以使用内置的库来发送邮件,并在邮件中嵌入HTML内容和图片,本文将介绍如何使用Python发送带有HTML格式内容,以及涉及的步骤和代码示例
    2023-08-08

最新评论