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

Python-pdf工具自制(合并、拆分、删除)

pdf工具,之前写的合并工具有点麻烦,使用PyQt5库重写合并拆分和删除指定页面的程序

实现如图:

代码:

import sysimport osfrom PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QVBoxLayout, QWidget, QFileDialog, QListWidget, QMessageBox, QLineEdit, QHBoxLayout, QInputDialogfrom PyQt5.QtCore import Qt, QThread, pyqtSignalfrom PyPDF2 import PdfReader, PdfWriter, PdfMergerfrom PyQt5 import QtGuiclass CustomListWidget(QListWidget):def __init__(self, parent=None):super().__init__(parent)class Worker(QThread):finished = pyqtSignal(str)error = pyqtSignal(str)def __init__(self, pdf_files, range_str=None, save_path=None, operation=None):super().__init__()self.pdf_files = pdf_filesself.range_str = range_strself.save_path = save_pathself.operation = operationdef run(self):try:if self.operation == 'merge':merger = PdfMerger()for pdf in self.pdf_files:merger.append(pdf)merger.write(self.save_path)merger.close()self.finished.emit('PDF文件已成功合并。')elif self.operation == 'split':start_page, end_page = self.parse_range(self.range_str)reader = PdfReader(self.pdf_files[zxsq-anti-bbcode-0])os.makedirs(self.save_path, exist_ok=True)for page in range(start_page, end_page + 1):writer = PdfWriter()writer.add_page(reader.pages)split_save_path = os.path.join(self.save_path, f'Page_{page + 1}.pdf')writer.write(split_save_path)self.finished.emit('PDF文件已成功拆分并保存。')elif self.operation == 'delete':start_page, end_page = self.parse_range(self.range_str)reader = PdfReader(self.pdf_files[zxsq-anti-bbcode-0])writer = PdfWriter()for page_num in range(len(reader.pages)):if not (start_page <= page_num <= end_page):writer.add_page(reader.pages[zxsq-anti-bbcode-page_num])writer.write(self.save_path)self.finished.emit('指定页面已从PDF中删除。')except Exception as e:self.error.emit(str(e))def parse_range(self, range_str):if '-' in range_str:start_page, end_page = map(int, range_str.split('-'))else:start_page = end_page = int(range_str)return start_page - 1, end_page - 1  # Convert to 0-based indexclass PDFMergerApp(QMainWindow):def __init__(self):super().__init__()self.initUI()self.pdf_files = []def initUI(self):self.setWindowTitle('PDF 工具箱')self.setWindowIcon(QtGui.QIcon('111.ico'))self.setGeometry(100, 100, 800, 600)mainLayout = QVBoxLayout()self.addButton = QPushButton('添加 PDF', self)self.addButton.clicked.connect(self.addPDF)mainLayout.addWidget(self.addButton)self.listWidget = CustomListWidget(self)mainLayout.addWidget(self.listWidget)# 删除按钮的水平布局deleteLayout = QHBoxLayout()self.removeButton = QPushButton('删除选定', self)self.removeButton.clicked.connect(self.removeSelected)deleteLayout.addWidget(self.removeButton)self.removeAllButton = QPushButton('删除全部', self)self.removeAllButton.clicked.connect(self.removeAll)deleteLayout.addWidget(self.removeAllButton)mainLayout.addLayout(deleteLayout)self.mergeButton = QPushButton('合并 PDFs', self)self.mergeButton.clicked.connect(self.mergePDFs)mainLayout.addWidget(self.mergeButton)# 拆分和删除页码的水平布局splitDeleteLayout = QHBoxLayout()self.splitInput = QLineEdit(self)self.splitInput.setPlaceholderText('输入拆分范围,如 1 或 1-4')splitDeleteLayout.addWidget(self.splitInput)self.splitButton = QPushButton('拆分 PDF', self)self.splitButton.clicked.connect(self.splitPDF)splitDeleteLayout.addWidget(self.splitButton)self.deleteInput = QLineEdit(self)self.deleteInput.setPlaceholderText('输入删除页码,如 1 或 1-4')splitDeleteLayout.addWidget(self.deleteInput)self.deleteButton = QPushButton('删除页面', self)self.deleteButton.clicked.connect(self.deletePages)splitDeleteLayout.addWidget(self.deleteButton)mainLayout.addLayout(splitDeleteLayout)container = QWidget()container.setLayout(mainLayout)self.setCentralWidget(container)def addPDF(self):files, _ = QFileDialog.getOpenFileNames(self, '打开文件', '', 'PDF files (*.pdf)')for file_path in files:self.addPDFFile(file_path)def addPDFFile(self, file_path):if file_path and file_path not in self.pdf_files:self.pdf_files.append(file_path)self.listWidget.addItem(file_path)def removeSelected(self):for item in self.listWidget.selectedItems():self.pdf_files.remove(item.text())self.listWidget.takeItem(self.listWidget.row(item))def removeAll(self):self.pdf_files.clear()self.listWidget.clear()def mergePDFs(self):save_path, _ = QFileDialog.getSaveFileName(self, '保存文件', '', 'PDF files (*.pdf)')if save_path:self.thread = Worker(self.pdf_files, save_path=save_path, operation='merge')self.thread.finished.connect(self.onFinished)self.thread.error.connect(self.onError)self.thread.start()def splitPDF(self):if len(self.pdf_files) != 1:QMessageBox.warning(self, "错误", "请只选择一个PDF文件进行拆分。")returnrange_str = self.splitInput.text().strip()folder_path = self.getFolderName()if range_str and folder_path:self.thread = Worker(self.pdf_files, range_str=range_str, save_path=folder_path, operation='split')self.thread.finished.connect(self.onFinished)self.thread.error.connect(self.onError)self.thread.start()def getFolderName(self):folder_path = QFileDialog.getExistingDirectory(self, "选择保存拆分文件的位置")if folder_path:folder_name, ok = QInputDialog.getText(self, "文件夹名称", "输入文件夹名称:")if ok and folder_name:full_path = os.path.join(folder_path, folder_name)os.makedirs(full_path, exist_ok=True)return full_pathreturn Nonedef deletePages(self):if len(self.pdf_files) != 1:QMessageBox.warning(self, "错误", "请只选择一个PDF文件进行删除操作。")returnrange_str = self.deleteInput.text().strip()save_path = QFileDialog.getSaveFileName(self, '保存文件', '', 'PDF files (*.pdf)')[zxsq-anti-bbcode-0]if save_path and range_str:self.thread = Worker(self.pdf_files, range_str=range_str, save_path=save_path, operation='delete')self.thread.finished.connect(self.onFinished)self.thread.error.connect(self.onError)self.thread.start()def onFinished(self, message):self.show_message("操作完成", message)self.clear_pdf_list()def onError(self, error_message):self.show_message("操作失败", error_message)def show_message(self, title, message):QMessageBox.information(self, title, message)def clear_pdf_list(self):self.pdf_files.clear()self.listWidget.clear()def main():app = QApplication(sys.argv)ex = PDFMergerApp()ex.show()sys.exit(app.exec_())if __name__ == '__main__':main()

 

相关文章:

Python-pdf工具自制(合并、拆分、删除)

pdf工具,之前写的合并工具有点麻烦,使用PyQt5库重写合并拆分和删除指定页面的程序 实现如图: 代码: import sysimport osfrom PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QVBoxLayout, QWidget, QFileDia…...

23.12.9 《CLR via C#》 笔记7

第九章 参数 可选参数和命名参数 可选参数:在方法声明中为参数指定默认值,在调用方法时,如果不提供相应可选参数的值,将会使用默认值命名参数:在调用方法时通过指定参数名称来传递参数值,而不是按照参数在方…...

input、el-input输入框输入规则

一、input 只能输入框只能输入正整数&#xff0c;输入同时禁止了以0开始的数字输入&#xff0c;防止被转化为其他进制的数值。 <!-- 不能输入零时--> <input typetext οninput"valuevalue.replace(/^(0)|[^\d]/g,)"><!-- 能输入零时--> <inp…...

Qt优秀开源项目之十九:跨平台记事本Notes

官网&#xff1a;https://www.get-notes.com github&#xff1a;https://github.com/nuttyartist/notes 一.特性 1.完全基于Qt和C 2.完全开源和跨平台&#xff08;Linux、macOS、Windows&#xff09; 3.运行速度快&#xff0c;界面美如画 4.支持Markdown 5.支持使用嵌套文件夹…...

[足式机器人]Part4 南科大高等机器人控制课 Ch03 Operator View of Rigid-Body Transformation

本文仅供学习使用 本文参考&#xff1a; B站&#xff1a;CLEAR_LAB 笔者带更新-运动学 课程主讲教师&#xff1a; Prof. Wei Zhang 南科大高等机器人控制课 Ch03 Operator View of Rigid-Body Transformation 1. Rotation Operation via Differential Equation1.1 Skew Symmetr…...

SpringBoot项目静态资源默认访问目录

SpringBoot项目&#xff1a;静态资源默认访问目录 参考博客&#xff1a;https://blog.csdn.net/weixin_43808717/article/details/118281904...

xtu oj 1255 勾股数

题目描述 勾股数是指满足a2b2c2的正整数&#xff0c;比如最有名的“勾三股四弦五”。 现在给你两个正整数,请问是否存在另外一个正整数&#xff0c;使其成为“勾股数”&#xff1f; 输入 第一行是一个整数K&#xff0c;表示样例的个数。 以后每行一个样例&#xff0c;为两个…...

【ArcGIS Pro微课1000例】0051:创建数据最小几何边界范围(点、线、面数据均可)

本实例为专栏系统文章:创建点数据最小几何边界(范围),配套案例数据,持续同步更新! 文章目录 一、工具介绍二、实战演练三、注意事项一、工具介绍 创建包含若干面的要素类,用以表示封闭单个输入要素或成组的输入要素指定的最小边界几何。 工具界面及参数如下所示: 核心…...

Oracle 怎樣修改DB_NAME

DBNEWID 是一个数据库实用程序&#xff0c;用于更改 Oracle 数据库的 DBNAME 和 DBID。可以更改 DBID 或 DBNAME 或两者。 DBNAME 是在创建数据库时指定的数据库名称&#xff0c;DBID 是创建数据库时分配给数据库的唯一编号。 以下步骤演示如何使用 DBNEWID 实用程序更改 Oracl…...

git标签的管理与思考

git 标签管理 git 如何打标签呢&#xff1f; 标签是什么? 标签 相当于一个 版本管理的一个贴纸&#xff0c;随时 可以通过标签 切换到 这个版本的状态 &#xff0c; 有人可能有疑问 git commit 就可以知道 代码的改动了&#xff0c; 为啥还需要标签来管理呢&#xff1f; …...

ESP32网络编程-OTA方式升级固件(基于Arduino IDE)

OTA方式升级固件(基于Arduino IDE) 文章目录 OTA方式升级固件(基于Arduino IDE)1、ESP32的OTA介绍2、OTA升级固件方式3、软件准备4、硬件准备5、代码实现ESP32吸引人的编程方式之一就是通过OTA方式升级固件。本文将详细介绍在Arduino IDE中升级固件。 1、ESP32的OTA介绍 O…...

力扣-151. 反转字符串中的单词

文章目录 看下去&#xff0c;你一定可以理解此题&#xff0c;写的简单易懂力扣题目解题思路函数构成1.反转函数2.消除掉多余空格函数 整体函数 看下去&#xff0c;你一定可以理解此题&#xff0c;写的简单易懂 力扣题目 给你一个字符串 s &#xff0c;请你反转字符串中 单词 …...

VSCode Keil Assintant 联合开发STM32

文章目录 VSCodeKeil AssistantUV5&#x1f947;软件下载&#x1f947;配置环境&#x1f947;插件安装&#x1f948;C/C Extension Pack&#x1f949;C/C Extension Pack介绍&#x1f949;插件安装 &#x1f948;Keil Assistant&#x1f949;Keil Assistant介绍&#x1f949;插…...

华为交换机基本配置

一、配置时间 sys ntp-service unicast-server 192.168.1.1 ntp-service unicast-server 192.168.1.2 clock timezone UTC add 8 clock timezone CST add 08:00:00 undo ntp-service disable q手动设置一个时间 clock datetime 13:43:00 2023-10-10save ysys保存&#xff01;保…...

每天一个Linux命令 -- (7)more命令

欢迎阅读《每天一个Linux命令》系列&#xff01;在本篇文章中&#xff0c;将介绍Linux系统下的more命令&#xff0c;它用于逐屏显示文件的内容。 概念 more命令是Linux系统下的文件逐屏显示命令&#xff0c;用于逐屏显示文件的内容。 命令操作 more命令的语法如下&#xff1…...

JUnit 之初体验

文章目录 1.定义2.引入1&#xff09;使用 Maven 工具2&#xff09;使用 Gradle 工具3&#xff09;使用 Jar 包 2.样例0&#xff09;前提1&#xff09;测试类2&#xff09;测试方法3&#xff09;测试断言4&#xff09;实施 总结 1.定义 JUnit 是一个流行的 Java 单元测试框架&a…...

【前端设计模式】之适配器模式

适配器模式是一种常见的设计模式&#xff0c;用于将一个类的接口转换成客户端所期望的另一个接口。在前端开发中&#xff0c;适配器模式可以帮助我们解决不同框架或库之间的兼容性问题&#xff0c;提高代码的复用性和可维护性。 适配器模式特性 适配器类&#xff1a;适配器类…...

【数据结构】循环队列

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:数据结构 ⚙️操作环境:Visual Studio 2022 目录 &#x1f38f;队列顺序存储的不足 &#x1f38f;循环队列的定义 &#x1f38f;设计循环队列 结语 &#x1f38f;队列顺序存储的不足 我们假设用一个可以存放为n个数据…...

Docker的资源控制

Docker的资源控制&#xff1a; 对容器使用宿主机的资源进行限制&#xff0c;Docker 通过 Cgroup 来控制容器使用的资源配额&#xff0c;包括 CPU 内存 磁盘i/o Docker 使用Linux自带的功能cgroup&#xff0c;Cgroup 是 ControlGroups 的缩写 C crontrol groups是Linux内核…...

SpringBoot 自动装配原理详解

什么是 SpringBoot 自动装配&#xff1f; 我们现在提到自动装配的时候&#xff0c;一般会和 Spring Boot 联系在一起。但是&#xff0c;实际上 Spring Framework 早就实现了这个功能。Spring Boot 只是在其基础上&#xff0c;通过 SPI 的方式&#xff0c;做了进一步优化。 Spr…...

KubeSphere 容器平台高可用:环境搭建与可视化操作指南

Linux_k8s篇 欢迎来到Linux的世界&#xff0c;看笔记好好学多敲多打&#xff0c;每个人都是大神&#xff01; 题目&#xff1a;KubeSphere 容器平台高可用&#xff1a;环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...

基于大模型的 UI 自动化系统

基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

大话软工笔记—需求分析概述

需求分析&#xff0c;就是要对需求调研收集到的资料信息逐个地进行拆分、研究&#xff0c;从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要&#xff0c;后续设计的依据主要来自于需求分析的成果&#xff0c;包括: 项目的目的…...

Python:操作 Excel 折叠

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

django filter 统计数量 按属性去重

在Django中&#xff0c;如果你想要根据某个属性对查询集进行去重并统计数量&#xff0c;你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求&#xff1a; 方法1&#xff1a;使用annotate()和Count 假设你有一个模型Item&#xff0c;并且你想…...

数据链路层的主要功能是什么

数据链路层&#xff08;OSI模型第2层&#xff09;的核心功能是在相邻网络节点&#xff08;如交换机、主机&#xff09;间提供可靠的数据帧传输服务&#xff0c;主要职责包括&#xff1a; &#x1f511; 核心功能详解&#xff1a; 帧封装与解封装 封装&#xff1a; 将网络层下发…...

【AI学习】三、AI算法中的向量

在人工智能&#xff08;AI&#xff09;算法中&#xff0c;向量&#xff08;Vector&#xff09;是一种将现实世界中的数据&#xff08;如图像、文本、音频等&#xff09;转化为计算机可处理的数值型特征表示的工具。它是连接人类认知&#xff08;如语义、视觉特征&#xff09;与…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)

本文把滑坡位移序列拆开、筛优质因子&#xff0c;再用 CNN-BiLSTM-Attention 来动态预测每个子序列&#xff0c;最后重构出总位移&#xff0c;预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵&#xff08;S…...

laravel8+vue3.0+element-plus搭建方法

创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

mac 安装homebrew (nvm 及git)

mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用&#xff1a; 方法一&#xff1a;使用 Homebrew 安装 Git&#xff08;推荐&#xff09; 步骤如下&#xff1a;打开终端&#xff08;Terminal.app&#xff09; 1.安装 Homebrew…...