在PHP中解析PPTX获取图片X/Y坐标(共享服务器环境)
解决方案
要获取PPTX中图片的X、Y坐标,需读取对应幻灯片的XML内容——图片的位置信息存储在幻灯片(ppt/slides/slideN.xml)的<a:xfrm>节点下的<a:off>属性中。以下是修改后的代码,集成了坐标提取逻辑,仅依赖PHP内置模块,适配共享服务器环境:
function pptx_extract_images_with_coords() { // 获取POST数据 $data = filter_input_array(INPUT_POST); $attachment_id = $data['attachment_id']; // 获取附件文件及名称 $input_file = get_attached_file($attachment_id); $input_file_name = pathinfo($input_file)["filename"]; // 初始化ZipArchive $package = new \ZipArchive(); if (!$package->open($input_file)) { throw new RuntimeException('无法打开PPTX文件,可能是文件损坏或格式错误'); } // 读取根关系文件 $relationsXml = $package->getFromName('_rels/.rels'); if ($relationsXml === false) { throw new RuntimeException('无效的PPTX归档文件,根关系文件缺失'); } $relations = simplexml_load_string($relationsXml); // 解析绝对路径的辅助函数 function absoluteZipPath($path) { $path = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $path); $parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen'); $absolutes = []; foreach ($parts as $part) { if ($part === '.') continue; if ($part === '..') { array_pop($absolutes); } else { $absolutes[] = $part; } } return implode('/', $absolutes); } $slidesData = []; // 遍历根关系,找到文档主入口 foreach ($relations->Relationship as $rel) { if ($rel["Type"] !== 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument') { continue; } // 获取幻灯片关系文件路径 $docRelPath = absoluteZipPath(dirname($rel["Target"]) . "/_rels/" . basename($rel["Target"]) . ".rels"); $slideRelationsXml = $package->getFromName($docRelPath); if (!$slideRelationsXml) continue; $slideRelations = simplexml_load_string($slideRelationsXml); // 遍历所有幻灯片关系 foreach ($slideRelations->Relationship as $slideRel) { if ($slideRel["Type"] !== 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide') { continue; } // 获取幻灯片编号 $slideFilename = pathinfo($slideRel["Target"])["filename"]; $slideNo = preg_replace('/[^0-9]/', '', $slideFilename); $slideKey = 'page_' . ($slideNo - 1); // 读取幻灯片XML内容 $slideXmlPath = absoluteZipPath(dirname($rel["Target"]) . "/" . $slideRel["Target"]); $slideXml = $package->getFromName($slideXmlPath); if (!$slideXml) continue; $slideDoc = simplexml_load_string($slideXml); // 注册命名空间(PPTX XML使用多命名空间,必须注册才能用XPath查询) $slideDoc->registerXPathNamespace('p', 'http://schemas.openxmlformats.org/presentationml/2006/main'); $slideDoc->registerXPathNamespace('a', 'http://schemas.openxmlformats.org/drawingml/2006/main'); $slideDoc->registerXPathNamespace('r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); // 获取幻灯片的关系文件,建立图片ID与文件路径的映射 $slideRelPath = absoluteZipPath(dirname($rel["Target"]) . "/" . dirname($slideRel["Target"]) . "/_rels/" . basename($slideRel["Target"]) . ".rels"); $slideRelXml = $package->getFromName($slideRelPath); if (!$slideRelXml) continue; $slideRelDoc = simplexml_load_string($slideRelXml); $imageIdMap = []; foreach ($slideRelDoc->Relationship as $imgRel) { if ($imgRel["Type"] === 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image') { $imageIdMap[(string)$imgRel["Id"]] = (string)$imgRel["Target"]; } } // 遍历幻灯片中的所有图片节点 $picNodes = $slideDoc->xpath('//p:pic'); foreach ($picNodes as $pic) { // 获取图片关联ID $blip = $pic->xpath('.//a:blip')[0]; $imgRelId = (string)$blip['r:embed']; if (!isset($imageIdMap[$imgRelId])) continue; // 获取图片文件信息 $imgPath = $imageIdMap[$imgRelId]; $imgFilename = basename($imgPath); $imgExt = strtolower(pathinfo($imgFilename, PATHINFO_EXTENSION)); // 提取图片X、Y坐标(原始单位为EMU,1EMU=1/914400英寸,1cm≈360000EMU) $xfrm = $pic->xpath('.//a:xfrm')[0]; $off = $xfrm->xpath('.//a:off')[0]; $x = (int)$off['x']; $y = (int)$off['y']; // 整理数据 $imageData = [ 'filename' => $imgFilename, 'extension' => $imgExt, 'x_emu' => $x, 'y_emu' => $y, 'x_cm' => round($x / 360000, 2), // 转换为厘米 'y_cm' => round($y / 360000, 2) ]; // 区分动态图与普通图 if ($imgExt === 'gif') { $slidesData[$slideKey]['animated_images'][] = $imageData; } else { $slidesData[$slideKey]['images'][] = $imageData; } } } } $package->close(); return $slidesData; }
关键说明
- 命名空间注册:PPTX的XML使用多个命名空间,必须通过
registerXPathNamespace注册后,才能用XPath准确查询节点 - 坐标单位转换:原始坐标为EMU(英制公制单位),代码中已转换为常用的厘米单位,可根据需求自行调整转换比例
- 图片关联逻辑:通过幻灯片关系文件中的
r:embed属性,将幻灯片内的图片节点与实际图片文件路径关联,确保坐标与对应图片匹配
内容的提问来源于stack exchange,提问作者Ali Hussain
相关产品推荐
相关产品推荐

