使用openpyxl导入.bin图片至Excel时遇KeyError: '.wmf'求助
解决openpyxl插入.bin(WMF矢量图)时的KeyError: '.wmf'问题
问题原因
你提取的.bin文件本质是WMF矢量格式,openpyxl识别出图片类型为WMF后,会尝试从系统MIME类型映射中查找.wmf对应的类型,但你的Python环境未注册该MIME类型,因此抛出KeyError。
解决方法
方法1:手动注册WMF的MIME类型
在脚本开头添加代码,将WMF的MIME类型注册到mimetypes库,让openpyxl能找到对应映射:
import mimetypes mimetypes.add_type('image/x-wmf', '.wmf')
方法2:保留真实格式扩展名(推荐)
Excel中的.bin图片实际是WMF格式,重命名提取的文件时改为.wmf扩展名(比如image1.bin→image1.wmf),openpyxl可直接识别格式并匹配MIME类型,无需额外注册。
方法3:改用xlsxwriter插入图片
xlsxwriter对矢量图支持更友好,原生兼容WMF格式,无需额外处理MIME类型。
修正后的完整代码
结合方法1的修正版本,同时修复原代码中的路径错误、文件名重复、频繁保存等问题:
from zipfile import ZipFile from pathlib import Path import sys import os import openpyxl from openpyxl.drawing.image import Image import mimetypes # 注册WMF的MIME类型,解决KeyError mimetypes.add_type('image/x-wmf', '.wmf') # 识别图片文件 imgformats = ('bin',) # 元组正确写法,避免被解析为字符串 def is_image(filename): return any(filename.endswith(ext) for ext in imgformats) # 创建保存目录 folders = ['imgsave'] for folder in folders: if not os.path.exists(folder): os.makedirs(folder) # 获取所有xlsx文件 path = Path(".") try: files = list(path.glob('*.xlsx')) # 转为列表避免迭代失效 except PermissionError as e: print(f'Permission Error: {str(e)}') sys.exit() # 统计变量初始化 file_count = 0 overall_size = 0 data = [] # 提取图片到指定目录 media_dir = Path('xl/media') media_dir.mkdir(parents=True, exist_ok=True) # 确保目录层级存在 for file in files: with ZipFile(file) as working_zip: image_list = [name for name in working_zip.namelist() if is_image(name)] # 统计文件大小和数量 for img in image_list: overall_size += working_zip.getinfo(img).file_size file_count = len(image_list) # 提取图片文件 working_zip.extractall("", image_list) # 重命名并移动到media目录,避免文件名重复 for idx, img in enumerate(image_list): new_name = media_dir / f'{file.stem}_{idx+1}.bin' os.rename(img, new_name) data.append(file_count) data.append(overall_size) # 生成图片插入的单元格位置 cellcycletemp = ['A', 'H', 'O', 'V', 'AC'] col_count = len(cellcycletemp) cellcycle = [cellcycletemp[n%col_count] + str((n//col_count) +13) for n in range(120)] # 创建新Excel并插入图片 wb = openpyxl.Workbook() ws = wb.worksheets[0] # 获取所有提取的.bin图片 imagelist = [f for f in os.listdir(media_dir) if f.endswith('.bin')] # 插入图片(限制数量不超过预生成的单元格位置) for n, file in enumerate(imagelist[:120]): img_path = media_dir / file img = Image(img_path) img.anchor = cellcycle[n] ws.add_image(img) # 统一保存文件,避免重复IO操作 wb.save('imgsave/combined images.xlsx')
额外说明
- 若选择方法2,只需将重命名逻辑中的
.bin改为.wmf,可省略MIME类型注册步骤。 - 原代码中
rows=4与cellcycletemp的5个元素不匹配,已修正为按列数自动计算单元格位置。 - 避免在循环内多次调用
wb.save(),所有图片插入完成后统一保存可提升运行效率。
内容的提问来源于stack exchange,提问作者Tea
相关产品推荐
相关产品推荐

