合并PDF编程

2021年01月13日 星期三

有同事用CAD批量出图后想要合并这些PDF,理论上可以用现成软件实现。不过采用python的相关第三方库也可以实现。……

合并PDF编程

​ 有同事用CAD批量出图后想要合并这些PDF,理论上可以用现成软件实现。不过采用python的相关第三方库也可以实现。

版本1.0

# 用于合并PDF
# kiritamirei.cn
# 2020年12月
# PDF合并.py

from PyPDF2 import PdfFileMerger
import os

merger = PdfFileMerger()

files = os.listdir()#列出目录中的所有文件
for file in files: #从所有文件中选出pdf文件合并
    if file[-4:] == ".pdf":
        merger.append(open(file, 'rb'))

with open('newfile.pdf', 'wb') as fout:  #输出文件为newfile.pdf
    merger.write(fout)

上述方法有几个问题:

(1)py文件必须与pdf文档放在同一个文件夹内;

(2)合并的文件顺序没法掌控。

对此,可以自定义上述变量files,如:

files =[str(i)+'.pdf' for i in range(36)]

不过还是有问题,如果要合并的文件很多,文件名又不规则,自定义起来也并不方便。

版本1.1

​ 针对上述问题,版本1.1设计了GUI,可以多次选择文件,同时对文件合并顺序能排位,并能删除错选进去的文件。

点击程序下载,提取码lmoy

合并文件界面1

与此同时,增加了合并时的异常调试(在实际使用过程中存在无法正常合并程序异常退出的情形)。

在实际编程过程中,上移、下移文件时自动调整焦点目标,以便能连续下移或上移。

相关代码:

# 用于合并PDF文件
# 2021年1月8日 星期五 天气晴
# kiritanimirei.cn
# pdf_merge.py

# 2021年1月13日 星期三 天气晴

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import Qt
from PyPDF2 import PdfFileMerger
import  os
import myico             

class table(QWidget):
    def __init__(self,num):
        super().__init__()
        self.initui()

    def initui(self):
        # 默认参数
        # 最大d
        self.__currentItemNum = -1
        self.__file =[]

        self.setWindowTitle('合并PDF')
        dMax =200
        self.desktop = QApplication.desktop()
        self.screenRect = self.desktop.screenGeometry()
        height = self.screenRect.height()
        width = self.screenRect.width()

        wwg =QWidget(self)
        w1 = QHBoxLayout(wwg)
        self.setMinimumWidth(820)
        self.setMinimumHeight(800)

        # 设置图标
        icon = QIcon(':/eye.png')
        self.setWindowIcon(icon)


        self.btn0 = QPushButton('选择文件')
        self.btn1 = QPushButton('合并')
        self.btn2 = QPushButton('上移')
        self.btn3 = QPushButton('下移')
        self.btn4 = QPushButton('删除')


        self.tree=QTreeWidget()
        self.tree.setColumnCount(2)
        self.tree.setHeaderLabels(['序号','文件名'])
        self.tree.setMinimumHeight(600)
        self.tree.setMinimumWidth(800)

        # 设置容器

        vla1 = QVBoxLayout()
        vla2 = QVBoxLayout()
        vla3 = QVBoxLayout()

        vla1.setAlignment(Qt.AlignTop)
        vla2.setAlignment(Qt.AlignTop)
        vla3.setAlignment(Qt.AlignTop)

        hla11 =  QHBoxLayout()
        hla21 =  QHBoxLayout()
        hla31 =  QHBoxLayout()
        hla41 =  QHBoxLayout()

        w1.addLayout(vla1)
        w1.addLayout(vla2)
        w1.addLayout(vla3)

        vla1.addLayout(hla11)
        vla1.addLayout(hla21)
        vla1.addLayout(hla31)
        vla1.addLayout(hla41)

        hla11.addWidget(self.btn0)
        hla41.addWidget(self.btn1)

        hla21.addWidget(self.tree)
        hla31.addWidget(self.btn2)
        hla31.addWidget(self.btn3)
        hla31.addWidget(self.btn4)

        # 设置响应
        self.btn0.clicked.connect(self.getfile)
        self.btn1.clicked.connect(self.merge)
        self.btn2.clicked.connect(self.upfile)
        self.btn3.clicked.connect(self.downfile)
        self.btn4.clicked.connect(self.deletefile) 
        self.tree.itemClicked.connect(self.treeClick)


    def getfile(self):
        # 得到文件名
        # aa=QFileDialog.getOpenFileNames(self,filter='*.xlsx')
        files =QFileDialog.getOpenFileNames(self,filter='*.pdf')
        self.__file += files[0]
        self.tree.clear()
        for i,obj in enumerate(self.__file):
            print(obj)
            root=QTreeWidgetItem(self.tree)
            root.setText(0,str(i+1))
            root.setText(1,obj)



    @property
    def inputfiles(self):
        return self.__file


    def merge(self):
        if len(self.inputfiles) > 1:# 合并文件多与1个
            merger = PdfFileMerger()
            print(self.inputfiles)
            try:
                for file in self.inputfiles: #从所有文件中选出pdf文件合并
                    if file[-4:] == ".pdf":
                        merger.append(open(file, 'rb'))

                with open('newfile.pdf', 'wb') as fout:  #输出文件为newfile.pdf
                    merger.write(fout)
            except:
                msg_box = QMessageBox(QMessageBox.Warning, '警告', '不明原因错误!')
                msg_box.exec_()
                raise
            else:
                QMessageBox.information(self,"消息","合并成功。")
        else:
            msg_box = QMessageBox(QMessageBox.Warning, '警告', '合并文件数目不够!')
            msg_box.exec_()

    def treeClick(self):

        self.__currentItemNum = int(self.tree.currentItem().text(0))-1
        print(self.__currentItemNum)

    def upfile(self):
        #print(self.__currentItemNum)
        if self.__currentItemNum >=1:
            aa = self.__file[self.__currentItemNum]
            bb = self.__file[self.__currentItemNum-1]
            self.__file[self.__currentItemNum-1]= aa
            self.__file[self.__currentItemNum]= bb

            self.tree.clear()
            for i,obj in enumerate(self.__file):
                # print(obj)
                root=QTreeWidgetItem(self.tree)
                root.setText(0,str(i+1))
                root.setText(1,obj)
                if i == self.__currentItemNum-1:
                    self.tree.setCurrentItem(root)
            self.__currentItemNum-=1

    def downfile(self):
        #print(self.__currentItemNum)
        if self.__currentItemNum >=0 and self.__currentItemNum<len(self.__file)-1:
            aa = self.__file[self.__currentItemNum]
            bb = self.__file[self.__currentItemNum+1]
            self.__file[self.__currentItemNum+1]= aa
            self.__file[self.__currentItemNum]= bb

            self.tree.clear()
            for i,obj in enumerate(self.__file):
                # print(obj)
                root=QTreeWidgetItem(self.tree)
                root.setText(0,str(i+1))
                root.setText(1,obj)
                if i == self.__currentItemNum+1:
                    self.tree.setCurrentItem(root)
            self.__currentItemNum+=1
            #print(self.__currentItemNum)

    def deletefile(self):
        if self.__currentItemNum!=-1:
            self.__file.pop(self.__currentItemNum)
            self.tree.clear()
            for i,obj in enumerate(self.__file):
                # print(obj)
                root=QTreeWidgetItem(self.tree)
                root.setText(0,str(i+1))
                root.setText(1,obj)
            self.__currentItemNum =-1          

if __name__=="__main__":
    app =QApplication(sys.argv)
    form = table(6)
    form.show()
    sys.exit(app.exec_())


为了方便其他同事应用,将其输出为exe文件。此时,一开始出现了问题。按照网上相关资料需要如下操作:

(1)写一个qrc文件(任意文本编辑器都可以,只要改扩展名)

<RCC> 
    <qresource prefix="/"> 
        <file>eye.png</file>
     </qresource> 
</RCC>

(2)将相关图标生成二进制文件

pyrcc5 -o myico.py img.qrc

(3)在主程序中进行设置

import myico  
# 设置图标
icon = QIcon(':/eye.png')
self.setWindowIcon(icon)

其在任务栏显式如下图

合并文件界面2

不过该exe自身图标依旧没有改变,需要在生成exe时进行处理。

pyinstaller -F -w -i eye.ico pdf_merge.py

这里如果采用png图片会报错,暂时没有去进一步研究这一问题。


2021年1月13日 星期三 天气晴

精选博客

基于ezdxf的DXF编写

本文主要用于讲采用python的ezdxf模块进行DXF格式的CAD创建。主要讲清楚了具体对象结构和使用流程。在此基础上结合相关帮助文件可以进行较为复杂的图形绘制了。……

继 续 阅 读

网页保存为PDF

edge或chrome没有直接保存为pdf的办法,理论上采用插件可以解决。 这里有两个edge插件: - Save as PDF - PDF Saver - 网上有个应用程序是wkhtmltopdf,其可以在cmd中转化网页成pdf。 - 相关网页 来对比下前三种效果。……

继 续 阅 读

word的按样式输出

在编写一个标准,写的时候呢就会把条文正文和条文说明写在一块,方便编写和对照查看(如下图所示)。但是呢最终的成文必然是两者需要分开的。如果条文很多的话就会非常麻烦。可是word又没有图层功能,可以快速筛选出两者。于是尝试采用下python的相关扩展库来实现这一功能。……

继 续 阅 读