如何用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
相关产品推荐
相关产品推荐

