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

使用pdfmake给PDF添加多页时生成文件打开空白如何解决

问题根因

你当前的实现逻辑存在本质错误:直接拼接多个独立PDF的二进制流完全不符合PDF文件规范。每个独立PDF都包含完整的文件头、元数据、页面对象、交叉引用表、尾部标识结构,直接追加写入同一文件后,PDF阅读器只能识别首个PDF的头部结构,后续追加的内容无法被解析,就会出现文件有体积但打开全空白的问题。

同时你当前的generatePDF方法也存在小缺陷:doc.end()调用后直接返回文档对象,没有等待流生成完成,可能出现返回的流不完整的问题。

解决方案

提供两种可行方案,可根据你的业务场景选择:

方案1:直接生成单份多页PDF(推荐)

无需引入额外依赖,性能最优,适合所有ID的PDF使用同一份模板、字体的场景,核心逻辑是把多页内容合并到同一个pdfmake配置中一次性生成:

// 1. 收集所有页面内容,统一添加分页符
const allContent = []
for (const [idx, id] of ids.entries()) {
  context.log("Generating content for ID: " + id);
  const singlePageConfig = JSON.parse(templateStr)
  allContent.push(...singlePageConfig.content)
  // 除了最后一页,每页末尾加强制分页符
  if (idx !== ids.length - 1) {
    allContent.push({ text: '', pageBreak: 'after' })
  }
}

// 2. 一次性生成完整的多页PDF
const fullDocConfig = {
  ...JSON.parse(templateStr),
  content: allContent
}
const fullPdfStream = await PdfGenerator.generatePDF(fullDocConfig)
fullPdfStream.pipe(fs.createWriteStream(dir + fileName))

方案2:生成独立PDF后再合并

如果业务要求必须先为每个ID生成独立PDF再合并,可以用pdf-lib库完成合并操作:

import { PDFDocument } from 'pdf-lib'

// 1. 先生成所有独立PDF的Buffer
const pdfBufferList: Buffer[] = []
for (const id of ids) {
  context.log("Generating PDF for ID: " + id);
  const pdfStream = await PdfGenerator.generatePDF(JSON.parse(templateStr))
  // 将流转为Buffer
  const pdfBuffer = await new Promise<Buffer>((resolve, reject) => {
    const chunks: Buffer[] = []
    pdfStream.on('data', chunk => chunks.push(chunk))
    pdfStream.on('end', () => resolve(Buffer.concat(chunks)))
    pdfStream.on('error', reject)
  })
  pdfBufferList.push(pdfBuffer)
}

// 2. 合并所有PDF
const mergedPdf = await PDFDocument.create()
for (const buf of pdfBufferList) {
  const singlePdf = await PDFDocument.load(buf)
  const pages = await mergedPdf.copyPages(singlePdf, singlePdf.getPageIndices())
  pages.forEach(page => mergedPdf.addPage(page))
}

// 3. 写入合并后的文件
const mergedBuffer = await mergedPdf.save()
fs.writeFileSync(dir + fileName, mergedBuffer)

补充优化:修正generatePDF方法

调整返回时机,确保流完全生成后再返回:

public static async generatePDF(docDefinition: any): Promise<any> { 
    const fontDescriptors = {
        Roboto: {
            normal: path.resolve("./fonts/Poppins-Regular.ttf"),
            bold: path.resolve("./fonts/Poppins-Medium.ttf"),
            italics: path.resolve("./fonts/Poppins-Italic.ttf"),
            bolditalics: path.resolve("./fonts/Poppins-MediumItalic.ttf"),
        },
    };
    const printer = new pdfMakePrinter(fontDescriptors);
    const doc = printer.createPdfKitDocument(docDefinition);
    doc.end();

    return new Promise((resolve, reject) => {
        doc.on('end', () => resolve(doc));
        doc.on('error', reject);
    });
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 22:06:04