You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 11:37:25