
phpspreadsheet 在读取并保存含图形、图片的 excel 文件时,常因不支持部分原生 excel 对象而导致图片丢失,尤其在非活动工作表中;本文详解原因及规避方法。
PHPSpreadsheet 是一个功能强大的纯 PHP Excel 处理库,但需明确其设计定位:它并非 Excel 的完整镜像引擎,而是以可维护性与跨平台兼容性为优先的“逻辑表格处理器”。因此,对 Shape(如文本框、自选图形)、Chart(图表)以及嵌入式 Drawing(图片)等富媒体对象的支持存在天然限制——尤其是当这些对象位于非首张工作表(如问题中的 sheet2)或采用复杂布局(如浮动定位、组合对象、链接图片)时,PHPSpreadsheet 在加载(Reader)阶段可能未完全解析其二进制结构,而在写入(Writer)阶段亦无法重建原始 OLE 或 DrawingML 关系链,最终导致保存后图片“消失”。
✅ 关键事实澄清:
- PHPSpreadsheet 不会修改原始文件,而是构建内存中的新工作簿模型;所有图形/图片若未被显式载入模型(即未被 Reader 解析为 \PhpOffice\PhpSpreadsheet\Worksheet\Drawing 实例),则不会出现在输出文件中;
- setOffice2003Compatibility(true) 仅影响公式兼容性与部分 XML 命名空间,并不增强图形支持;
- setPreCalculateFormulas(false) 仅跳过公式预计算,与绘图对象无关。
? 可行解决方案:
-
优先使用 Xlsx Reader/Writer(已默认启用):确保未误用 Xls(Excel 97–2003 二进制格式),因其图形支持更弱。当前代码中 new \PhpOffice\PhpSpreadsheet\Reader\Xlsx() 正确。
立即学习“PHP免费学习笔记(深入)”;
显式检查并保留图片(推荐):
PHPSpreadsheet 支持读取和写入基础图片(.png, .jpg, .gif),但要求图片必须作为 Drawing 对象绑定到单元格(非自由浮动)。可通过以下方式验证并补救:
// 检查 sheet2 中是否存在图片
$sheet2 = $spreadsheet->getSheetByName('Sheet2');
if ($sheet2) {
$drawings = $sheet2->getDrawingCollection();
echo "Sheet2 contains " . $drawings->count() . " drawing(s).\n";
foreach ($drawings as $drawing) {
echo "- " . $drawing->getName() . " (" . $drawing->getPath() . ")\n";
}
}⚠️ 若输出为 0,说明 Reader 未能识别该图片(常见于自由浮动图片、嵌入式 OLE 对象或加密/损坏关系),此时 PHPSpreadsheet 无从保留。
- 替代策略:避免依赖 PHPSpreadsheet 处理图形
? 总结:PHPSpreadsheet 的图片丢失本质是格式支持边界问题,而非配置错误。开发者应理性评估需求——若报表强依赖复杂图形/图表,建议转向 PHPOffice/PHPExcel(已停止维护,不推荐)、Box/Spout(仅支持纯数据)或商业方案(如 Aspose.Cells);若仅需简单单元格内图片,务必确保原始 Excel 中图片已正确插入(右键 → “大小和属性” → “属性” → 选择“大小和位置随单元格而变”),并升级至最新版 PHPSpreadsheet(≥v2.0),以获得持续优化的 Drawing 解析能力。











