You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Python PIL生成PDF时内存错误的修复方案咨询

解决大量图片生成PDF时的Memory Error问题

看起来你遇到的核心问题是内存耗尽:你的代码把所有生成的标签图片都存在imlist列表里,当处理大量图片时,内存被这些PIL Image对象占满,引发MemoryError。而报错里的AttributeError只是内存不足导致图片加载失败的次生问题,根源还是内存占用过高。

下面是针对性的解决方案,修改后的代码可以支持处理任意数量的图片,同时保持内存占用在合理水平:

核心思路

不再一次性把所有图片存在内存里,而是逐个生成标签并保存为单个临时PDF文件,最后用PDF合并工具把这些临时文件合并成一个最终PDF。这样内存里每次只需要处理一张图片,不会随着图片数量线性增长。

修改后的代码

首先需要安装PyPDF2库(用于合并PDF):

pip install PyPDF2

替换你的代码为以下版本:

from PIL import Image, ImageDraw, ImageFont
import textwrap
import pandas
import datetime
import os
from tkinter import filedialog
from tqdm import tqdm_gui
from PyPDF2 import PdfMerger
import tempfile

datenow = datetime.datetime.now()
pdate = datenow.strftime("%d-%m-%y")
y = 0
excel = filedialog.askopenfilename(initialdir="/", title="Select A File", filetypes=(('Excel File', '*.xlsx'),('all files', '*.*')))
save_dir = filedialog.askdirectory()

# 创建自动清理的临时目录,存储单个页面PDF
with tempfile.TemporaryDirectory(dir=save_dir) as temp_dir:
    df = pandas.read_excel(excel)
    merger = PdfMerger()  # 初始化PDF合并器
    
    # 遍历Excel数据,生成标签
    for data in tqdm_gui(df.values, desc="Generating labels..."):
        name, no = data
        x = 0
        while x < no:
            x += 1
            y += 1
            LH = len(name)
            
            # 根据名称长度调整字体大小和换行宽度
            if LH < 32:
                font_size = 70
                wrap_width = 16
            else:
                font_size = 53
                wrap_width = 22
            
            name_upper = name.upper()
            wrapped_text = textwrap.wrap(name_upper, width=wrap_width)
            MAX_W, MAX_H = 800, 592
            
            # 加载模板图片并绘制文本
            im = Image.open('TFC.jpg')
            draw = ImageDraw.Draw(im)
            font = ImageFont.truetype('OpenSans-ExtraBold.ttf', font_size)
            current_h, line_pad = 155, -5
            
            for line in wrapped_text:
                w, h = draw.textsize(line, font=font)
                draw.text(((MAX_W - w) / 2, current_h), line, font=font)
                current_h += h + line_pad
            
            # 保存当前标签为单个PDF,然后关闭图片释放内存
            temp_pdf = os.path.join(temp_dir, f"temp_label_{y}.pdf")
            im.save(temp_pdf, save_all=True)
            im.close()
            
            # 将临时PDF添加到合并队列
            merger.append(temp_pdf)
    
    # 生成最终的合并PDF
    final_pdf_path = os.path.join(save_dir, f"{pdate} TF {y}.pdf")
    merger.write(final_pdf_path)
    merger.close()

os.startfile(save_dir)

关键优化点

  1. 内存控制:每个标签生成后立即保存为PDF并关闭图片对象,释放内存,避免累积所有图片
  2. 临时文件自动清理:使用tempfile.TemporaryDirectory,程序结束后会自动删除所有临时PDF文件,无需手动清理
  3. 代码健壮性:修复了原代码中name = name.upper()修改原始数据的问题,改用独立变量存储大写名称
  4. 进度提示优化:给tqdm_gui添加了描述文本,更直观了解生成进度

额外优化建议

如果想进一步提升性能,可以提前加载固定资源(模板图片和字体),避免重复IO操作:

# 在循环开始前提前加载模板和字体
template_image = Image.open('TFC.jpg')
font_cache = {}

# 循环内替换图片加载和字体加载部分
im = template_image.copy()  # 复制模板,避免修改原始图片
if font_size not in font_cache:
    font_cache[font_size] = ImageFont.truetype('OpenSans-ExtraBold.ttf', font_size)
font = font_cache[font_size]

这样可以减少重复打开图片和字体文件的开销,提升处理大量图片时的速度。

内容的提问来源于stack exchange,提问作者Raja Monsingh Charles

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 18:02:43