Laravel 图片转 PDF:上传成功后,怎样拿到转换结果?

AI摘要
这是一篇关于在 Laravel 12 中集成 ComPDF 图片转 PDF 接口的技术分享。文章强调上传成功与转换完成是两件事,主张先用单张无个人信息的 PNG 走通请求、结果检查、下载与重新打开全流程,再扩展多图与队列。内容涵盖 Artisan 命令示例、API key 配置、返回结构解析、版式与清晰度验收要点,以及上传与转换状态分离、结果及时落盘、多文件合并与转换分开三条工程边界。属于知识分享。

Laravel图片转PDF:从请求检查到结果下载

做凭证或扫描件附件功能时,“图片上传成功”和“PDF 已经可以下载”是两件事。图片保存在 Laravel 的磁盘里,只说明输入已经准备好;转换接口还可能拒绝文件、返回失败,或完成任务后给出一个需要及时下载的地址。

先让一张 PNG 走完请求、检查结果、下载和重新打开,再考虑多图合并和队列。这样遇到问题时,能分清是上传、转换还是文件保存出了错。

先确认要的是什么文件

图片转 PDF 适合把已有图片交付为 PDF。它不等于 OCR,不能据此承诺图片里的编号变成可搜索、可复制的文字。多张图片一起提交,也不能仅凭“支持多文件”就认定会自动合成一个有序的 PDF。

第一轮准备一张没有个人信息的 PNG:四个角有明显标记,中间有文字和数字。它能帮助你发现裁切、旋转和清晰度变化。先保留原图,不要在上传时为了统一尺寸而拉伸。

如果业务明确要求统一 A4、固定边距或一图一页,先把这些列为验收条件。本例的图片转换接口没有列出这些版式参数,不能自行加上 pageSize、pageMode 之类字段。需要固定模板时,应另选支持对应版式控制的生成方案。

用一条 Artisan 命令验证接口

以下代码按 Laravel 12 的 HTTP Client 写法和 ComPDF 图片转 PDF 接口组织。本文已用一张无个人信息的 PNG 核对接口,并在 Laravel 项目中运行下方命令,成功取得下载地址和 PDF 文件。这只验证单张输入的调用链,自己的图片仍应按后文检查版式和清晰度。

先在 .env 中设置控制台提供的 API key,不要提交到版本库:

COMPDF_API_KEY=替换为自己的API_key

在 config/services.php 的返回数组中增加:

'compdf' => [
    'key' => env('COMPDF_API_KEY'),
],

将下面的命令加入 routes/console.php。如果文件里已有 Artisan 或 Http 导入,保留一份即可。路径参数使用服务器上可读取的 PNG 文件;它不是浏览器里的图片网址。

use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Http;

Artisan::command('pdf:from-png {path}', function () {
    $path = realpath($this->argument('path'));
    $key = config('services.compdf.key');

    if (!$key || !$path || !is_readable($path)) {
        $this->error('请检查 API key 和本地文件路径。');
        return 1;
    }

    $image = @getimagesize($path);
    if (!$image || $image[2] !== IMAGETYPE_PNG) {
        $this->error('本例只接收可识别的 PNG 图片。');
        return 1;
    }

    $stream = fopen($path, 'rb');
    try {
        $response = Http::withHeaders(['x-api-key' => $key])
            ->acceptJson()
            ->connectTimeout(10)
            ->timeout(120)
            ->attach('file', $stream, basename($path))
            ->post(
                'https://api-server.compdf.com/server/v2/process/img/pdf',
                ['language' => 2]
            );
    } finally {
        if (is_resource($stream)) {
            fclose($stream);
        }
    }

    $response->throw();
    $body = $response->json();
    if ((string) data_get($body, 'code') !== '200') {
        $this->error('接口未返回成功状态,请检查返回信息和账号额度。');
        return 1;
    }

    // 分别读取任务包、文件数组或单文件结果。
    $data = data_get($body, 'data', []);
    $files = data_get($data, 'fileInfoDTOList');
    $file = is_array($files)
        ? ($files[0] ?? [])
        : (is_array($data) && array_is_list($data) ? ($data[0] ?? []) : $data);
    $url = data_get($file, 'downloadUrl');
    $taskState = data_get($data, 'taskStatus');
    $fileState = data_get($file, 'status');
    $failed = (int) data_get($data, 'taskFailNum', 0) > 0
        || ($fileState && $fileState !== 'success')
        || (bool) data_get($file, 'failureCode');

    if ($failed || ($taskState && $taskState !== 'TaskFinish') || !$url) {
        $this->error('尚未取得成功结果,请按 taskId 检查任务及失败原因。');
        $this->line('taskId: '.data_get($file, 'taskId', data_get($data, 'taskId', '未返回')));
        return 1;
    }

    $this->line('taskId: '.data_get($file, 'taskId', data_get($data, 'taskId', '未返回')));
    $this->line('downloadUrl: '.$url);
    return 0;
});

更新配置后运行:

php artisan config:clear
php artisan pdf:from-png /绝对路径/check.png

HTTP 非成功状态会抛出异常;连接异常和超时也会使命令失败。返回业务错误、任务未结束或缺少下载地址时,本例返回退出码 1。不要把“请求发出去了”当成转换完成。 如果服务超时,不要立即无限重试;先根据已取得的任务 ID 核查,避免重复创建任务。

代码分别处理任务包、文件数组和单文件结果,但你的账号实际响应仍需核对。若返回结构不同,先查看任务 ID、状态和错误字段,再调整解析,不能仅搜索任意一个 downloadUrl 就认定成功。

HTTP响应、任务结果与下载文件应分别检查

检查顺序示意:分别确认请求、任务与最终文件,不能只看一个成功状态。

下载之后,再看图片有没有被正确保留

先在浏览器打开命令输出的地址并下载 PDF。图片转 PDF 文档标明结果地址有效期为 24 小时,它适合取回产物,不适合直接作为业务系统的永久附件地址。

关闭文件后重新打开,与原 PNG 对照:

  • 四个角是否都在,有没有内容被裁掉;
  • 文字、细线和数字在正常阅读比例下是否清楚;
  • 方向是否符合使用要求;不能用拉伸来修正横竖问题;
  • 页数、页尺寸和文件大小是否符合自己的交付条件;
  • 文件能否正常下载、打开,而不是扩展名叫 .pdf 的错误页面。

一张图通过后,再分别用横图、竖图和较大图片做同样检查。输出满足需求,才值得接着做批量;如果不满足固定纸张或文字检索要求,应该换处理路径,而不是继续给这个接口叠加未说明的参数。

接回上传和队列时,保留这三条边界

上传与转换分开记状态。 Laravel 上传时先校验格式、大小及实际像素,再保存到私有存储。队列拿服务器文件路径执行转换;不要把前端传入的任意路径直接交给上述命令。示例只做 PNG 识别,生产上传仍需按应用资源限制设置文件和像素上限。

转换结果及时保存。 应用核对任务与输出后,把 PDF 下载到自己的存储,保存来源附件 ID、版本、任务 ID 和输出路径。下载与文件校验完成后再标记可下载,并由应用做权限检查。批量重试需要识别同一输入版本,防止同一附件产生多份无主文件。

多文件处理与合并分开。 一张图片对应一个结果时,按附件 ID 记录结果,不靠任务完成先后排序。如果确实要把多张凭证装订成一份 PDF,先定义材料顺序、检查每个转换结果,再按 PDF 合并接口的输入约定组织合并;转换接口本身不能替你决定业务页序。

先确认单张 PNG 能得到合格的 PDF,再接自己的附件、存储和权限,是这条链路里最有用的检查顺序。ComPDF 完成图片到 PDF 的转换,Laravel 负责让这个结果成为可追踪、可授权下载的业务附件;两部分分别验收,后续排障才有明确的位置。

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
未填写
文章
42
粉丝
2
喜欢
7
收藏
9
排名:1391
访问:2800
私信
所有博文
社区赞助商