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

如何用JavaScript将PDF多页合并为单页长文档

用JavaScript将多页不同尺寸PDF合并为单页长文档的可行方案

结合PDF.js、Canvas和pdf-lib可以解决你的问题——核心思路是先把所有PDF页面渲染为Canvas,拼接成一个大Canvas,再转成单页PDF。以下是具体实现:

1. 渲染所有PDF页面到Canvas

使用PDF.js加载每个PDF的所有页面,按原始尺寸渲染为独立Canvas,同时计算总高度和最大宽度,用于创建最终的拼接Canvas。

async function renderAllPagesToCanvas(pdfUrls) {
  const pageCanvases = [];
  let totalHeight = 0;

  for (const url of pdfUrls) {
    const pdfDoc = await pdfjsLib.getDocument(url).promise;
    for (let pageNum = 1; pageNum <= pdfDoc.numPages; pageNum++) {
      const page = await pdfDoc.getPage(pageNum);
      const viewport = page.getViewport({ scale: 1 }); // 保留原始分辨率

      const canvas = document.createElement('canvas');
      canvas.width = viewport.width;
      canvas.height = viewport.height;
      const ctx = canvas.getContext('2d');

      await page.render({ canvasContext: ctx, viewport }).promise;

      pageCanvases.push(canvas);
      totalHeight += viewport.height;
    }
  }

  // 创建总Canvas:宽度取所有页面的最大值,高度为所有页面高度之和
  const maxWidth = Math.max(...pageCanvases.map(c => c.width));
  const totalCanvas = document.createElement('canvas');
  totalCanvas.width = maxWidth;
  totalCanvas.height = totalHeight;
  const totalCtx = totalCanvas.getContext('2d');

  // 逐个绘制页面到总Canvas,水平居中对齐
  let currentY = 0;
  for (const canvas of pageCanvases) {
    const xOffset = (maxWidth - canvas.width) / 2;
    totalCtx.drawImage(canvas, xOffset, currentY);
    currentY += canvas.height;
  }

  return totalCanvas;
}

2. 将拼接后的Canvas转为单页PDF

用pdf-lib创建新PDF文档,把拼接好的Canvas转为PNG(或JPEG)嵌入到PDF页面中,确保尺寸完全匹配。

async function canvasToPdf(canvas) {
  const { PDFDocument } = PDFLib;

  // 创建空PDF文档
  const pdfDoc = await PDFDocument.create();
  // 将Canvas转为PNG字节数据
  const pngBytes = await new Promise((resolve) => {
    canvas.toBlob((blob) => {
      const reader = new FileReader();
      reader.onload = () => resolve(new Uint8Array(reader.result));
      reader.readAsArrayBuffer(blob);
    }, 'image/png');
  });

  // 嵌入PNG到PDF
  const pngImage = await pdfDoc.embedPng(pngBytes);
  // 添加与图片尺寸一致的页面
  const page = pdfDoc.addPage([pngImage.width, pngImage.height]);
  // 绘制图片填满整个页面
  page.drawImage(pngImage, {
    x: 0,
    y: 0,
    width: pngImage.width,
    height: pngImage.height,
  });

  // 导出PDF字节流
  return pdfDoc.save();
}

3. 整合流程并下载结果

把上述两个函数结合,调用后自动下载生成的单页PDF:

async function mergeToSinglePagePdf(pdfUrls) {
  try {
    const totalCanvas = await renderAllPagesToCanvas(pdfUrls);
    const pdfBytes = await canvasToPdf(totalCanvas);

    // 触发下载
    const blob = new Blob([pdfBytes], { type: 'application/pdf' });
    const downloadUrl = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = downloadUrl;
    a.download = 'merged-single-page.pdf';
    a.click();
    URL.revokeObjectURL(downloadUrl);
  } catch (err) {
    console.error('合并失败:', err);
  }
}

// 调用示例:传入PDF文件的URL数组
mergeToSinglePagePdf(['./file1.pdf', './file2.pdf']);

常见问题处理

  • 质量损失:如果需要更高分辨率,渲染PDF时可以提高scale值(比如scale: 2),同时Canvas尺寸也会按比例放大,最终PDF清晰度会提升,但文件体积会增大。
  • 跨域限制:如果PDF来自外部域名,需要目标服务器配置CORS;或者先将PDF文件转为Blob对象后再传入函数。
  • 内存溢出:处理大量页面时,可分批次渲染并拼接,或降低scale值减少内存占用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 12:52:44