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

Laravel实现PDF指定位置添加签名图片方案咨询

在Laravel中给现有PDF添加指定位置签名的可行方案

你的代码核心错误在于把现有PDF的二进制内容直接拼接进HTML,domPDF的作用是将HTML渲染为新PDF,而非编辑/合并已有PDF,所以生成的PDF会包含乱码的二进制数据,完全不符合预期。

下面是几种可行的解决方法,优先推荐FPDI方案,因为它专门针对现有PDF的编辑需求:

方案一:使用FPDI(推荐)

FPDI是专注于导入现有PDF并添加内容的库,非常适合给已有PDF插入签名的场景。

步骤1:安装依赖

composer require setasign/fpdi-fpdf

步骤2:实现代码

public function addSignatureToPdf(ContractFile $contractFile)
{
    // 处理远程PDF:先下载到本地临时目录(如果原PDF存储在远程服务器)
    $remotePdfUrl = "https://your-remote-server/contracts/{$contractFile->uid}";
    $tempOriginalPdf = storage_path('app/temp/' . uniqid() . '.pdf');
    file_put_contents($tempOriginalPdf, file_get_contents($remotePdfUrl));

    // 签名图片本地路径
    $signatureImagePath = storage_path('app/contract-files/დავით-ხაჩიძე.png');
    // 修改后PDF的输出路径
    $outputPdfPath = storage_path($this::PDF_DIRECTORY_PATH . 'modified_contract.pdf');

    // 初始化FPDI
    $pdf = new \setasign\Fpdi\Fpdi();
    // 获取原PDF的总页数
    $totalPages = $pdf->setSourceFile($tempOriginalPdf);

    // 遍历每一页,复制原内容并在指定页面插入签名
    for ($pageNum = 1; $pageNum <= $totalPages; $pageNum++) {
        $templateId = $pdf->importPage($pageNum);
        $pageSize = $pdf->getTemplateSize($templateId);

        // 创建与原页面尺寸一致的新页面
        $pdf->AddPage($pageSize['orientation'], [$pageSize['width'], $pageSize['height']]);
        // 导入原页面的全部内容
        $pdf->useTemplate($templateId);

        // 仅在最后一页插入签名(可根据需求修改为指定页码)
        if ($pageNum === $totalPages) {
            // 获取图片原始尺寸
            list($imgW, $imgH) = getimagesize($signatureImagePath);
            // 缩放图片(示例:缩放到100px宽,保持比例)
            $scale = 100 / $imgW;
            $scaledW = 100;
            $scaledH = $imgH * $scale;

            // 计算右下角位置:距离右边缘20mm,距离底部20mm
            $x = $pageSize['width'] - $scaledW - 20;
            $y = $pageSize['height'] - $scaledH - 20;

            // 插入签名图片
            $pdf->Image($signatureImagePath, $x, $y, $scaledW, $scaledH);
        }
    }

    // 保存修改后的PDF
    $pdf->Output($outputPdfPath, 'F');

    // 清理临时文件(如果使用了远程PDF下载)
    unlink($tempOriginalPdf);

    return "已添加签名的PDF保存路径:$outputPdfPath";
}

说明

  • 若原PDF在本地,可直接替换$tempOriginalPdf为本地路径,省略下载步骤
  • 调整$x和$y的值可以改变签名位置,单位为毫米(mm)
  • 支持指定任意页码插入签名,只需修改if ($pageNum === $totalPages)的判断条件

方案二:使用TCPDF

如果项目中已经在使用TCPDF,也可以用它来实现相同功能:

步骤1:安装依赖

composer require tecnickcom/tcpdf

步骤2:简化实现示例

public function addSignatureWithTcpdf(ContractFile $contractFile)
{
    $originalPdfPath = storage_path($this::PDF_DIRECTORY_PATH . "combined_document{$contractFile->getHash()}.pdf");
    $signatureImagePath = storage_path('app/contract-files/დავით-ხაჩიძე.png');
    $outputPdfPath = storage_path($this::PDF_DIRECTORY_PATH . 'modified_contract_tcpdf.pdf');

    $pdf = new \TCPDF();
    $pageCount = $pdf->setSourceFile($originalPdfPath);

    for ($pageNum = 1; $pageNum <= $pageCount; $pageNum++) {
        $tplId = $pdf->importPage($pageNum);
        $size = $pdf->getTemplateSize($tplId);
        $pdf->AddPage($size['orientation'], [$size['width'], $size['height']]);
        $pdf->useTemplate($tplId);

        if ($pageNum === $pageCount) {
            list($imgW, $imgH) = getimagesize($signatureImagePath);
            $scaledW = 100;
            $scaledH = $imgH * ($scaledW / $imgW);
            $x = $size['width'] - $scaledW - 20;
            $y = $size['height'] - $scaledH - 20;
            $pdf->Image($signatureImagePath, $x, $y, $scaledW, $scaledH);
        }
    }

    $pdf->Output($outputPdfPath, 'F');
    return "TCPDF处理后的PDF路径:$outputPdfPath";
}

方案三:使用laravel-snappy的间接方式

如果坚持使用laravel-snappy,可以通过两步实现:

  1. 创建一个HTML视图,精准定位签名位置,用snappy生成仅包含签名的PDF
  2. 使用PDF合并工具(如pdftk或PHP库smalot/pdfparser)将签名PDF叠加到原PDF的指定页面

这种方式步骤较多,不如FPDI直接高效,仅推荐在特定场景下使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 08:36:00