python 在pdf文件中批量添加编码(DrawString中文解决,Rotation处理)

参考了好多资料和文章,然后各种无目的的尝试和实验,成功。希望可以帮到在办公室繁重办公的各位。

import PyPDF2, xlrd,io,os
import win32ui
from PyPDF2 import PdfFileReader, PdfFileWriter
from PIL import Image
import tkinter as tk
from tkinter import filedialog
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfgen import canvas
from reportlab.pdfbase.ttfonts import TTFont

fspec="Excel 2003(*.xls)|*.xls"
dlg = win32ui.CreateFileDialog(1,None, "请选择索引excel表", 1, fspec, None)
'''
        请将文件路径放在xls文件第1个表的A列,将从第2行开始
        将将要录入的代码放在B列
        pdf文件与图片文件是分次处理,故不能统一编码,卡脖子的技术瓶颈已经在改代码中解决,可自行重构代码打到效果
'''
root=tk.Tk()
root.withdraw()
dlg.SetOFNInitialDir('d:/')  # 设置打开文件对话框中的初始显示目录
dlg.DoModal()				# 显示文件对话框
filename = dlg.GetPathName()  # 获取选择的文件名称
outDir=filedialog.askdirectory()  # 获取选择的保存
outDir.replace("/","\\")    # 格式化文件路径
print(outDir)               # print输出路径
wb=xlrd.open_workbook(filename)     # 打开索引表
sheet1 =wb.sheets()[0]          # 获取索引表的第一个表格
path=sheet1.col(0)              # 读取表格第一列的内容:合同文件路径
xulie=sheet1.col(1)             # 读取表格第二列的内容:文件编号
'print(path)'
print("=======================================================")
'print(xulie)'
FontSize=16                     # 设置字体大小
pdfmetrics.registerFont(TTFont('华光综艺_CNKI', 'HGZY_CNKI.TTF'))       # 注册中文字体包
for i in range(1,sheet1.nrows-1):           # 遍历表格里的合同文件
    file = os.path.splitext(path[i].value)      # 获取文件名中的信息
    filename, type = file
    print("Got-PDF-Path = %s"%path[i].value)
    print("Got-PDF-Index = %s"%xulie[i].value)
    if type==".pdf":                        # 判断为pdf文件则进行下列操作:
        PdfReader=PyPDF2.PdfFileReader(path[i].value)       # 打开读取接口
        pageCount=PdfReader.getNumPages()                   # 获取页面数
        print(xulie[i].value,"-Pages = ",pageCount)            # print页面数
        writerObj = PdfFileWriter()                         # 新建写入接口(未指定写入目标)
        for page in PdfReader.pages:                # 遍历pdf文件中的每一页
            print("Page",PdfReader.getPageNumber(page)+1,"/",pageCount)            # Print该页页码
            Ohight = int(page.cropBox.upperRight[1])        # 获取页面高度(英文打错了但懒得改)
            Owidth = int(page.cropBox.upperRight[0])        # 获取页面宽度
            print("Size = (Height:%s"%Ohight, "; Width:%s)"%Owidth,)    # print页面长宽
            packet = io.BytesIO()                           # 为画布创建IO流,申请空间
            packet.seek(0)                                  # 从0开始读写
            can = canvas.Canvas(packet)                     # 创建画布,并绑定IO流
            can.setFont('华光综艺_CNKI',FontSize)             # 设置字体和大小
            xl = "%s" % xulie[i].value                      # 格式化编号内容
            if page.mediaBox.getUpperRight_x() - page.mediaBox.getUpperLeft_x() > \
            page.mediaBox.getUpperRight_y() - page.mediaBox.getLowerRight_y():      # 判断纵横
                print('横向')
                BleedX = FontSize*2                             # 设置空白处宽度
                BleedY = 0                                      # 设置空白处高度
            else:                                               # 纵向同理
                print('纵向')
                BleedX = 0
                BleedY = FontSize*2
            Owidth+=2*BleedX                                    # 记录新的页面宽度
            Ohight+=2*BleedY                                    # 记录新的页面高度
            can.translate(Owidth/2, Ohight/2)                   # 将画布的原点放置在页面中心
            Bpage=writerObj.addBlankPage(Owidth,Ohight)         # 创建新的页面
            Bpage.mergeScaledTranslatedPage(page, 1, BleedX, BleedY)        # 将旧页面居中贴到新页面上
            can.drawString(Owidth / 2 - FontSize * len(xl), Ohight / 2 - FontSize, text=xl.encode('utf-8'))
                                                                # 往画布右上角写字
            can.rotate(180)                                     # 画布颠倒,准备再写字(为了处理上下颠倒的情况)
            can.drawString(Owidth / 2 - FontSize * len(xl), Ohight / 2 - FontSize, text=xl.encode('utf-8'))
                                                                # 往画布右上角再写一次字
            can.save()                              # 画布提交保存到IO流
            textPg = PdfFileReader(packet)          # 通过IO流创建写了编号的pdf
            Bpage.mergePage(textPg.getPage(0))      # 将写了编号的pdf覆盖到输出的页面上

        if writerObj.getNumPages() % 2 == 1: writerObj.addBlankPage()       # 如果页面是单数,就加一页空白页,方便双面打印
        outstream = open(outDir + "/%s.pdf"%xulie[i].value, 'xb')           # 在选定的输出文件夹里新建文件和输出接口(IO流)
        print('Saving as %s'%(outDir + "/%s.pdf"%xulie[i].value))           # print保存的路径
        writerObj.write(outstream)                                          # 将pdf输出到IO流里写入文件
        outstream.close()                                                   # 关闭输出IO流,文件保存
    else:   # 处理图片文件
        # 处理非pdf文件:将同编号的图片文件加入到同一个pdf文件中
        # 表格字典化:
        # 利用字典储存路径列表,键为编号
        PathDict = {'初始':(0)}                                              # 初始化字典:定义字符串(编码)的键,列表(文件路径)的内容
        if PathDict.get("%s" % xulie[i].value)==None:                       # 如果该序列键指向的内容为空(之前没有遍历到同编号的图片的话)
            PathDict["%s" % xulie[i].value]=list("%s" % path[i].value)          # 新建键和列表内容
        else:                                                               # 如果已经有同编号的图片的话
            PathDict["%s" % xulie[i].value].append("%s" % path[i].value)        # 在列表里添加该图片的路径
del i                                                                   # 删除之前i的赋值和格式(变量类型重置)
for i in PathDict.keys():                                               # 遍历字典里的键
    packet = io.BytesIO()                                                   # 为画布创建IO流,申请空间
    packet.seek(0)                                                          # 从0开始读写
    can = canvas.Canvas(packet)                                             # 创建画布,并绑定IO流
    can.setFont('华光综艺_CNKI', FontSize)                                    # 设置字体和大小
    for k in PathDict[i]:                                                   # 遍历键里的列表(图片路径)
        img = Image.open(k, "r")                                                # 打开图片路径读取内容
        can.setPageSize((img.size[0],img.size[1]))                              # 读取图片大小来设置画布大小
        print(k,":",img.size)                                                   # print图片大小
        can.drawImage(canvas.ImageReader(k),0,0)                                # 把图片印在画布上
        Owidth=img.size[0]                                                      # 记录页面宽度为图片宽度
        Ohight=img.size[1]                                                      # 记录页面高度为图片高度
        page=PdfFileWriter.addBlankPage(Owidth,Ohight)                          # 新建一个跟图片同高同宽的页面
        if img.size[0] > img.size[1]:                                           # 判断图片方向
            print('横向')
            BleedX = FontSize * 2                                                   # 设置空白处宽度
            BleedY = 0                                                              # 设置空白处高度
        else:                                                                   # 纵向同理
            print('纵向')
            BleedX = 0
            BleedY = FontSize * 2
        Owidth += 2 * BleedX                                                    # 记录下页面出血后的宽度
        Ohight += 2 * BleedY                                                    # 记录下页面出血后的高度
        can.translate(Owidth / 2, Ohight / 2)                                   # 将画布放在新页面中心
        Bpage = writerObj.addBlankPage(Owidth, Ohight)                          # 在输出pdf里新建新页面
        Bpage.mergeScaledTranslatedPage(page, 1, BleedX, BleedY)                # 把图片页面居中放到输出pdf的新页面中
        can.drawString(Owidth / 2 - FontSize * len(i), Ohight / 2 - FontSize, text=i.encode('utf-8'))  # 写字
        can.rotate(180)                                                         # 画布颠倒,准备再写字(为了处理上下颠倒的情况)
        can.drawString(Owidth / 2 - FontSize * len(i), Ohight / 2 - FontSize, text=i.encode('utf-8'))  # 写字
        can.save()                                                              # 画布提交保存到IO流
        textPg = PdfFileReader(packet)                                          # 通过IO流创建写了编号的pdf
        Bpage.mergePage(textPg.getPage(0))                                      # 将写了编号的pdf覆盖到输出的页面上
    if writerObj.getNumPages() % 2 == 1: writerObj.addBlankPage()   # 如果最终pdf的页面是单数,就加一页空白页,方便双面打印
    outstream = open(outDir + "/%s.pdf" % xulie[i].value, 'xb')     # 在选定的输出文件夹里新建文件和输出接口(IO流)
    print('Saving as %s' % (outDir + "/%s.pdf" % xulie[i].value))   # print保存的文件
    writerObj.write(outstream)  # 将pdf输出到IO流里写入文件
    outstream.close()  # 关闭输出IO流,文件保存

你可能感兴趣的:(python,excel,canvas)