Laravel 中使用 FPDI 实现 PDF 骑缝章功能

发布于:2025-07-28 ⋅ 阅读:(17) ⋅ 点赞:(0)

在处理 PDF 文档时,我们经常需要为多页文档添加骑缝章,确保文档的完整性和严肃性。本文将介绍如何在 Laravel 框架中使用 FPDI 扩展库实现这一功能,通过分割印章图片并按页添加的方式,生成规范的骑缝章效果。

一、实现思路

骑缝章的核心原理是将一个完整的印章图片分割成与 PDF 页数相同的份数,然后在每一页的边缘位置添加对应的分割部分,拼接成完整的印章效果。实现步骤如下:
1、使用 FPDI 读取原始 PDF 文档并获取页数
2、将印章图片按 PDF 页数进行均等分割
3、循环处理每一页 PDF,添加对应的分割印章
4、重新生成带骑缝章的 PDF 文档

二、环境准备

首先需要安装 FPDI 相关依赖,通过 Composer 执行以下命令:

composer require setasign/fpdi-fpdf

该扩展库基于 FPDF,提供了 PDF 文档的读取和编辑功能,非常适合处理 PDF 盖章场景。

三、完整实现代码

以下是实现骑缝章功能的核心代码,包含 PDF 处理和图片分割逻辑:

/**
 * 为PDF添加骑缝章
 * @param string $file PDF文件路径
 * @param string $acrossPageSeal 骑缝章图片路径
 * @return string 处理后的文件路径
 */
public function addSealToPDF($file, $acrossPageSeal)
{
    try {
        // 初始化FPDI对象
        $pdf = new Fpdi();
        
        // 去除默认页眉页脚(如横线等)
        $pdf->setPrintHeader(false);
        $pdf->setPrintFooter(false);
        $pdf->setFontSubsetting(false);
        
        // 读取PDF文件并获取总页数
        $page_num = $pdf->setSourceFile(public_path($file));
        
        // 仅对多页PDF添加骑缝章
        if ($page_num > 1 && !empty($acrossPageSeal)) {
            // 分割印章图片为与页数相同的份数
            $to_imgs = self::cuttingImg(public_path($acrossPageSeal), $page_num, 'to');
            
            // 循环处理每一页
            for ($i = 0; $i < $page_num; $i++) {
                // 添加新页面
                $pdf->AddPage();
                
                // 导入当前页模板
                $tplId = $pdf->importPage($i + 1);
                $pdf->useTemplate($tplId);
                
                // 在指定位置添加分割后的印章
                // 参数说明:图片路径、X坐标、Y坐标、宽度、高度、格式
                $pdf->Image($to_imgs[$i], 195, 110, 15, '', 'png');
            }
            
            // 输出并覆盖原文件(F模式表示保存到本地文件)
            $pdf->Output(public_path($file), 'F');
        }
    } catch (\Exception $exception) {
        // 异常处理:如果原文件存在则返回原文件
        if (Storage::exists($file)) {
            return $file;
        }
    }
    
    return $file;
}

/**
 * 分割图片为指定份数
 * @param string $imgPath 原始图片路径
 * @param int $num 分割份数
 * @param string $dir 保存目录
 * @return array 分割后的图片路径数组
 */
private function cuttingImg($imgPath, $num, $dir)
{
    // 确保保存目录存在
    $saveDir = public_path($dir);
    if (!file_exists($saveDir)) {
        mkdir($saveDir, 0755, true);
    }
    
    // 获取图片信息
    list($width, $height, $type) = getimagesize($imgPath);
    $ext = image_type_to_extension($type, false);
    
    // 根据图片类型创建资源
    switch ($type) {
        case IMAGETYPE_PNG:
            $source = imagecreatefrompng($imgPath);
            break;
        case IMAGETYPE_JPEG:
            $source = imagecreatefromjpeg($imgPath);
            break;
        default:
            throw new \Exception("不支持的图片格式");
    }
    
    $result = [];
    // 计算每一份的宽度(横向分割)
    $partWidth = ceil($width / $num);
    
    for ($i = 0; $i < $num; $i++) {
        // 创建新图片资源
        $newImg = imagecreatetruecolor($partWidth, $height);
        
        // 保留PNG透明度
        if ($type == IMAGETYPE_PNG) {
            imagesavealpha($newImg, true);
            $transColor = imagecolorallocatealpha($newImg, 0, 0, 0, 127);
            imagefill($newImg, 0, 0, $transColor);
        }
        
        // 复制图片部分区域
        imagecopy(
            $newImg, 
            $source, 
            0, 0, 
            $i * $partWidth, 0, 
            $partWidth, $height
        );
        
        // 保存分割后的图片
        $savePath = $saveDir . '/' . uniqid() . '.' . $ext;
        switch ($type) {
            case IMAGETYPE_PNG:
                imagepng($newImg, $savePath);
                break;
            case IMAGETYPE_JPEG:
                imagejpeg($newImg, $savePath);
                break;
        }
        
        $result[] = $savePath;
        imagedestroy($newImg);
    }
    
    imagedestroy($source);
    return $result;
}

四、代码解析

1、PDF 处理核心逻辑:

  • 使用 Fpdi 类初始化 PDF 处理对象
  • 通过 setSourceFile 方法读取 PDF 并获取页数
  • 循环处理每一页时,先导入原页面模板,再添加对应分割的印章图片
  • 用 Output 方法以覆盖模式保存处理后的 PDF

2、图片分割关键步骤:

  • 根据 PDF 页数计算每部分印章的宽度
  • 使用 GD 库函数进行图片分割处理
  • 针对 PNG 图片保留透明度,确保盖章效果自然
  • 分割后的图片临时保存,供 PDF 处理使用

3、坐标与尺寸设置:

  • Image 方法中的参数 195, 110, 15 分别代表 X 坐标、Y 坐标和宽度
  • 实际使用中需根据 PDF 尺寸和印章大小调整,建议通过多次测试确定最佳位置

通过以上实现,我们可以在 Laravel 项目中快速为 PDF 文档添加规范的骑缝章,适用于合同、协议等重要文档的电子化处理场景。实际应用中可根据具体业务需求调整参数和逻辑。


网站公告

今日签到

点亮在社区的每一天
去签到