使用bwip-js生成PNG Buffer后,PDFKit报未知图片格式错误
问题解决:bwip-js生成PNG插入PDFkit报"Unknown image format"错误
问题描述
使用bwip-js生成条形码(返回PNG格式Buffer),通过fs.writeFile保存为PNG文件后,用pdfkit插入该图片时提示"Unknown image format",但本地文件管理器可正常打开图片,修改后缀为.PNG也无法解决问题。原代码如下:
const PDFDocument = require("pdfkit"); const bwipjs = require("bwip-js"); const fs = require("fs"); function generateCustomerInvoice(data) { const id = "12345678" bwipjs .toBuffer({ bcid: "code128", text: id, scale: 3, height: 10, includetext: true, textxalign: "center", }) .then((png) => { fs.writeFile("./barcodes/" + id + ".png", png, () => {}); console.log("Barcode Finished"); }) .then(() => { const doc = new PDFDocument({ autoFirstPage: false }); doc.pipe(fs.createWriteStream("./pdfs/customer/" + id + ".pdf")); doc.addPage({ size: "A5", margin: 20 }); doc.lineWidth(1); doc.lineCap("butt").moveTo(20, 20).lineTo(399.53, 20).stroke(); doc.lineCap("butt").moveTo(20, 20).lineTo(20, 575.28).stroke(); doc.lineCap("butt").moveTo(399.53, 20).lineTo(399.53, 575.28).stroke(); doc.lineCap("butt").moveTo(20, 575.28).lineTo(399.53, 575.28).stroke(); doc.fontSize(12).text("Customer Invoice", 40, 40); doc.image("./barcodes/" + id + ".png", 40, 40); doc.end(); }); }
解决方案
方案1:直接使用Buffer插入PDF(推荐)
bwip-js返回的PNG Buffer可直接传给pdfkit的doc.image(),无需写入本地文件,既避免异步问题,又减少IO操作:
const PDFDocument = require("pdfkit"); const bwipjs = require("bwip-js"); const fs = require("fs"); function generateCustomerInvoice(data) { const id = "12345678" bwipjs .toBuffer({ bcid: "code128", text: id, scale: 3, height: 10, includetext: true, textxalign: "center", }) .then((pngBuffer) => { const doc = new PDFDocument({ autoFirstPage: false }); doc.pipe(fs.createWriteStream("./pdfs/customer/" + id + ".pdf")); doc.addPage({ size: "A5", margin: 20 }); // 绘制边框 doc.lineWidth(1); doc.lineCap("butt").moveTo(20, 20).lineTo(399.53, 20).stroke(); doc.lineCap("butt").moveTo(20, 20).lineTo(20, 575.28).stroke(); doc.lineCap("butt").moveTo(399.53, 20).lineTo(399.53, 575.28).stroke(); doc.lineCap("butt").moveTo(20, 575.28).lineTo(399.53, 575.28).stroke(); // 添加文本和条形码 doc.fontSize(12).text("Customer Invoice", 40, 40); // 直接传入Buffer,指定格式为png doc.image(pngBuffer, 40, 60, { format: "png" }); doc.end(); console.log("PDF生成完成"); }) .catch(err => { console.error("生成失败:", err); }); }
方案2:修复异步文件写入的时序问题
如果必须保存本地文件,需要确保文件完全写入后再读取。使用fs.promises.writeFile替代回调版本,保证异步流程顺序:
const PDFDocument = require("pdfkit"); const bwipjs = require("bwip-js"); const fs = require("fs").promises; const fsSync = require("fs"); // 用于创建写入流 function generateCustomerInvoice(data) { const id = "12345678" const barcodePath = "./barcodes/" + id + ".png"; bwipjs .toBuffer({ bcid: "code128", text: id, scale: 3, height: 10, includetext: true, textxalign: "center", }) .then((png) => { return fs.writeFile(barcodePath, png); // 返回Promise确保写入完成 }) .then(() => { console.log("Barcode Finished"); const doc = new PDFDocument({ autoFirstPage: false }); doc.pipe(fsSync.createWriteStream("./pdfs/customer/" + id + ".pdf")); doc.addPage({ size: "A5", margin: 20 }); // 绘制边框 doc.lineWidth(1); doc.lineCap("butt").moveTo(20, 20).lineTo(399.53, 20).stroke(); doc.lineCap("butt").moveTo(20, 20).lineTo(20, 575.28).stroke(); doc.lineCap("butt").moveTo(399.53, 20).lineTo(399.53, 575.28).stroke(); doc.lineCap("butt").moveTo(20, 575.28).lineTo(399.53, 575.28).stroke(); // 添加文本和条形码 doc.fontSize(12).text("Customer Invoice", 40, 40); doc.image(barcodePath, 40, 60); doc.end(); }) .catch(err => { console.error("生成失败:", err); }); }
关键说明
- 方案1中,直接传入Buffer时可以显式指定
{ format: "png" },让pdfkit明确识别格式,避免自动检测出错。 - 原代码的核心问题是异步时序错误:
fs.writeFile是异步操作,第二个then在文件还没写完就执行,导致读取到不完整的文件内容,触发格式识别错误。
内容的提问来源于stack exchange,提问作者Josh Bunzel
相关产品推荐
相关产品推荐

