zl程序教程

您现在的位置是:首页 >  Python

当前栏目

Python调用WPS进行文档转换PDF及PDF转图片

2023-03-20 14:52:54 时间

文档转PDF

这里是利用WPS进行转换,要先安装WPS。

安装依赖

pip install pypiwin32

代码

#!/usr/bin/python
# -*- coding: UTF-8 -*-

import os
import win32com.client


def ConvertByWps(sourceFile, targetFile):
    if not os.path.exists(sourceFile):
        print(sourceFile + "不存在,无法继续!")
        return False
    typemap = {
        'doc': 'word',
        'docx': 'word',
        'ppt': 'ppt',
        'pptx': 'ppt',
        'xls': 'excel',
        'xlsx': 'excel',
    }
    name_arr = sourceFile.split(".")
    suffix = name_arr[len(name_arr) - 1]
    wpstype = typemap.get(suffix)

    if (wpstype is None):
        return False

    os.system('taskkill /im wps.exe')
    # 如果文件存在就删除
    if os.path.exists(targetFile):
        os.remove(targetFile)
    if wpstype == 'word':
        ConvertDocToPdf(sourceFile, targetFile)
    elif wpstype == 'ppt':
        ConvertPptToPdf(sourceFile, targetFile)
    elif wpstype == 'excel':
        ConvertXlsToPdf(sourceFile, targetFile)
    if os.path.exists(targetFile):
        return True
    else:
        return False


# 转换 Word文件档到pdf
def ConvertDocToPdf(src, dst):
    wps = win32com.client.Dispatch("Kwps.Application")
    wps.Visible = False
    doc = wps.Documents.Open(src)
    doc.ExportAsFixedFormat(dst, 17)
    doc.Close()
    wps.Quit()


# 转换 PPT文件档到pdf
def ConvertPptToPdf(src, dst):
    wps = win32com.client.Dispatch("Kwpp.Application")
    wps.Visible = False
    ppt = wps.Presentations.Open(src)
    ppt.SaveAs(dst, 32)
    ppt.Close()
    wps.Quit()


# 转换 XLS文件档到pdf
def ConvertXlsToPdf(src, dst):
    wps = win32com.client.Dispatch("Ket.Application")
    excel = wps.Workbooks.Open(src)
    excel.ExportAsFixedFormat(0, dst)
    excel.Close()
    wps.Quit()


if __name__ == '__main__':
    # 当前目录
    d = os.path.dirname(__file__)
    abspath = os.path.abspath(d)

    # 测试用例
    src = abspath + r"/Doc/test.docx"
    dst = abspath + r"/Doc/test.pdf"
    r = ConvertByWps(src, dst)
    print(r)

PDF转图片

方式1

fitz

pip install fitz
pip install PyMuPDF

转换

import fitz
import os
import time


# 将PDF转化为图片
# pdfPath pdf文件的路径
# imgPath 图像要保存的文件夹
# zoom_x x方向的缩放系数
# zoom_y y方向的缩放系数
# rotation_angle 旋转角度
def pdf_image(pdfPath, imgPath, zoom_x, zoom_y, rotation_angle):
    path_arr = pdfPath.split(os.sep)
    path_arr.reverse()
    filename = ""
    if(len(path_arr) > 0):
        filename = path_arr[0].split(".")[0]
    start_time = time.perf_counter()
    pdf = fitz.open(pdfPath)

    # 逐页读取PDF
    filename_arr = []
    for pg in range(0, pdf.pageCount):
        page = pdf[pg]
        # 设置缩放和旋转系数
        trans = fitz.Matrix(zoom_x, zoom_y).prerotate(rotation_angle)
        pm = page.get_pixmap(matrix=trans, alpha=False)
        # 开始写图像
        filename_all = f'{imgPath}{os.sep}{filename}_{str(pg)}.png'
        pm.save(filename_all)
        filename_arr.append(filename_all)
    pdf.close()
    end_time = time.perf_counter()
    print(f"时间差:{end_time-start_time}")
    print(len(filename_arr))


pdf_image(
    r"D:ToolsDocTest145页.pdf",
    r"D:ToolsDocTestpic",
    2,
    2,
    0
)

方式2

安装poppler

https://blog.alivate.com.au/poppler-windows/

添加bin对应目录到环境变量

注意

如果调用方法传入poppler_path参数,则不用设置环境变量。

https://github.com/Belval/pdf2image

安装依赖

pip install pdf2image

转换代码

from pdf2image import convert_from_path, convert_from_bytes
from pdf2image.exceptions import (
    PDFInfoNotInstalledError,
    PDFPageCountError,
    PDFSyntaxError
)
import time

try:
    start_time = time.perf_counter()
    images = convert_from_path(
        r"D:ToolsDocTest145页.pdf",
        output_folder=r"D:ToolsDocTestpic",
        poppler_path=r"D:Toolspoppler-0.67.0in",
        size=(1024, None),
        thread_count=4,
        timeout=60,
        fmt='jpeg'
    )
    end_time = time.perf_counter()
    print(f"时间差:{end_time-start_time}")
    print(images[0])
except PDFInfoNotInstalledError:
    print("未安装poppler")
except PDFPageCountError:
    print("页面异常")
except PDFSyntaxError:
    print("PDF页面异常")
except:
    print("其它异常")

转换时间对比

PDF页数

是否带水印

方式1(s)

方式2(s)

方式2-4线程(s)

1

0.0596313

0.1325932

0.1315048

2

0.2342085

0.2125386

0.1481465

145

23.7634431

16.4102064

5.3497324

448

否/纯文字

20.5313859

30.8443124

8.4962063

结论

  • 转换速度方式2在页面少的时候时间稍长,但是一旦页码多的时候方式2优势就比较明显。
  • 两种都能正常转换带水印的文档。
  • 如果文档都是纯文字GBK的时候,方式1转换正常,而方式2乱码。

方式1我切换为多线程依旧作用不大

import fitz
import os
import time
from concurrent import futures
import threading


# 将PDF转化为图片
# pdfPath pdf文件的路径
# imgPath 图像要保存的文件夹
# zoom_x x方向的缩放系数
# zoom_y y方向的缩放系数
# rotation_angle 旋转角度
def pdf_image(pdfPath, imgPath, zoom_x, zoom_y, rotation_angle):
    path_arr = pdfPath.split(os.sep)
    path_arr.reverse()
    filename = ""
    if(len(path_arr) > 0):
        filename = path_arr[0].split(".")[0]
    start_time = time.perf_counter()
    pdf = fitz.open(pdfPath)

    # 逐页读取PDF
    filename_arr = []
    pages = []

    def savePage(pageobj):
        print(threading.current_thread().name)
        page = pageobj["page"]
        pg = pageobj["pg"]
        # 设置缩放和旋转系数
        trans = fitz.Matrix(zoom_x, zoom_y).prerotate(rotation_angle)
        pm = page.get_pixmap(matrix=trans, alpha=False)
        # 开始写图像
        filename_all = f'{imgPath}{os.sep}{filename}_{str(pg)}.png'
        pm.save(filename_all)
        filename_arr.append(filename_all)

    for pg in range(0, pdf.pageCount):
        page = pdf[pg]
        pages.append({
            "page": page,
            "pg": pg
        })

    print(len(pages))

    with futures.ThreadPoolExecutor(max_workers=8) as executor:
        for future in executor.map(savePage, pages):
            pass
    pdf.close()
    end_time = time.perf_counter()
    print(f"时间差:{end_time-start_time}")
    print(len(filename_arr))


pdf_image(
    r"D:ToolsDocTest145页.pdf",
    r"D:ToolsDocTestpic",
    2,
    2,
    0
)