基于 pdf-lib 的图片转PDF工具核心JS实现

简介: 这是一款纯前端图片转PDF工具:基于Vue构建交互界面,利用开源库pdf-lib在浏览器端完成PDF生成。支持图片上传、排序、旋转、自定义页面尺寸与布局(contain/cover/center),全程无需后端,所有处理均在本地完成,安全高效。

这篇只讲功能层 JavaScript 实现。这个工具是我用 Vue 组织页面交互,再配合 pdf-lib 在浏览器端完成 PDF 生成。pdf-lib 是公开可用的通用开源库(MIT 许可),可直接用于浏览器和 Node.js。核心流程是:

上传图片 -> 读取并建模 -> 调整顺序/旋转 -> 计算页面与布局 -> 写入 PDF -> 下载

在线工具网址:https://see-tool.com/image-to-pdf
工具截图:
工具截图.png

0)先说下 pdf-lib 在这个工具里的角色

pdf-lib 在这里主要负责三件事:创建 PDF 文档、把图片字节嵌入文档、按给定坐标绘制到页面。

它的调用模型很直接:

create/load -> addPage/embed -> drawImage -> save

对图片转 PDF 这类场景,它有几个很实用的点:

  • API 稳定,浏览器端可直接运行,不依赖后端转换
  • 页面坐标和尺寸控制细,适合做“边距、缩放、居中、铺满”这类排版
  • 同一套逻辑可扩展到“合并现有 PDF、写文本、填表单”等后续功能

这个工具里最核心的一步是 embedJpg + drawImage:前者把二进制图片数据放进 PDF,后者决定图片在页面中的位置和显示尺寸。只要前面把页面尺寸和布局参数算对,最终导出的版式就会稳定可控。

1)状态模型:围绕“图片队列 + 转换配置”组织

工具初始化后维护一个状态对象,核心字段如下:

  • images:当前待转换图片队列
  • settings:页面尺寸、方向、布局、边距、文件名
  • isConverting:是否正在生成,防止重复点击

每张图片对象都会保存:namesizeformatpreview(dataURL)widthheightrotation。这样后续排序、旋转、预览和生成 PDF 都可以直接复用同一份数据。

2)文件接入:先过滤,再读取 DataURL 和尺寸

上传与拖拽最后都进入同一入口,先只保留图片类型,再做数量上限控制。每个文件会经过两步:

  1. FileReader.readAsDataURL 读成 DataURL
  2. Image 对象加载,拿到 naturalWidth/naturalHeight

核心读取函数:

function readFileAsDataUrl(file) {
   
  return new Promise(function (resolve, reject) {
   
    var reader = new FileReader();
    reader.onload = function (event) {
   
      resolve(
        String(event.target && event.target.result ? event.target.result : ""),
      );
    };
    reader.onerror = function () {
   
      reject(new Error("file_read_failed"));
    };
    reader.readAsDataURL(file);
  });
}

读取成功后把图片对象追加进队列,页面统计和预览区会立即重渲染。

3)页面尺寸计算:统一转换到 PDF 点单位

PDF 里统一使用 point(pt),因此先做单位换算:

  • MM_TO_PT = 72 / 25.4
  • PX_TO_PT = 72 / 96

固定纸张(A4/A3/Letter/Legal)先由毫米转 pt;如果用户选“原始尺寸”,则按图片像素转 pt。方向为 auto 时,会根据图片宽高自动判定横版或竖版。

function getPageSizePt(pageSize, orientation, imageWidth, imageHeight) {
   
  var widthPt;
  var heightPt;

  if (pageSize === "original") {
   
    widthPt = imageWidth * PX_TO_PT;
    heightPt = imageHeight * PX_TO_PT;
  } else {
   
    var pageSizeValue = PAGE_SIZES_MM[pageSize] || PAGE_SIZES_MM.a4;
    widthPt = pageSizeValue.width * MM_TO_PT;
    heightPt = pageSizeValue.height * MM_TO_PT;
  }

  // 省略方向交换逻辑
  return {
   
    widthPt: widthPt,
    heightPt: heightPt,
    orientation: finalOrientation,
  };
}

4)布局算法:contain / cover / center

每页先算内容区:

contentWidth = pageWidth - margin * 2

contentHeight = pageHeight - margin * 2

然后按布局模式计算绘制矩形:

  • contain:完整显示图片,按最小缩放比适配
  • cover:铺满内容区,按最大缩放比适配
  • center:不缩放,居中绘制

当边距过大导致内容区宽高小于等于 0 时,直接抛错,转换流程会给出明确提示。

5)旋转处理:先画到 Canvas,再统一转 JPEG

为了让 pdf-lib 写入稳定,工具会先把当前图片(含旋转角度)绘制到 canvas,再导出 JPEG 字节。角度支持 0/90/180/270。

function drawImageToJpeg(image, rotation) {
   
  var angle = Number(rotation || 0);
  var swapSide = angle === 90 || angle === 270;
  var canvas = document.createElement("canvas");

  canvas.width = swapSide ? image.naturalHeight : image.naturalWidth;
  canvas.height = swapSide ? image.naturalWidth : image.naturalHeight;

  var context = canvas.getContext("2d", {
    alpha: false });
  context.fillStyle = "#ffffff";
  context.fillRect(0, 0, canvas.width, canvas.height);
  context.translate(canvas.width / 2, canvas.height / 2);
  context.rotate((angle * Math.PI) / 180);
  context.drawImage(image, -image.naturalWidth / 2, -image.naturalHeight / 2);

  return parseDataUrl(canvas.toDataURL("image/jpeg", 0.92));
}

这里先铺白底,可以避免透明图在 PDF 中出现黑底。

6)PDF 生成:逐页 addPage + embedJpg + drawImage

转换时按图片队列顺序循环处理,每张图先算页面尺寸和布局,再写入 PDF:

async function buildPdfBlobWithPdfLib(pages, PDFDocument) {
   
  var pdfDocument = await PDFDocument.create();

  for (var i = 0; i < pages.length; i += 1) {
   
    var item = pages[i];
    var page = pdfDocument.addPage([item.pageWidthPt, item.pageHeightPt]);
    var jpg = await pdfDocument.embedJpg(item.imageBytes);
    page.drawImage(jpg, {
   
      x: item.xPt,
      y: item.yPt,
      width: item.drawWidthPt,
      height: item.drawHeightPt,
    });
  }

  var pdfBytes = await pdfDocument.save();
  return new Blob([pdfBytes], {
    type: "application/pdf" });
}

最终通过对象 URL 触发浏览器下载,文件名会先做非法字符清洗。

7)交互动作如何影响最终 PDF

工具里“上移/下移/拖拽排序/旋转/删除”都直接改 images 队列,因此最终 PDF 页序与图片列表始终一致。

  • 排序:交换数组元素或拖拽后 splice
  • 旋转:rotation = (rotation + 90) % 360
  • 删除:按 id 过滤

由于生成时是按队列顺序遍历,交互结果会无缝反映到导出文件。

8)转换过程控制:状态锁 + 分阶段提示

点击“转换”后会先进入 isConverting = true

  • 禁用上传、配置项和操作按钮
  • 显示“正在生成第 X / N 页”
  • 完成后恢复可操作状态

错误按场景给出明确反馈,比如无图片、文件名为空、边距过大、生成失败。整条链路是纯前端闭环:从读取、排版到导出,都在浏览器端完成。

目录
相关文章
|
8天前
|
人工智能 安全 Linux
【OpenClaw保姆级图文教程】阿里云/本地部署集成模型Ollama/Qwen3.5/百炼 API 步骤流程及避坑指南
2026年,AI代理工具的部署逻辑已从“单一云端依赖”转向“云端+本地双轨模式”。OpenClaw(曾用名Clawdbot)作为开源AI代理框架,既支持对接阿里云百炼等云端免费API,也能通过Ollama部署本地大模型,完美解决两类核心需求:一是担心云端API泄露核心数据的隐私安全诉求;二是频繁调用导致token消耗过高的成本控制需求。
5223 9
|
16天前
|
人工智能 JavaScript Ubuntu
5分钟上手龙虾AI!OpenClaw部署(阿里云+本地)+ 免费多模型配置保姆级教程(MiniMax、Claude、阿里云百炼)
OpenClaw(昵称“龙虾AI”)作为2026年热门的开源个人AI助手,由PSPDFKit创始人Peter Steinberger开发,核心优势在于“真正执行任务”——不仅能聊天互动,还能自动处理邮件、管理日程、订机票、写代码等,且所有数据本地处理,隐私完全可控。它支持接入MiniMax、Claude、GPT等多类大模型,兼容微信、Telegram、飞书等主流聊天工具,搭配100+可扩展技能,成为兼顾实用性与隐私性的AI工具首选。
21237 115
|
12天前
|
人工智能 安全 前端开发
Team 版 OpenClaw:HiClaw 开源,5 分钟完成本地安装
HiClaw 基于 OpenClaw、Higress AI Gateway、Element IM 客户端+Tuwunel IM 服务器(均基于 Matrix 实时通信协议)、MinIO 共享文件系统打造。
8098 10

热门文章

最新文章