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

openpyxl中按PIL风格等比例缩放图片遇错,求可行解决方案

解决openpyxl中图片按比例缩放并插入Excel的问题

我来帮你搞定这个问题!你遇到的两个错误其实都是因为命名冲突和没有正确区分PIL与openpyxl的Image类导致的,咱们一步步拆解解决:

问题根源分析

  1. AttributeError: 'Image' object has no attribute 'resize':
    你代码里导入的Image来自openpyxl.drawing.image,这个类仅负责将图片导入Excel,本身没有图片缩放的resize方法。而你注释掉了PIL的Image导入,导致screen_scaling里调用的是openpyxl的Image对象,自然触发报错。

  2. UnboundLocalError: local variable 'rel' referenced before assignment:
    这个错误通常是因为你尝试用PIL处理图片后,没有生成openpyxl能正常识别的图片源,再加上命名冲突干扰了类的初始化流程,最终导致变量引用异常。

解决方案:明确区分两类Image类

核心思路是给PIL和openpyxl的Image类重命名导入,彻底避免混淆,然后用PIL完成缩放,再交给openpyxl插入Excel。

方案1:保存缩放后的图片到本地(简单直观)

下面是修正后的完整代码,关键部分我加了注释:

import openpyxl
# 重命名PIL的Image类,避免和openpyxl的冲突
from PIL import ImageGrab, Image as PILImage
# 同样重命名openpyxl的Image类
from openpyxl.drawing.image import Image as XLImage

image_scale = 2
column_start = 3
row_start = 3

def screen_capture():
    img = ImageGrab.grab()
    img.save('test.jpg', 'JPEG')

def screen_scaling():
    # 用PILImage加载本地图片,这才是真正能缩放的图片对象
    img = PILImage.open('test.jpg')
    # 按比例计算新尺寸,保持宽高比
    new_width = int(img.width / image_scale)
    new_height = int(img.height / image_scale)
    # 注意:PIL 9.1.0之后ANTIALIAS被重命名为LANCZOS,低版本可以用PILImage.ANTIALIAS
    resized_img = img.resize((new_width, new_height), PILImage.Resampling.LANCZOS)
    # 保存缩放后的图片(可以覆盖原文件,也可以存新文件)
    resized_img.save('test_resized.jpg', 'JPEG')

wb = openpyxl.Workbook()
ws = wb.active

screen_capture()
screen_scaling()

# 用XLImage加载缩放后的图片,插入到Excel指定位置
img1 = XLImage('test_resized.jpg')
img1.anchor = ws.cell(row=row_start, column=column_start).coordinate
ws.add_image(img1)

wb.save('Save_test_data.xlsx')
wb.close()

方案2:用内存字节流处理(无需生成临时文件)

如果不想生成本地临时文件,可以用io.BytesIO把缩放后的图片存在内存里,直接传给openpyxl,效率更高:

import openpyxl
import io
from PIL import ImageGrab, Image as PILImage
from openpyxl.drawing.image import Image as XLImage

image_scale = 2
column_start = 3
row_start = 3

def screen_capture():
    img = ImageGrab.grab()
    img.save('test.jpg', 'JPEG')

def screen_scaling():
    img = PILImage.open('test.jpg')
    new_width = int(img.width / image_scale)
    new_height = int(img.height / image_scale)
    resized_img = img.resize((new_width, new_height), PILImage.Resampling.LANCZOS)
    
    # 将图片保存到内存字节流
    img_bytes = io.BytesIO()
    resized_img.save(img_bytes, 'JPEG')
    img_bytes.seek(0)  # 重置文件指针到开头,让openpyxl能读取
    return img_bytes

wb = openpyxl.Workbook()
ws = wb.active

screen_capture()
# 获取内存中的缩放图片
resized_img_stream = screen_scaling()

# 直接用字节流初始化XLImage
img1 = XLImage(resized_img_stream)
img1.anchor = ws.cell(row=row_start, column=column_start).coordinate
ws.add_image(img1)

wb.save('Save_test_data.xlsx')
wb.close()

关键注意事项

  • 务必区分PIL和openpyxl的Image类,重命名导入是最稳妥的方式,避免变量混淆。
  • 关于PIL的缩放滤镜:如果你的PIL版本低于9.1.0,继续用PILImage.ANTIALIAS即可;高版本推荐用PILImage.Resampling.LANCZOS,两者效果一致,但后者是官方现在推荐的写法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 07:47:39