WPS Office 粘贴截图时会生成 =DISPIMG("ID_xxx",1) 公式嵌入图片,这类图片在 Microsoft Excel 中无法正常显示。这个工具自动把所有公式图片提取为 Excel 原生浮动图片,精确匹配单元格尺寸,一个命令搞定。单文件 Python,零配置,打包成 exe 可直接分发。

处理流程 — 7 个阶段
📦
.xlsx 解压
ZipFile
🔍
扫描公式
lxml XML
🖼️
匹配图片
ID → media
🧹
清除公式
删除 DISPIMG
📐
插入浮动图
openpyxl
🎯
修正尺寸
EMU 尺寸修正
📥
保存输出
_excel.xlsx

一、WPS 的 DISPIMG 是什么

WPS Office 里粘贴截图时,它不会像 Excel 那样直接插入浮动图片,而是在单元格内写入一个 =DISPIMG("ID_XXXXXXXX",1) 公式,图片数据存在 xlsx 包的 xl/media/ 目录中。这个公式是 WPS 私有的,Microsoft Excel 不识别——打开后要么显示公式文本,要么一片空白。

手动操作的替代方案是逐张另存再插入,耗时且容易出错。自动化处理的核心思路:解压 xlsx → 删除公式 → 匹配 media 文件 → 用 openpyxl 插入浮动图片 → 修正 XML 尺寸

二、核心模块拆解

2.1 单元格尺寸计算

图片需要精确缩放到单元格大小。Excel 的列宽单位和行高单位不是像素,需要做转换:列宽单位 ≈ 默认字体数字 0 的宽度 + padding(Calibri 11pt 下 1 单位 ≈ 8px),行高 pt 转 px 用 96/72 换算。

def col_width_to_pixels(width, default_font='Calibri', default_size=11):
    if width is None:
        width = 8.43  # Excel 默认列宽
    return int(width * 8 + 5)

def row_height_to_pixels(height):
    if height is None:
        height = 15  # Excel 默认行高
    return int(height * 96 / 72)

2.2 ID 与文件匹配

DISPIMG 公式中的 ID(如 ID_A3F8B2C1)需要映射到 xl/media/ 下的实际图片文件。采用三级匹配策略:精确文件名匹配 → 部分包含匹配 → 剩余文件轮询兜底。确保每张公式图都能找到对应的 media 文件。

# 三级匹配策略
for img_id in all_ids:
    if img_id in media_map:                  # ① 精确匹配
        id_to_file[img_id] = media_map[img_id]
    else:
        for name, fp in media_map.items():
            if img_id in name:              # ② 包含匹配
                id_to_file[img_id] = fp
                break

2.3 EMU 尺寸修正

openpyxl 插入的浮动图片在 drawing XML 中用 EMU(English Metric Units)表示尺寸,但 openpyxl 设置的像素尺寸在重新打包后会丢失精度。工具在最后一步直接解析 XML,将像素转换为 EMU(1px = 9525 EMU)写入 <a:ext> 节点,确保在 Excel 中打开时图片大小完全正确。

# 像素 → EMU 写入 drawing XML
ext.set('cx', str(target_w * 9525))
ext.set('cy', str(target_h * 9525))

三、进度条:打包 exe 后的刚需

大文件可能包含上百张图片,如果没有进度反馈,用户会以为程序卡死了。实现了一个零依赖的 ProgressBar 类,输出到 stderr,不干扰主逻辑。

终端运行效果
PowerShell — wps_convert.exe
PS D:\work> .\wps_convert.exe report.xlsx

📥 解压文件... ██████████████████████████████ 100.0%
📋 表格 ██████████████████████████████ 100.0% (8/8)
DISPIMG 公式: 156 个 | media 文件: 152 个
匹配: 156/156
📥 插入图片... ████████████████████░░░░░░░░░░ 65.4%
🖼️ 插入图片 ████████████████████████████░░ 95/156

✅ 完成!156 个图片已转为浮动图片 → report_excel.xlsx

按回车键退出...

7 个阶段按权重分配进度:解压 5%、扫描 10%、清理 10%、打包 5%、插入图片 50%(最慢,有独立子进度条)、修正尺寸 15%、保存 5%。总体进度条 + 嵌套子进度条,用户能清楚看到当前跑到哪一步。

四、用法

4.1 命令行

# 直接指定文件
python wps_convert.py input.xlsx

# 指定输出路径
python wps_convert.py input.xlsx output.xlsx

# 双击 exe,弹出文件选择框
wps_convert.exe

4.2 依赖

首次运行自动安装 lxmlPillowopenpyxl,无需手动 pip install。打包 exe 后跳过自动安装。

五、打包分发

PyInstaller 单文件打包,目标用户无需安装 Python:

# PowerShell 一条命令
pyinstaller --onefile --icon=03.ico \
  --hidden-import=lxml --hidden-import=lxml.etree \
  --hidden-import=PIL --hidden-import=openpyxl \
  --name wps_convert wps_convert.py
💡 踩坑记录:PyInstaller 6.0 以上移除了 --key 字节码加密,如果你之前用的是旧版打包命令,需要去掉 --key 参数,否则直接报错。

六、总结

一个解决实际办公痛点的小工具:WPS 公式图片在 Excel 中不显示 → 自动提取为浮动图片。核心约 400 行 Python,解压 xlsx 包、解析 XML、匹配 media 文件、用 openpyxl 重新插入浮动图片、后处理修正 EMU 尺寸。加上进度条和错误捕获,打包后可直接分发给同事使用。

核心收获:xlsx 本质上是一个 zip 包,理解了 Open XML 格式,很多 Excel 自动化问题都能迎刃而解