使用 python 合并 pdf 发票

300 阅读2分钟

最近有一大批发票需要提交,但打印机只能一张 a4 纸打印一张发票,很费纸,并且大小不符合提交的需求,因此产生了将两张发票合并成一张的想法,以下是实现的代码

项目结构(data 和 target 是文件夹)

.
├── data
├── merge.py
└── target

实现需要使用到 pymupdf、fitz

import os, fitz

pdf_folder = os.getcwd() + "/data"
merged_pdf_folder = os.getcwd() + "/target"

# 获取 pdf 文件的名称
pdf_names = []
for file in os.scandir(pdf_folder):
    if file.is_file() and file.name.endswith(".pdf"):
        pdf_names.append(file.name)

# 生成 pdf 所需的参数
width, height = fitz.paper_size("a4")
a4_ratio = 210 / 297
r = fitz.Rect(0, 0, width, height)
rx = r * a4_ratio
r1 = fitz.Rect(0, 0, r.width, rx.width)
r2  = fitz.Rect(0, rx.width, r.width, r.height)
r_tab = [r1, r2]

# 获取所有 pdf 文件
src = fitz.open()
for name in pdf_names:
    read_pdf = fitz.open(pdf_folder + '/' + name)
    src.insert_pdf(read_pdf)

def merge_two_pdf(pdf_tuple: list, id: str):
    if len(pdf_tuple) != 1 and len(pdf_tuple) != 2:
        return
    doc_manager = fitz.open()
    page = doc_manager.new_page(-1, width = width, height = height)
    for spage in pdf_tuple:
        if spage.rect.width > spage.rect.height:
            page.show_pdf_page(r_tab[spage.number % 2], src, spage.number, rotate = 0)
        else:
            page.show_pdf_page(r_tab[spage.number % 2], src, spage.number, rotate = 90)
    doc_manager.save(merged_pdf_folder + '/' + id.replace('.pdf', '') + '.pdf', garbage = 4, deflate = True)

def merge_all_pdf():
    if len(src) == 0:
        return
    doc_manager = fitz.open()
    page = None
    for spage in src:
        if spage.number % 2 == 0:
            page = doc_manager.new_page(-1, width = width, height = height)
        if spage.rect.width > spage.rect.height:
            page.show_pdf_page(r_tab[spage.number % 2], src, spage.number, rotate = 0)
        else:
            page.show_pdf_page(r_tab[spage.number % 2], src, spage.number, rotate = 90)
    doc_manager.save(merged_pdf_folder + '/all.pdf', garbage = 4, deflate = True)

代码的功能是获取 data 文件夹里面的原始 pdf,合并后保存在 target 目录下。注意,上面的代码只适用于 mac,windows 文件路径的书写下可能会有所不同

由于公司的打印机无法设置单面打印,我就只能设置 2 张发票合并成一个只有一页的 pdf,即调用 merge_two_pdf

for i in range(0, len(src), 2):
    try:
        merge_two_pdf([src[i], src[i + 1]], pdf_names[i] + '_' + pdf_names[i + 1])
    except IndexError:
        print(i)
        merge_two_pdf([src[i]], pdf_names[i])

如果你们公司打印机能设置单面打印的话,直接调用 merge_all_pdf 即可