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

