Python PDF转换工具箱(PDF转图片,word,拆分,删除,提取) ...

打印 上一主题 下一主题

主题 826|帖子 826|积分 2478

Python PDF转换工具箱(PDF转图片,word,拆分,删除,提取)

1.简介:

利用Python自写的pdf工具箱,包罗pdf转word,图片,合并,页面拆分,页面删除,页面提取、
转换word,图片功能,支持文件拖入。文章末了已附源码以及打包好的exe文件,各人需要可自行下载学习,喜欢的话给博主点个小小的关注哦,主页还将会更新更多Python相干干货资源,关注不迷路哦!
功能先容:
合并:添加次序就是合并次序,可多次添加。
拆分:将输入页码的范围拆分成每个独立的pdf,单次可输入多个范围。
删除:将输入页码的范围删除,单次可输入多个范围,生存删除后的文件。
提取:将输入页码的范围提取成独立的pdf,单次可输入多个范围。
2.运行结果:


3.相干源码:

  1. import os
  2. import re
  3. import sys
  4. from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QVBoxLayout, QWidget, QFileDialog, QListWidget, \
  5.     QMessageBox, QLineEdit, QHBoxLayout
  6. from PyQt5.QtCore import QThread, pyqtSignal
  7. from PyPDF2 import PdfReader, PdfWriter, PdfMerger
  8. from pdf2docx import Converter
  9. import fitz  # 用于PDF转JPG的处理
  10. class CustomListWidget(QListWidget):
  11.     def __init__(self, parent=None):
  12.         super().__init__(parent)
  13.         self.setAcceptDrops(True)
  14.         self.parentWindow = parent
  15.     def dragEnterEvent(self, event):
  16.         if any(url.toString().lower().endswith('.pdf') for url in event.mimeData().urls()):
  17.             event.acceptProposedAction()
  18.     def dragMoveEvent(self, event):
  19.         if any(url.toString().lower().endswith('.pdf') for url in event.mimeData().urls()):
  20.             event.acceptProposedAction()
  21.     def dropEvent(self, event):
  22.         pdf_files = [url.toLocalFile() for url in event.mimeData().urls() if url.toString().lower().endswith('.pdf')]
  23.         for f in pdf_files:
  24.             self.parentWindow.addPDFFile(f)
  25. class Worker(QThread):
  26.     finished = pyqtSignal(str)
  27.     error = pyqtSignal(str)
  28.     def __init__(self, pdf_files, range_str=None, save_path=None, operation=None):
  29.         super().__init__()
  30.         self.pdf_files = pdf_files
  31.         self.range_str = range_str
  32.         self.save_path = save_path
  33.         self.operation = operation
  34.     def run(self):
  35.         try:
  36.             if self.operation == 'merge':
  37.                 self.merge_pdfs()
  38.             elif self.operation == 'split':
  39.                 self.split_pdfs()
  40.             elif self.operation == 'delete':
  41.                 self.delete_pages()
  42.             elif self.operation == 'extract':
  43.                 self.extract_pages()
  44.             elif self.operation == 'jpg':
  45.                 self.pdf_to_jpg()
  46.             elif self.operation == 'word':
  47.                 self.pdf_to_word()
  48.         except Exception as e:
  49.             self.error.emit(str(e))
  50.     def merge_pdfs(self):
  51.         merger = PdfMerger()
  52.         for pdf in self.pdf_files:
  53.             merger.append(pdf)
  54.         merger.write(self.save_path)
  55.         merger.close()
  56.         self.finished.emit('PDF文件已成功合并。')
  57.     def split_pdfs(self):
  58.         ranges = self.parse_ranges(self.range_str)
  59.         reader = PdfReader(self.pdf_files[0])
  60.         os.makedirs(self.save_path, exist_ok=True)  # 确保目标文件夹存在
  61.         file_index = 1  # 用于创建唯一的文件名
  62.         for range_index, (start_page, end_page) in enumerate(ranges):
  63.             # 对于每个范围,拆分出来的每个页面为一个单独的PDF文件
  64.             for page_num in range(start_page, end_page + 1):
  65.                 writer = PdfWriter()
  66.                 writer.add_page(reader.pages[page_num])
  67.                 # 使用文件索引来确保每个文件的名称都是唯一的
  68.                 split_save_path = os.path.join(self.save_path, f'split_page_{file_index}.pdf')
  69.                 with open(split_save_path, 'wb') as f:
  70.                     writer.write(f)
  71.                 file_index += 1
  72.         self.finished.emit('PDF文件已成功拆分并保存。')
  73.     def delete_pages(self):
  74.         ranges = self.parse_ranges(self.range_str)
  75.         reader = PdfReader(self.pdf_files[0])
  76.         writer = PdfWriter()
  77.         pages_to_delete = {page for start, end in ranges for page in range(start, end + 1)}
  78.         for i in range(len(reader.pages)):
  79.             if i not in pages_to_delete:
  80.                 writer.add_page(reader.pages[i])
  81.         with open(self.save_path, 'wb') as f:
  82.             writer.write(f)
  83.         self.finished.emit('指定页面已从PDF中删除。')
  84.     def extract_pages(self):
  85.         ranges = self.parse_ranges(self.range_str)
  86.         reader = PdfReader(self.pdf_files[0])
  87.         os.makedirs(self.save_path, exist_ok=True)  # 在循环外提前确保目录存在
  88.         for i, (start_page, end_page) in enumerate(ranges):
  89.             writer = PdfWriter()
  90.             for page_num in range(start_page, end_page + 1):
  91.                 writer.add_page(reader.pages[page_num])
  92.             extract_save_path = os.path.join(self.save_path, f'extract_{i + 1}.pdf')
  93.             with open(extract_save_path, 'wb') as f:
  94.                 writer.write(f)
  95.         self.finished.emit('指定页面已从PDF中提取。')
  96.     def pdf_to_jpg(self):
  97.         for file in self.pdf_files:
  98.             pdf = fitz.open(file)
  99.             img_folder = os.path.join(self.save_path, os.path.splitext(os.path.basename(file))[0])
  100.             os.makedirs(img_folder, exist_ok=True)
  101.             for pg in range(pdf.page_count):
  102.                 page = pdf[pg]
  103.                 trans = fitz.Matrix(2, 2)  # 设置转换矩阵为放大2倍
  104.                 pm = page.get_pixmap(matrix=trans, alpha=False)
  105.                 pic_name = f'Page_{pg + 1}.jpg'
  106.                 pic_path = os.path.join(img_folder, pic_name)
  107.                 pm.save(pic_path)
  108.         self.finished.emit('PDF文件已成功转换为图片。')
  109.     def pdf_to_word(self):
  110.         for file in self.pdf_files:
  111.             docx_name = os.path.splitext(file)[0] + '.docx'
  112.             cv = Converter(file)
  113.             cv.convert(docx_name, start=0, end=None)
  114.             cv.close()
  115.         self.finished.emit('PDF文件已成功转换为Word文档。')
  116.     def parse_ranges(self, ranges_str):
  117.         ranges = []
  118.         for part in re.split(',|,', ranges_str):
  119.             if '-' in part:
  120.                 start_page, end_page = map(int, part.split('-'))
  121.                 ranges.append((start_page - 1, end_page - 1))
  122.             else:
  123.                 page = int(part)
  124.                 ranges.append((page - 1, page - 1))
  125.         return ranges
  126. class PDFMergerApp(QMainWindow):
  127.     def __init__(self):
  128.         super().__init__()
  129.         self.initUI()
  130.         self.pdf_files = []
  131.     def initUI(self):
  132.         self.setWindowTitle('PDF 工具箱')
  133.         self.setGeometry(100, 100, 800, 600)
  134.         mainLayout = QVBoxLayout()
  135.         self.addButton = QPushButton('添加 PDF', self)
  136.         self.addButton.clicked.connect(self.addPDF)
  137.         mainLayout.addWidget(self.addButton)
  138.         self.listWidget = CustomListWidget(self)
  139.         mainLayout.addWidget(self.listWidget)
  140.         deleteLayout = QHBoxLayout()
  141.         self.removeButton = QPushButton('删除选定', self)
  142.         self.removeButton.clicked.connect(self.removeSelected)
  143.         deleteLayout.addWidget(self.removeButton)
  144.         self.removeAllButton = QPushButton('删除全部', self)
  145.         self.removeAllButton.clicked.connect(self.removeAll)
  146.         deleteLayout.addWidget(self.removeAllButton)
  147.         mainLayout.addLayout(deleteLayout)
  148.         convertLayout = QHBoxLayout()
  149.         self.convertJPGButton = QPushButton('转换为图片', self)
  150.         self.convertJPGButton.clicked.connect(self.convertToJPG)
  151.         convertLayout.addWidget(self.convertJPGButton)
  152.         self.convertWordButton = QPushButton('转换为Word', self)
  153.         self.convertWordButton.clicked.connect(self.convertToWord)
  154.         convertLayout.addWidget(self.convertWordButton)
  155.         mainLayout.addLayout(convertLayout)
  156.         self.mergeButton = QPushButton('合并 PDFs', self)
  157.         self.mergeButton.clicked.connect(self.mergePDFs)
  158.         mainLayout.addWidget(self.mergeButton)
  159.         splitLayout = QHBoxLayout()
  160.         self.splitInput = QLineEdit(self)
  161.         self.splitInput.setPlaceholderText('输入拆分页码范围可输入多个范围,如1,3-4,8-15')
  162.         splitLayout.addWidget(self.splitInput)
  163.         self.splitButton = QPushButton('拆分页面', self)
  164.         self.splitButton.clicked.connect(self.splitPDF)
  165.         splitLayout.addWidget(self.splitButton)
  166.         mainLayout.addLayout(splitLayout)
  167.         deletePageLayout = QHBoxLayout()
  168.         self.deleteInput = QLineEdit(self)
  169.         self.deleteInput.setPlaceholderText('输入删除页码范围可输入多个范围,如1,3-4,8-15')
  170.         deletePageLayout.addWidget(self.deleteInput)
  171.         self.deleteButton = QPushButton('删除页面', self)
  172.         self.deleteButton.clicked.connect(self.deletePages)
  173.         deletePageLayout.addWidget(self.deleteButton)
  174.         mainLayout.addLayout(deletePageLayout)
  175.         extractLayout = QHBoxLayout()
  176.         self.extractInput = QLineEdit(self)
  177.         self.extractInput.setPlaceholderText('输入提取页码范围可输入多个范围,如1,3-4,8-15')
  178.         extractLayout.addWidget(self.extractInput)
  179.         self.extractButton = QPushButton('提取页面', self)
  180.         self.extractButton.clicked.connect(self.extractPages)
  181.         extractLayout.addWidget(self.extractButton)
  182.         mainLayout.addLayout(extractLayout)
  183.         container = QWidget()
  184.         container.setLayout(mainLayout)
  185.         self.setCentralWidget(container)
  186.     def addPDF(self):
  187.         files, _ = QFileDialog.getOpenFileNames(self, '打开文件', '', 'PDF files (*.pdf)')
  188.         for file_path in files:
  189.             self.addPDFFile(file_path)
  190.     def addPDFFile(self, file_path):
  191.         if file_path and file_path not in self.pdf_files:
  192.             self.pdf_files.append(file_path)
  193.             self.listWidget.addItem(file_path)
  194.     def removeSelected(self):
  195.         for item in self.listWidget.selectedItems():
  196.             self.pdf_files.remove(item.text())
  197.             self.listWidget.takeItem(self.listWidget.row(item))
  198.     def removeAll(self):
  199.         self.pdf_files.clear()
  200.         self.listWidget.clear()
  201.     def mergePDFs(self):
  202.         save_path, _ = QFileDialog.getSaveFileName(self, '保存文件', '', 'PDF files (*.pdf)')
  203.         if save_path:
  204.             self.thread = Worker(self.pdf_files, save_path=save_path, operation='merge')
  205.             self.thread.finished.connect(self.onFinished)
  206.             self.thread.error.connect(self.onError)
  207.             self.thread.start()
  208.     def splitPDF(self):
  209.         if len(self.pdf_files) != 1:
  210.             QMessageBox.warning(self, "错误", "请只选择一个PDF文件进行拆分。")
  211.             return
  212.         range_str = self.splitInput.text().strip()
  213.         folder_path = self.getFolderName()
  214.         if range_str and folder_path:
  215.             self.thread = Worker(self.pdf_files, range_str=range_str, save_path=folder_path, operation='split')
  216.             self.thread.finished.connect(self.onFinished)
  217.             self.thread.error.connect(self.onError)
  218.             self.thread.start()
  219.     def deletePages(self):
  220.         if len(self.pdf_files) != 1:
  221.             QMessageBox.warning(self, "错误", "请只选择一个PDF文件进行删除操作。")
  222.             return
  223.         range_str = self.deleteInput.text().strip()
  224.         save_path = QFileDialog.getSaveFileName(self, '保存文件', '', 'PDF files (*.pdf)')[0]
  225.         if save_path and range_str:
  226.             self.thread = Worker(self.pdf_files, range_str=range_str, save_path=save_path, operation='delete')
  227.             self.thread.finished.connect(self.onFinished)
  228.             self.thread.error.connect(self.onError)
  229.             self.thread.start()
  230.     def extractPages(self):
  231.         if len(self.pdf_files) != 1:
  232.             QMessageBox.warning(self, "错误", "请只选择一个PDF文件进行提取操作。")
  233.             return
  234.         range_str = self.extractInput.text().strip()
  235.         save_path = QFileDialog.getSaveFileName(self, '保存文件', '', 'PDF files (*.pdf)')[0]
  236.         if save_path and range_str:
  237.             self.thread = Worker(self.pdf_files, range_str=range_str, save_path=save_path, operation='extract')
  238.             self.thread.finished.connect(self.onFinished)
  239.             self.thread.error.connect(self.onError)
  240.             self.thread.start()
  241.     def convertToJPG(self):
  242.         save_path = QFileDialog.getExistingDirectory(self, "选择保存图片的位置")
  243.         if save_path:
  244.             self.thread = Worker(self.pdf_files, save_path=save_path, operation='jpg')
  245.             self.thread.finished.connect(self.onFinished)
  246.             self.thread.error.connect(self.onError)
  247.             self.thread.start()
  248.     def convertToWord(self):
  249.         save_path = QFileDialog.getExistingDirectory(self, "选择保存Word的位置")
  250.         if save_path:
  251.             self.thread = Worker(self.pdf_files, save_path=save_path, operation='word')
  252.             self.thread.finished.connect(self.onFinished)
  253.             self.thread.error.connect(self.onError)
  254.             self.thread.start()
  255.     def getFolderName(self):
  256.         folder_path = QFileDialog.getExistingDirectory(self, "选择保存拆分文件的位置")
  257.         return folder_path
  258.     def onFinished(self, message):
  259.         QMessageBox.information(self, "操作完成", message)
  260.         self.clear_pdf_list()
  261.         self.clear_text_inputs()
  262.     def onError(self, error_message):
  263.         QMessageBox.warning(self, "操作失败", error_message)
  264.     def clear_pdf_list(self):
  265.         self.pdf_files.clear()
  266.         self.listWidget.clear()
  267.     def clear_text_inputs(self):
  268.         # 清除所有的QLineEdit控件内容
  269.         self.splitInput.clear()
  270.         self.deleteInput.clear()
  271.         self.extractInput.clear()
  272. def main():
  273.     app = QApplication(sys.argv)
  274.     ex = PDFMergerApp()
  275.     ex.show()
  276.     sys.exit(app.exec_())
  277. if __name__ == '__main__':
  278.     main()
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

惊雷无声

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表