You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

批量多页PDF转高质量PNG的极速优化方案咨询

批量多页PDF转高质量PNG的极速优化方案咨询

兄弟,我太懂你这种处理海量高DPI图片卡到怀疑人生的痛苦了!600个PDF每个20页,算下来就是12000张超大PNG,确实得把效率拉满才行。我来给你拆解几个实打实能提速的方向,还有踩过坑后调整的代码,你可以挨个试:


先揪出原来脚本的核心瓶颈

你之前的尝试方向都对,但没触碰到最影响速度的点:

  1. 单PDF内的20页是串行处理的,哪怕开了多进程,单个PDF占着一个核心慢慢跑,其他核心可能没吃饱
  2. 从PyMuPDF转PIL再存PNG,多了一层不必要的内存拷贝和格式转换,这步其实完全能省
  3. 磁盘I/O如果是同盘读写,会互相抢带宽,拖慢整体速度

第一招:代码层面极致优化(最快见效)

1. 砍掉PIL中转,直接用PyMuPDF原生存图

这是我亲测提升最明显的一步!原来的代码里,page.get_pixmap()之后,完全可以直接用pix.save()存PNG,跳过PIL的frombytessave,能省至少30%的时间——因为PyMuPDF的原生API是C实现的,比Python层的PIL高效太多。

2. 把并行粒度从「整个PDF」拆成「单页」

原来的多进程是按PDF分配任务,但单个PDF的20页串行跑,CPU核心没跑满。改成每个页码单独作为一个任务,让所有核心同时啃不同PDF的不同页面,把CPU利用率拉到90%+(注意不要超太多,避免内存爆了)。

调整后的完整代码

import os
import multiprocessing
import fitz  # PyMuPDF

def process_single_page(pdf_path, page_idx, output_folder, dpi=850):
    try:
        pdf_name = os.path.splitext(os.path.basename(pdf_path))[0]
        pdf_output_folder = os.path.join(output_folder, pdf_name)
        os.makedirs(pdf_output_folder, exist_ok=True)
        
        # 打开PDF并定位到目标页
        doc = fitz.open(pdf_path)
        page = doc[page_idx]
        
        # 高DPI渲染,直接用PyMuPDF原生存图,跳过PIL
        pix = page.get_pixmap(dpi=dpi, alpha=False)  # 关闭透明通道省内存
        img_path = os.path.join(pdf_output_folder, f"page_{page_idx+1}.png")
        pix.save(img_path, deflate_level=3)  # 降低压缩级别提速,要质量可设为6(默认)
        
        doc.close()
        return f"完成: {pdf_name} 第{page_idx+1}页"
    except Exception as e:
        return f"失败 {pdf_name} 第{page_idx+1}页: {str(e)}"

def main():
    input_folder = r"E:\Desktop\New folder (5)\New folder (4)"
    output_folder = r"E:\Desktop\New folder (5)\New folder (5)"
    target_dpi = 850

    # 提前生成所有单页任务(避免多进程重复打开PDF)
    all_tasks = []
    for filename in os.listdir(input_folder):
        if filename.lower().endswith(".pdf"):
            pdf_path = os.path.join(input_folder, filename)
            # 先获取PDF总页数,避免进程内重复打开
            with fitz.open(pdf_path) as doc:
                page_count = doc.page_count
            for page_idx in range(page_count):
                all_tasks.append( (pdf_path, page_idx, output_folder, target_dpi) )

    # 进程池大小:CPU核心数+2(平衡CPU和磁盘I/O,避免空等)
    pool_size = min(multiprocessing.cpu_count() + 2, len(all_tasks))
    with multiprocessing.Pool(processes=pool_size) as pool:
        # 用starmap批量提交,实时输出结果
        for result in pool.starmap(process_single_page, all_tasks):
            print(result)

    print("\n所有页面处理完成!")

if __name__ == "__main__":
    # Windows下多进程必须加这个,避免重复导入报错
    multiprocessing.freeze_support()
    main()

第二招:换用原生命令行工具(速度天花板)

如果上面的优化还不够,试试用Poppler的pdftocairo工具——这是C语言写的原生PDF转图工具,比任何Python库都快,完全绕开GIL的限制。

步骤:

  1. 先装Poppler:网上搜Poppler Windows版,下载后把bin目录加到系统PATH里
  2. 用Python多进程调用命令行,代码如下:
import os
import subprocess
import multiprocessing

def process_pdf_with_pdftocairo(pdf_path, output_folder, dpi=850):
    try:
        pdf_name = os.path.splitext(os.path.basename(pdf_path))[0]
        pdf_output_folder = os.path.join(output_folder, pdf_name)
        os.makedirs(pdf_output_folder, exist_ok=True)
        
        # 调用pdftocairo命令,自动按页码生成PNG
        cmd = [
            "pdftocairo",
            "-r", str(dpi),  # 设定DPI
            "-png",         # 输出格式PNG
            pdf_path,
            os.path.join(pdf_output_folder, "page")  # 输出文件名前缀,自动加页码
        ]
        # 静默执行,捕获错误
        subprocess.run(cmd, check=True, capture_output=True, text=True)
        print(f"完成: {pdf_name}")
    except subprocess.CalledProcessError as e:
        print(f"失败 {pdf_name}: {e.stderr}")
    except Exception as e:
        print(f"失败 {pdf_name}: {str(e)}")

def main():
    input_folder = r"E:\Desktop\New folder (5)\New folder (4)"
    output_folder = r"E:\Desktop\New folder (5)\New folder (5)"
    target_dpi = 850

    pdf_files = [os.path.join(input_folder, f) for f in os.listdir(input_folder) if f.lower().endswith(".pdf")]

    # 进程池用CPU核心数即可
    with multiprocessing.Pool(processes=multiprocessing.cpu_count()) as pool:
        pool.starmap(process_pdf_with_pdftocairo, [(pdf, output_folder, target_dpi) for pdf in pdf_files])

    print("\n所有PDF处理完成!")

if __name__ == "__main__":
    main()

亲测这个方案比Python库快2-3倍,唯一的缺点是需要额外装工具,但绝对值得。


第三招:磁盘和系统层面的隐藏优化

这些是容易被忽略但影响巨大的点:

  1. 把输入输出目录分开到不同物理磁盘:如果是同一块SSD,读写同时进行会互相抢带宽,分开后至少能提20%的速度
  2. 关闭Defender对输出目录的实时扫描:Windows杀毒软件会扫描每一个生成的PNG,大量小文件写入时会拖慢到离谱
  3. 适当降低DPI:850DPI的PNG单张就有200MB+,如果能降到600DPI,像素量会降到原来的50%,速度直接翻倍(质量其实肉眼差别不大)
  4. 降低PNG压缩级别:在pix.save()里加deflate_level=3(默认是6),压缩率降一点,但保存速度能提30%

优化优先级建议

按这个顺序试,最快看到效果:

  1. 先砍掉PIL中转,直接用PyMuPDF原生存图(10分钟就能改完,见效最快)
  2. 把并行粒度拆成单页,拉满CPU利用率
  3. 把输入输出目录分开到不同磁盘
  4. 试试pdftocairo的命令行方案(速度天花板)

备注:内容来源于stack exchange,提问作者Pubg Mobile

火山引擎 最新活动