如何用Openpyxl在XLSX多工作表添加同一张图片且不增大文件体积?
解决Openpyxl重复插入同一张图片不产生副本的问题
核心思路:复用图片的二进制资源
Openpyxl默认每次添加图片都会重新读取文件并存储副本,但我们可以通过预加载图片的二进制数据,让多个工作表共享同一份图片资源,既规避文件关闭报错,又避免Excel重复存储图片导致体积臃肿。
具体实现步骤
- 一次性读取图片二进制内容:先打开图片文件读取字节数据,之后关闭文件,避免后续重复操作引发I/O错误。
- 创建基础图片对象:基于读取到的字节数据生成一个基础
Image对象,用于复用其image_data属性。 - 在多工作表中复用资源:每个工作表创建新的
Image对象,但直接复用基础对象的image_data,让Excel识别为同一份嵌入资源。
示例代码
from openpyxl import Workbook from openpyxl.drawing.image import Image # 仅读取一次图片二进制数据 with open("product.jpg", "rb") as img_file: img_raw_data = img_file.read() wb = Workbook() # 创建基础图片对象,用于提供共享的image_data base_image = Image() base_image.image_data = img_raw_data # 给多个工作表添加同一张图片 for sheet_title in ["产品列表1", "产品列表2", "产品列表3"]: ws = wb.create_sheet(title=sheet_title) # 新建图片对象但复用基础资源 target_img = Image() target_img.image_data = base_image.image_data target_img.anchor = "B2" # 设置图片在工作表中的位置 ws.add_image(target_img) # 删除默认生成的空白工作表 wb.remove(wb["Sheet"]) wb.save("产品报表.xlsx")
原理说明
Openpyxl的Image对象通过image_data存储图片的二进制内容,当多个Image对象共享同一image_data时,Excel会将该图片作为单一嵌入资源保存,所有工作表的图片引用都会指向这份资源,不会重复存储。同时预读取字节数据的方式,彻底避免了重复打开文件引发的ValueError: I/O operation on closed file错误。
额外提示
- 如果需要调整不同工作表中图片的大小、样式,直接在对应工作表的
target_img对象上设置即可,不会影响共享的图片资源。 - 该方法支持JPG、PNG等Openpyxl兼容的所有图片格式,效果和手动复制图片完全一致,文件体积不会因重复引用增大。
内容的提问来源于stack exchange,提问作者A. Sudnikovich
相关产品推荐
相关产品推荐

