Python+PyQt5实现——图片尺寸修改器(GUI工具)

发布于:2025-03-04 ⋅ 阅读:(85) ⋅ 点赞:(0)

专栏导读

在这里插入图片描述

  • 🌸 欢迎来到Python办公自动化专栏—Python处理办公问题,解放您的双手

  • 🏳️‍🌈 博客主页:请点击——> 一晌小贪欢的博客主页求关注

  • 👍 该系列文章专栏:请点击——>Python办公自动化专栏求订阅

  • 🕷 此外还有爬虫专栏:请点击——>Python爬虫基础专栏求订阅

  • 📕 此外还有python基础专栏:请点击——>Python基础学习专栏求订阅

  • 文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏

  • ❤️ 欢迎各位佬关注! ❤️

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、代码结构

①. init

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



②. initUI

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



③. dragEnterEvent

处理拖拽事件,判断是否允许文件拖放到图片显示区域。
如果拖拽的是文件,则接受该操作。

④. dropEvent

处理文件拖放到图片显示区域后的事件。
检查文件类型是否为图片(支持 .png, .jpg, .jpeg, .bmp),如果是,则加载图片。



⑤. loadImage

加载指定路径的图片。
使用 Pillow 库读取图片的原始尺寸,并更新预览图片。
初始化宽度和高度输入框的值为图片的原始尺寸。
启用保存按钮,并在状态标签中显示“图片已加载”。



⑥. selectImage

打开文件对话框,让用户选择图片文件。
如果用户选择了有效文件,则调用 loadImage 方法加载图片。



⑦ updatePreview

更新图片预览区域。
根据当前图片路径生成缩略图,并保持宽高比。



⑧. onLockAspectRatioChanged

处理锁定比例复选框的状态变化。
如果勾选了锁定比例:
连接宽度输入框和高度输入框的 textChanged 信号,实现两者联动。
如果取消勾选:
断开宽度和高度输入框的信号连接。



⑨. updateHeightFromWidth

当宽度输入框的值发生变化时,根据锁定比例计算并更新高度输入框的值。
防止递归调用导致死循环(通过临时断开高度输入框的信号连接)。



⑩. 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办公自动化专栏

  • 求个 ❤️ 喜欢 ❤️

  • 此外还有爬虫专栏,欢迎大家订阅:Python爬虫基础专栏

  • 求个 👍 收藏 👍

  • 此外还有Python基础专栏,欢迎大家订阅:Python基础学习专栏


网站公告

今日签到

点亮在社区的每一天
去签到