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()

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/210211.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java 好码

1【强制】不要在 foreach 循环里进行元素的 remove/add 操作。 remove 元素请使用 Iterator方式&#xff0c;如果并发操作&#xff0c;需要对 Iterator 对象加锁。 正例&#xff1a; List<String> list new ArrayList<>(); list.add("1");list.add(…

unity 2d 入门 飞翔小鸟 Cinemachine 记录分数(十二)

1、创建文本 右键->create->ui->leagcy->text 2、设置字体 3、设置默认值和数字 4、当切换分辨率&#xff0c;分数不见问题 拖拽这里调整 调整到如下图 5、编写得分脚本 using System.Collections; using System.Collections.Generic; using UnityEngine; …

Docker网络架构介绍

本文主要介绍了Docker容器的单机网络架构与集群网络架构&#xff0c;辅以演示&#xff0c;并简单介绍了网络管理中的命令。 前文&#xff1a; Docker的安装与简单操作命令-CSDN博客 docker网络原理介绍 与ovs类似&#xff0c;docker容器采用veth-pair linux bridge (虚拟交…

mysql语句练习

1、查询"01"课程比"02"课程成绩高的学生的信息及课程分数 SELECT student.*,s1.s_score,s2.s_score FROM student,score s1,score s2 WHERE student.s_ids1.s_id AND student.s_ids2.s_id AND s1.c_id01 AND s2.c_id02 AND s1.s_score>s2.s_score 2、…

0007Java程序设计-ssm基于微信小程序的在线考试系统

文章目录 **摘要**目 录系统实现开发环境 编程技术交流、源码分享、模板分享、网课分享 企鹅&#x1f427;裙&#xff1a;776871563 摘要 网络技术的快速发展给各行各业带来了很大的突破&#xff0c;也给各行各业提供了一种新的管理技术&#xff0c;基于微信小程序的在线考试…

Linux下apisix离线安装教程

Linux下apisix离线安装教程 一、首先需要安装etcd&#xff1a;二、通过rpm离线安装apisix三、启动apisix四、安装apisix-dashboard1、安装2、更改dashboard登录账号名和密码3、运行 一、首先需要安装etcd&#xff1a; 解压缩etcd后执行以下命令&#xff1a; tar -xvf etcd-v3.…

C#注册表技术及操作

目录 一、注册表基础 1.Registry和RegistryKey类 &#xff08;1&#xff09;Registry类 &#xff08;2&#xff09;RegistryKey类 二、在C#中操作注册表 1.读取注册表中的信息 &#xff08;1&#xff09;OpenSubKey()方法 &#xff08;2&#xff09;GetSubKeyNames()…

内外联动——记建行江门鹤山支行营业部堵截一起新型骗局

建设银行广东省江门市分行&#xff08;以下简称“江门建行”&#xff09;认真贯彻落实党中央、国务院决策部署&#xff0c;紧紧围绕当地市委工作部署和上级行要求&#xff0c;扛牢国有大行责任&#xff0c;坚守金融工作的政治性、人民性&#xff0c;以深化新金融行动助力江门全…

javascript实现List列表数据结构

书籍推荐 有幸拜读《数据结构与算法Javascript描述》这本书&#xff0c;先强烈安利一波&#xff01;非常感谢作者大大给我们前端领域带来这本书。 全书从javascript的角度出发&#xff0c;简单明了的分析了数据结构在javascript领域的实现过程与实际的应用案例&#xff0c;且…

postgres 登录及常用命令

登陆 输入以下命令&#xff0c;尝试登录psql: psql -U postgres 报告以下错误&#xff1a; psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: FATAL: Peer authentication failed for user "postgres" 换成下面…

Initializing libiomp5md.dll, but found libiomp5md.dll already initialized.

报错&#xff1a; OMP: Error #15: Initializing libiomp5md.dll, but found libiomp5md.dll already initialized. OMP: Hint This means that multiple copies of the OpenMP runtime have been linked into the program. That is dangerous, since it can degrade performan…

差异计算基础知识 - 了解期末业务操作、WIP 和差异

原文地址&#xff1a;Basics of variance calculation-Understanding Period End activities, WIP and Variances | SAP Blogs 大家好&#xff0c; 这是我在成本核算方面的第六份文件&#xff0c;旨在解释期末的差异计算和相关活动。 我将引导您完成期末活动和差异计算。在本文…

MySQL char 尾随空格丢失与右侧空格填充

今天看《高性能MySQL(第四版)》,讲char,varchar时说“当存储CHAR值时&#xff0c;MySQL删除所有尾随空格。如果需要进行比较&#xff0c;值会用空格填充。”感觉这两句话有冲突啊&#xff0c;便研究了下。 对于具体的问题&#xff0c;当然官方文档是最好的&#xff0c;The CHAR…

【性能测试】Jmeter 配置元件(一):计数器

Jmeter 配置元件&#xff08;一&#xff09;&#xff1a;计数器 在 Jmeter 中&#xff0c;通过函数 ${__counter(,)} 可以实现每次加 1 1 1 的计数效果。但如果步长不为 1 1 1&#xff0c;则要利用到我们的计数器。 函数作用${__counter(,)}计数器&#xff0c;每次加 1${__d…

vue父子组件传值

父组件向子组件传值 1.在父组件中调用子组件时&#xff0c;定义要传递的参数 //使用子组件&#xff0c;并传递value作为prop<childComponent :childValue"parentValue"></childComponent>// 父组件的data中定义传递的参数data() {return {parentValue: &…

论文导读|10月MSOM文章精选:智慧医疗

编者按 在“10月MSOM文章精选&#xff1a;智慧医疗”中&#xff0c;我们有主题、有针对性地选择了MSOM期刊杂志中一些有关智慧医疗领域的有趣文章&#xff0c;不但对文章的内容进行了概括与点评&#xff0c;而且也对文章的结构进行了梳理&#xff0c;旨在激发广大读者的阅读兴趣…

c++--面向对象特性

1.面向对象指的是继承&#xff0c;封装&#xff0c;多态。 继承主要关注类的构造&#xff0c;赋值&#xff0c;析构。 以下对多态&#xff0c;封装进行补充说明。 2、多态 2.1.定义 a.赋值 派生类的指针&#xff0c;可以赋值给基类的指针。 派送类的对象&#xff0c;可以赋值给…

教师需要什么技能?

作为一名老师&#xff0c;需要掌握许多技能&#xff0c;以便能够成功地教育和指导学生。以下是一些关键技能&#xff1a; 1.教学技能&#xff1a;老师需要有深入的学科知识和教学经验&#xff0c;以便能够有效地传授知识。教师应该了解如何设计和执行教学计划&#xff0c;制定课…

【Java基础篇 | 面向对象】—— 聊聊什么是接口(下篇)

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【JavaSE_primary】 本专栏旨在分享学习JavaSE的一点学习心得&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 上篇&#xff08;【Ja…

SpringBoot 自动装配原理详解

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