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

如何在PDF中查找指定字符串的绝对坐标(PHP+TCPDF/FPDI)

如何用TCPDF/FPDI定位PDF中唯一字符串的坐标

核心思路

由于TCPDF/FPDI没有直接提供文本坐标查询API,我们可以通过解析PDF页面的底层指令,拦截包含目标字符串的文本渲染操作,提取其相对于页面左上角的坐标。同时利用你允许替换字符串的条件,辅助验证坐标的准确性。

实现步骤

1. 自定义FPDI子类,拦截PDF指令

创建一个继承自FPDI的子类,重写页面内容解析方法,追踪文本操作和当前坐标:

class FPDICoordTracker extends FPDI {
    private $targetString;
    private $foundCoords = [];
    private $currentX = 0;
    private $currentY = 0;

    public function setTargetString(string $str) {
        $this->targetString = $str;
    }

    public function getFoundCoords() {
        return $this->foundCoords;
    }

    protected function _parsePageContent($content) {
        parent::_parsePageContent($content);

        $tokens = preg_split('/\s+/', trim($content));
        $i = 0;
        $tokenCount = count($tokens);

        while ($i < $tokenCount) {
            $token = $tokens[$i];

            // 追踪文本位置指令:Td(直接设置位置)
            if ($token === 'Td') {
                $x = (float)$tokens[$i-2];
                $y = (float)$tokens[$i-1];
                // 转换PDF默认的左下角原点为左上角原点
                $this->currentX = $x;
                $this->currentY = $this->h - $y;
                $i += 1;
            }
            // 追踪文本矩阵指令:Tm(包含平移的矩阵)
            elseif ($token === 'Tm') {
                $e = (float)$tokens[$i-2];
                $f = (float)$tokens[$i-1];
                $this->currentX = $e;
                $this->currentY = $this->h - $f;
                $i += 1;
            }
            // 处理单个字符串显示指令:Tj
            elseif ($token === 'Tj') {
                $str = trim($tokens[$i-1], '()');
                $str = preg_replace('/\\\(.)/', '$1', $str);
                if ($str === $this->targetString) {
                    $this->foundCoords[] = [
                        'x' => $this->currentX,
                        'y' => $this->currentY,
                        'page' => $this->page
                    ];
                }
                $i += 1;
            }
            // 处理字符串数组显示指令:TJ
            elseif ($token === 'TJ') {
                $j = $i - 1;
                $tjContent = '';
                while ($j >= 0 && $tokens[$j] !== '[') {
                    $part = trim($tokens[$j], '()');
                    if (is_numeric($part)) {
                        $j--;
                        continue;
                    }
                    $tjContent = preg_replace('/\\\(.)/', '$1', $part) . $tjContent;
                    $j--;
                }
                if (strpos($tjContent, $this->targetString) !== false) {
                    $this->foundCoords[] = [
                        'x' => $this->currentX,
                        'y' => $this->currentY,
                        'page' => $this->page
                    ];
                }
                $i += 1;
            } else {
                $i += 1;
            }
        }
    }
}

2. 使用子类加载PDF并获取坐标

// 初始化自定义追踪类
$pdf = new FPDICoordTracker();
$pdf->setTargetString('你的唯一目标字符串');

// 加载目标PDF文件
$pageCount = $pdf->setSourceFile('target.pdf');

// 遍历所有页面解析内容
for ($pageNo = 1; $pageNo <= $pageCount; $pageNo++) {
    $tplIdx = $pdf->importPage($pageNo);
    $pdf->AddPage();
    $pdf->useTemplate($tplIdx);
}

// 获取定位结果
$coords = $pdf->getFoundCoords();

// 输出结果
if (!empty($coords)) {
    foreach ($coords as $coord) {
        echo "页面{$coord['page']},坐标:X={$coord['x']}pt,Y={$coord['y']}pt\n";
    }
} else {
    echo "未找到目标字符串\n";
}

3. 替换字符串验证坐标(可选)

如果需要确认坐标准确性,可以在对应位置绘制替换后的字符串:

// 遍历坐标替换字符串
foreach ($coords as $coord) {
    $pdf->setPage($coord['page']);
    // 用白色矩形覆盖原字符串(可选)
    $pdf->SetFillColor(255, 255, 255);
    $pdf->Rect($coord['x'], $coord['y'] - 5, $pdf->GetStringWidth('替换后的字符串'), 10, 'F');
    // 绘制新字符串
    $pdf->SetFont('helvetica', '', 12);
    $pdf->SetTextColor(255, 0, 0);
    $pdf->Text($coord['x'], $coord['y'], '替换后的字符串');
}

// 输出修改后的PDF
$pdf->Output('modified.pdf', 'F');

注意事项

  • PDF默认以左下角为原点,代码中通过$this->h - $y转换为左上角为原点的Y坐标,$this->h为当前页面高度(单位:pt)。
  • 部分复杂PDF可能使用特殊文本矩阵或字符间距调整,若遇到匹配问题,可微调指令解析逻辑。
  • 确保目标字符串唯一,避免返回多组坐标。

内容的提问来源于stack exchange,提问作者jeremysawesome

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 12:52:46