背景介绍
想象一下,你在制作一份电子表格,需要在某些单元格中放入产品图片。在 Excel 中,你只能把图片放在表格的”上层”,就像在表格上贴了一张贴纸。这样的图片是独立的,当你移动或复制单元格时,图片并不会跟着走。
WPS 为了解决这个问题,创造性地提出了 DISPIMG 公式。这个方案就像是把图片”嵌入”到了单元格中,让图片真正成为单元格的一部分。这样,无论你怎么移动或复制单元格,图片都会跟着走。
实现机制
WPS 的单元格图片功能通过三个关键文件相互配合来实现:
1. 工作表引用(sheet1.xml)- 图片的”索引卡”
想象你在图书馆查找一本书,首先会查看索引卡片。这里的 DISPIMG 公式就像是一张索引卡,记录了”这个单元格要显示哪张图片”的信息。
在工作表中,通过 DISPIMG 函数来引用单元格图片:
<sheetData>
<row r="1" ht="14.25">
<c r="C1" t="str">
<f>DISPIMG("ID_A16C8CE6E39B4F25934D584A1C41E1E1",1)</f>
<v>=DISPIMG("ID_A16C8CE6E39B4F25934D584A1C41E1E1",1)</v>
</c>
</row>
</sheetData>
其中, DISPIMG 函数接受两个参数:
- 图片的唯一标识符(ID)
- 图片的展示方式(模式参数)
2. 图片定义(cellimages.xml)- 图片的”档案卡”
每张图片都有一个详细的”档案卡”(存储在 cellimages.xml 中),记录了这张图片的所有重要信息:
- 图片的唯一编号(就像身份证号)
- 图片的显示方式(如何摆放、多大尺寸等)
- 图片实际存储位置的线索
特别值得注意的是,WPS 在设计这个”档案卡”时,采用了与 Office 文档相同的标准格式(OOXML)。这不仅确保了其他软件能理解这些信息,更重要的是,这样的设计让开发者可以复用处理传统 Office 浮动图片的代码逻辑,大大减少了重复开发的工作量。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<etc:cellImages
xmlns:xdr="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
xmlns:etc="http://www.wps.cn/officeDocument/2017/etCustomData">
<etc:cellImage>
<xdr:pic>
<!-- 1. 图片标识信息 -->
<xdr:nvPicPr>
<xdr:cNvPr id="1773908100" name="ID_A16C8CE6E39B4F25934D584A1C41E1E1"/>
<xdr:cNvPicPr>
<a:picLocks noChangeAspect="1"/>
</xdr:cNvPicPr>
</xdr:nvPicPr>
<!-- 2. 图片资源引用 -->
<xdr:blipFill>
<a:blip r:embed="rId1"/>
<a:stretch/>
</xdr:blipFill>
<!-- 3. 图片显示属性 -->
<xdr:spPr bwMode="auto">
<a:xfrm>
<a:off x="0" y="0"/>
<a:ext cx="59436000" cy="39623999"/>
</a:xfrm>
<a:prstGeom prst="rect">
<a:avLst/>
</a:prstGeom>
</xdr:spPr>
</xdr:pic>
</etc:cellImage>
</etc:cellImages>
3. 资源映射(_rels/cellimages.xml.rels)
最后,还需要一个清单(cellimages.xml.rels)来记录每张图片实际存放的位置,就像图书馆中的架位表,告诉你具体去哪个书架找这本书。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship
Id="rId1"
Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"
Target="media/image1.png"/>
<Relationship
Id="rId2"
Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"
Target="media/image2.png"/>
</Relationships>
引用链路说明
1. 工作表到图片定义的关联
- 工作表中的 DISPIMG 函数通过图片 ID 引用图片
- 图片 ID 对应 cellimages.xml 中 xdr:cNvPr 的 name 属性
- 这确保了每个单元格能准确找到其对应的图片定义
2. 图片定义到实际资源的关联
- cellimages.xml 中通过 r:embed 属性引用图片资源
- r:embed 的值(如 “rId1″)对应 cellimages.xml.rels 中的 Id
- cellimages.xml.rels 将这个 Id 映射到实际的图片文件路径
3. 资源存储结构
xl/
├── _rels/
│ └── cellimages.xml.rels
├── media/
│ ├── image1.png
│ └── image2.png
└── worksheets/
└── sheet1.xml
└── cellimages.xml
为什么要这样设计?
这种设计的巧妙之处在于:
- 模块化:每个部分职责明确,就像图书馆中的索引系统、档案系统和实际书架是分开管理的。这样便于维护和更新。
- 标准化:采用通用的 OOXML 标准,就像使用通用的图书分类法,确保其他软件也能读懂这些信息。
- 灵活性:图片可以方便地随单元格移动,就像书籍可以轻松地在书架间调整位置,而索引系统会自动更新。
- 高效性:通过 ID 和引用关系,系统可以快速定位到需要的图片,就像图书馆的编码系统让查找书籍变得简单高效。
这种设计让整个功能既实用又可靠,就像一个运作良好的图书管理系统,每个部分都各司其职,又紧密配合。
前端渲染实现
在前端实现中,需要特别处理 DISPIMG 公式的渲染逻辑:
- 公式识别
- 在非编辑模式下,首先识别单元格内容是否为 DISPIMG 公式
- 解析公式参数,获取图片 ID 和显示模式
- 图片渲染
示例代码:
function renderCellImage(ctx, cell, image) {
// 保存当前画布状态
ctx.save();
// 创建裁剪路径(限制在单元格范围内)
ctx.beginPath();
ctx.rect(cell.x, cell.y, cell.width, cell.height);
ctx.clip();
// 绘制图片
ctx.drawImage(image, cell.x, cell.y, cell.width, cell.height);
// 恢复画布状态
ctx.restore();
}
结论
WPS 的单元格图片功能通过巧妙的文件组织和引用机制,实现了图片与单元格的绑定。这种实现方式不仅保持了与标准 Office Open XML 的兼容性,还提供了灵活的图片管理和显示控制能力。理解这种实现机制对于开发类似功能或进行文件格式兼容都有重要的参考价值。