PHP无法直接解析RTF图片,需先定位{\pict...}块,再依\jpegblip等标识提取hex或二进制数据,用hex2bin()解码并验证文件头后保存;也可调用unrtf或LibreOffice等外部工具转换规避复杂解析。

PHP 本身不直接支持解析 RTF 文件中的图片,因为 RTF 是一种富文本格式,图片以二进制(如 \pict 块)、十六进制或 Base64 编码嵌入在文本流中,并非标准图像文件。要提取其中的图片,核心思路是:**先解析 RTF 结构定位 pict 块,再识别图片类型(WMF/EMF/JPEG/PNG 等),最后解码并保存为真实图像文件**。
识别并提取 RTF 中的 \pict 图片块
RTF 图片通常包裹在 {\pict ...} 控制字内,内部可能含 \pngblip(PNG)、\jpegblip(JPEG)、\wmetafile8(WMF)等标识。需用正则匹配完整 pict 块:
$pattern = '/\{\\\\pict(.*?)}(?=\\\\pict|})/s';
preg_match_all($pattern, $rtfContent, $matches);
foreach ($matches[0] as $pictBlock) {
// 进一步分析 $pictBlock 内容
}
注意:RTF 转义复杂(双反斜杠表示单反斜杠),建议先用 str_replace('\\\\', '\\', $rtf) 预处理,或使用已验证的 RTF 解析库(如 php-rtf)降低误匹配风险。
判断图片格式并解码二进制数据
从 \pict 块中提取原始数据前,先检查子控制字确定格式:
立即学习“PHP免费学习笔记(深入)”;
-
JPEG:含
\jpegblip→ 数据紧跟其后,通常是十六进制字符串(如'01a2b3...'),用hex2bin()解码 -
PNG:含
\pngblip→ 同样为 hex 数据,hex2bin()即可 -
WMF/EMF:含
\wmetafile8或\emfblip→ 数据为原始二进制,需跳过头部控制字后截取
示例(简化 JPEG 提取):
if (strpos($pictBlock, '\jpegblip') !== false) {
$hexData = preg_replace('/[^a-fA-F0-9]/', '', $pictBlock);
$binary = hex2bin($hexData);
if ($binary && substr($binary, 0, 2) === "\xFF\xD8") {
file_put_contents('output.jpg', $binary);
}
}
绕过手动解析:用外部工具辅助转换
若项目允许调用系统命令,更稳定的方式是借助成熟工具预处理:
-
unrtf(Linux):
unrtf --no-filter --html input.rtf > /dev/null可触发图片导出到临时目录 -
LibreOffice headless:
libreoffice --headless --convert-to html input.rtf生成含图片引用的 HTML + 图片文件夹 - 再用 PHP 读取生成的图片路径或 HTML 中的
此法规避 RTF 协议细节,适合生产环境对稳定性要求高的场景。
注意事项与常见坑
RTF 图片提取易失败的几个关键点:
- RTF 版本差异大(v1.0 到 v1.9.1),
\pict嵌套层级和转义规则不统一 - 部分编辑器(如 Word)导出的 RTF 会压缩图片数据或添加加密标记,需检查是否含
\picprop或\dibitmap - 十六进制数据可能跨多行、含空格/换行,提取前务必清理非十六进制字符
- 无扩展名的图片需靠文件头(magic bytes)识别格式,不能仅依赖控制字
不复杂但容易忽略:始终用 file_put_contents() 保存二进制数据,避免 echo/print 导致乱码;保存前用 getimagesizefromstring() 验证数据有效性。











