批量把word转图片再转pdf,防止文字被复制

🎯 程序主要功能

该程序实现了一个 自动化文档处理流水线,核心目标是:

将指定目录中的 Microsoft Word(.docx)文档批量转换为高质量、小体积的图像型 PDF 文件,适用于归档、分享或嵌入系统等场景。

注意不是word直接转pdf,而是先转图片,再拼凑成pdf,这样可以有效的防止pdf的文字被复制。

✅ 具体功能包括:

  1. 批量处理

    自动扫描 C:\temp 目录下所有 .docx 文件(自动跳过 Word 临时文件如 ~$xxx.docx)。

  2. Word → PDF 转换

    利用 Microsoft Word 的 COM 接口,将每个 .docx 文档导出为标准 PDF(保留原始排版)。

  3. PDF → 高清 JPEG 图像

    使用高分辨率(默认 150 DPI)将 PDF 每一页渲染为 JPEG 图片,兼顾清晰度与文件体积。

  4. 图像 → 压缩 PDF 合并

    将所有 JPEG 页面重新组合成一个单一 PDF 文件,并启用:

    • zlib 流压缩(deflate=True
    • 图像流压缩(deflate_images=True
    • 冗余对象清理(garbage=3, clean=True
  5. 错误容错与重试机制

    对于因 Word 卡顿或复杂内容导致失败的文档,自动重试最多 2 次,提升成功率。

  6. 输出结构清晰

    • 图片临时目录:xxx_pages/
    • 最终 PDF:xxx_combined.pdf
    • 显示生成文件大小(MB),便于监控
  7. 资源安全释放

    严格管理 Word 进程、临时文件、内存对象,防止进程残留或磁盘堆积。


⚙️ 技术栈(依赖库)

技术 用途 安装命令
pywin32 调用 Windows 上的 Microsoft Word COM 接口,实现 .docx → PDF pip install pywin32
PyMuPDF (fitz) 高性能 PDF 渲染、图像提取、PDF 合并与压缩 pip install PyMuPDF
Pillow (PIL) 将位图数据保存为 JPEG 格式(控制质量与体积) pip install Pillow
Python 标准库 tempfile(临时文件)、pathlib(路径操作)、os(文件系统)等 内置

💡 运行环境要求

  • Windows 系统(因依赖 Word COM)
  • 已安装 Microsoft Word(2010 或更高版本)
  • Python 3.7+

📦 典型应用场景

  • 项目文档自动化归档(可以代替出扫描文档再组成pdf)
  • 将动态 Word 报表转为不可编辑的 PDF 快照
  • 为无 Office 环境提供标准化文档交付格式
  • 减少人工操作,提升批量处理效率

📌 总结一句话

本程序利用 Word + PyMuPDF + Pillow 构建了一条稳定、高效、低体积的 Word → 图像型 PDF 自动化转换流水线,专为 Windows 企业文档处理场景设计。

复制代码
import os
import time
import tempfile
from pathlib import Path

import win32com.client
import fitz
from PIL import Image

TEMP_DIR = r"C:\temp"
DPI = 150
JPEG_QUALITY = 85
MAX_RETRIES = 2  # 失败重试次数

def pixmap_to_image(pix):
    return Image.frombytes("RGB", (pix.width, pix.height), pix.samples)

def safe_word_quit(app):
    try:
        if app:
            app.Quit()
    except:
        pass

def process_docx(word_path, retry=0):
    print(f"\n正在处理: {word_path.name} (尝试 {retry + 1}/{MAX_RETRIES + 1})")
    safe_name = "".join(c if c.isalnum() or c in "._-" else "_" for c in word_path.stem)
    output_folder = Path(TEMP_DIR) / f"{safe_name}_pages"
    output_folder.mkdir(exist_ok=True)

    temp_pdf = None
    word_app = None
    doc_obj = None

    try:
        # 创建临时 PDF
        with tempfile.NamedTemporaryFile(suffix=".pdf", delete=False) as tmp:
            temp_pdf = tmp.name

        # 启动 Word(关键:加延迟避免冲突)
        word_app = win32com.client.Dispatch("Word.Application")
        word_app.Visible = False
        word_app.DisplayAlerts = False  # 禁用弹窗

        doc_obj = word_app.Documents.Open(
            str(word_path.resolve()),
            ReadOnly=True,
            PasswordDocument="",  # 无密码
            AddToRecentFiles=False
        )
        doc_obj.ExportAsFixedFormat(OutputFileName=temp_pdf, ExportFormat=17)
        doc_obj.Close(SaveChanges=False)
        doc_obj = None
        safe_word_quit(word_app)
        word_app = None

        # PDF → JPEG
        pdf_doc = fitz.open(temp_pdf)
        zoom = DPI / 72.0
        mat = fitz.Matrix(zoom, zoom)
        image_paths = []

        for i in range(pdf_doc.page_count):
            page = pdf_doc.load_page(i)
            pix = page.get_pixmap(matrix=mat, alpha=False)
            img = pixmap_to_image(pix)
            img_path = output_folder / f"page_{i+1:03d}.jpg"
            img.save(img_path, "JPEG", quality=JPEG_QUALITY, optimize=True)
            image_paths.append(str(img_path))
            print(f"  → 已保存: {img_path}")

        pdf_doc.close()

        # 合并为 PDF
        if image_paths:
            output_pdf = Path(TEMP_DIR) / f"{safe_name}_combined.pdf"
            new_pdf = fitz.open()
            for img_path in image_paths:
                img_doc = fitz.open(img_path)
                w = img_doc[0].get_pixmap().width
                h = img_doc[0].get_pixmap().height
                img_doc.close()
                page = new_pdf.new_page(width=w, height=h)
                page.insert_image(fitz.Rect(0, 0, w, h), filename=img_path)
            new_pdf.save(str(output_pdf), garbage=3, deflate=True, deflate_images=True, clean=True)
            new_pdf.close()
            print(f"  → 已生成压缩 PDF: {output_pdf}")
            print(f"    文件大小: {output_pdf.stat().st_size / (1024*1024):.2f} MB")

        # 可选:删除图片文件夹
        # import shutil; shutil.rmtree(output_folder)

        return True

    except Exception as e:
        print(f"  ❌ 处理失败: {e}")
        if retry < MAX_RETRIES:
            time.sleep(2)  # 等待 2 秒再重试
            return process_docx(word_path, retry + 1)
        return False
    finally:
        # 强制清理
        if doc_obj:
            try:
                doc_obj.Close(SaveChanges=False)
            except:
                pass
        safe_word_quit(word_app)
        if temp_pdf and os.path.exists(temp_pdf):
            try:
                os.remove(temp_pdf)
            except:
                pass

def main():
    temp_dir = Path(TEMP_DIR)
    if not temp_dir.exists():
        print(f"目录 {TEMP_DIR} 不存在!")
        return

    # 只处理真正的 .docx,排除 ~$ 临时文件
    docx_files = [
        f for f in temp_dir.glob("*.docx")
        if f.is_file() and not f.name.startswith("~$")
    ]

    if not docx_files:
        print(f"{TEMP_DIR} 中没有找到有效的 .docx 文件。")
        return

    print(f"共发现 {len(docx_files)} 个文档待处理。")

    success_count = 0
    for word_path in docx_files:
        if process_docx(word_path):
            success_count += 1

    print(f"\n✅ 完成!成功: {success_count}/{len(docx_files)}")

if __name__ == "__main__":
    main()
相关推荐
小c君tt2 小时前
QT中treewidget中右键添加QAction方法
开发语言·qt
HUST2 小时前
C 语言 第九讲:函数递归
c语言·开发语言·数据结构·算法·c#
CodeCraft Studio2 小时前
国产化Word处理控件Spire.Doc教程:使用C# 编程方式批量转换Word为RTF
开发语言·c#·word·spire.doc·word文档转换·word开发组件·word api库
CSDN_RTKLIB2 小时前
【类定义系列一】C++ 头文件 / 源文件分离
开发语言·c++
invicinble2 小时前
arthas
开发语言·python
lzjava20242 小时前
Python中的模块和包
linux·开发语言·python
卜锦元2 小时前
Golang后端性能优化手册(第二章:缓存策略与优化)
开发语言·数据库·后端·性能优化·golang
挖矿大亨2 小时前
c++中值传递时是如何触发拷贝构造函数的
开发语言·c++
郝亚军2 小时前
顺序栈C语言版本
c语言·开发语言·算法