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

Python openpyxl绘制Excel像素画 大图生成文件损坏问题求助

Excel逐像素绘图大尺寸文件损坏问题排查与解决

问题描述

基于openpyxl+PIL编写的自动化脚本,可在Microsoft Excel中通过逐单元格填色实现像素画效果:

  • 处理500×500左右小尺寸图片时运行正常,输出文件可正常打开
  • 传入大尺寸图片时,生成的Excel文件提示损坏,无法正常打开
  • 脚本内变量为波兰语命名,完整实现代码如下:
import time
from openpyxl import Workbook, load_workbook
from openpyxl.styles import Color, PatternFill, Font, Border
from PIL import Image

plik = "1.xlsx"
fota = "fb.png"

start = time.time()

zdj = Image.open(fota)
zdj_rgb = zdj.convert("RGB")
szer, wys = zdj.size

wb = load_workbook(plik)
ws = wb.active

def rgb_to_hex(rgb):
    return '%02x%02x%02x' % rgb

def excel_col(col):
    
    quot, rem = divmod(col-1,26)
    return excel_col(quot) + chr(rem+ord('A')) if col!=0 else ''

for y in range(wys):
    for x in range(szer):

        yy = y+1

        komorka = str(excel_col(x+1) + str(yy))

        pixel_rgb = zdj_rgb.getpixel((x, y))
        
        rgb = "00" + str(rgb_to_hex((pixel_rgb[0], pixel_rgb[1], pixel_rgb[2])))

        rgbFill = PatternFill(start_color=rgb,
                end_color=rgb,
                fill_type='solid')

        ws[komorka].fill = rgbFill

end = time.time()

minuty, sekundy = divmod((end-start), 60)

print(f"Renderowanie zajelo {minuty} minut/y i {round(sekundy)} sekund.")

wb.save(plik)

排查思路

按优先级从高到低排查以下三类原因:

  • 超出Excel格式硬限制:Microsoft Excel单工作表最大支持16384列、1048576行,若输入图片宽度超过16384像素、高度超过1048576像素,脚本会生成超出合法范围的单元格地址,直接破坏xlsx文件结构。
  • 样式冗余超限:当前脚本为每个单元格单独创建PatternFill样式对象,即使多个单元格颜色完全一致也会生成独立样式条目。大尺寸图片下单元格数量暴涨,xlsx内部样式表的条目数会快速超出Excel或openpyxl支持的上限,触发文件损坏。
  • 写入不完整:默认模式下openpyxl会将全量工作表数据加载到内存,大尺寸图片对应单元格量达到数十万甚至上百万级别时,保存阶段容易因内存不足出现写入截断,生成不完整的xlsx压缩包,导致打开时提示损坏。

解决方案

对应问题点逐一修复即可:

  • 增加尺寸前置校验:加载图片后先判断宽高是否超出Excel单表行列上限,超出则先等比缩放到合法范围再处理,避免生成非法单元格地址。
  • 增加样式缓存复用:新建字典做颜色到样式对象的映射,相同RGB颜色仅创建一次PatternFill对象,所有同色单元格复用该对象,可将样式条目数从“单元格总数”降低到“图片使用的颜色总数”,同时大幅提升运行速度。核心优化代码如下:
# 初始化样式缓存
fill_cache = {}

for y in range(wys):
    for x in range(szer):
        yy = y + 1
        # 直接通过行列号获取单元格,比拼接地址字符串效率高3~5倍
        komorka = ws.cell(row=yy, column=x+1)
        pixel_rgb = zdj_rgb.getpixel((x, y))
        rgb_key = "00" + rgb_to_hex(pixel_rgb)
        # 缓存中无对应颜色时再新建样式
        if rgb_key not in fill_cache:
            fill_cache[rgb_key] = PatternFill(start_color=rgb_key, end_color=rgb_key, fill_type='solid')
        komorka.fill = fill_cache[rgb_key]
  • 大尺寸场景切换为只写模式:当图片尺寸超过2000×2000时,放弃加载现有Excel文件,使用Workbook(write_only=True)创建只写工作簿,该模式下openpyxl不会将全量数据驻留内存,而是逐段将数据写入磁盘,可彻底避免内存不足导致的写入截断问题。
  • 移除低效的列名转换逻辑:原脚本中递归实现的excel_col函数在列数较大时性能很差,直接用ws.cell(row=行号, column=列号)的方式访问单元格,无需手动拼接列名字符串,可大幅缩短整体运行时间。

内容的提问来源于stack exchange,提问作者Michal Pielka

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 21:45:46