订单号、运单号、资产编号这类信息,一旦由人工录入就难免出错。把它们印成条形码贴在单据上,扫码枪一次读取即可完成录入,出错率也随之下降。要在 Web 应用里把条形码落到 PDF 上,过去通常先在服务端生成条码图片,再拼回文档,文件往返一趟,链路并不短。
Spire.PDF for JavaScript 基于 WebAssembly 在浏览器端直接创建、修改和保存 PDF 文档,条形码由 PdfCode128BBarcode、PdfCode39Barcode 这类一维条码对象直接绘制到页面上,借助虚拟文件系统(VFS)读写文件,不需要把文档上传到服务器。
本文介绍两个核心功能点:
有关安装和项目配置,请参考 React 项目中集成 Spire.PDF for JavaScript。以下示例默认已安装 Spire.PDF 并完成 WebAssembly 模块初始化。
支持的条形码类型
十个一维条码类都从 PdfBarcode 派生,字符集与编码密度各不相同,选型可对照下表:
| 类 | 条码符号 | 支持的字符 |
|---|---|---|
PdfCodabarBarcode |
Codabar | 数字与 - $ : / . + |
PdfCode11Barcode |
Code 11 | 数字与 - |
PdfCode32Barcode |
Code 32 | 数字,常见于药品编码 |
PdfCode39Barcode |
Code 39 | 数字、大写字母、空格与 - . $ / + % |
PdfCode39ExtendedBarcode |
Code 39 Extended | 完整 ASCII,由多字符组合表示 |
PdfCode93Barcode |
Code 93 | 与 Code 39 相同的字符集,密度更高 |
PdfCode93ExtendedBarcode |
Code 93 Extended | 完整 ASCII |
PdfCode128ABarcode |
Code 128A | 数字、大写字母、符号与控制字符 |
PdfCode128BBarcode |
Code 128B | 数字、大小写字母与符号 |
PdfCode128CBarcode |
Code 128C | 成对出现的数字,密度最高 |
function App() {
const drawBarcodeTypes = async () => {
// 获取 Spire.PDF WASM 模块
const pdfModule = window.wasmModule?.spirepdf;
// 检查模块是否就绪
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// 把字体文件载入 VFS,供条码上方的类型名使用
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// 创建 PDF 文档并添加一个页面
const doc = new pdfModule.PdfDocument();
const page = doc.Pages.Add();
// 类型名的字体、颜色与对齐方式,绿色与黑色条码区分开
const labelFont = new pdfModule.PdfTrueTypeFont({ fontFile: '/Library/Fonts/ARIAL.TTF', size: 12 });
const labelBrush = new pdfModule.PdfSolidBrush({ pdfRGBColor: new pdfModule.PdfRGBColor({ color: pdfModule.Color.get_Green() }) });
const labelFormat = new pdfModule.PdfStringFormat({ alignment: pdfModule.PdfTextAlignment.Left });
// 待编码的数据,以及各自使用的条码类与标注在条码上方的类型名
const items = [
{ Barcode: pdfModule.PdfCodabarBarcode, label: 'Codabar', text: '00:12-3456/7890' },
{ Barcode: pdfModule.PdfCode11Barcode, label: 'Code 11', text: '123-4567890' },
{ Barcode: pdfModule.PdfCode32Barcode, label: 'Code 32', text: '16273849' },
{ Barcode: pdfModule.PdfCode39Barcode, label: 'Code 39', text: 'ORDER-2026-0007' },
{ Barcode: pdfModule.PdfCode39ExtendedBarcode, label: 'Code 39 Extended', text: 'Order 2026-0007' },
{ Barcode: pdfModule.PdfCode93Barcode, label: 'Code 93', text: 'ORDER-2026-0007' },
{ Barcode: pdfModule.PdfCode93ExtendedBarcode, label: 'Code 93 Extended', text: 'Order 2026-0007' },
{ Barcode: pdfModule.PdfCode128ABarcode, label: 'Code 128A', text: 'INVOICE 2026' },
{ Barcode: pdfModule.PdfCode128BBarcode, label: 'Code 128B', text: 'Order-2026-0001' },
{ Barcode: pdfModule.PdfCode128CBarcode, label: 'Code 128C', text: '20260001' },
];
// 从页面上方开始依次绘制
let y = 20;
for (const item of items) {
// 在条码上方标出它所属的类型
page.Canvas.DrawString({ s: `${item.label}:`, font: labelFont, brush: labelBrush, x: 20, y: y, format: labelFormat });
// 用待编码的文本创建条形码对象
const barcode = new item.Barcode({ text: item.text });
// 可读文本显示在条形码下方
barcode.TextDisplayLocation = pdfModule.TextLocation.Bottom;
// 收窄条高,让十种条码排进同一页
barcode.BarHeight = 25;
// 绘制到类型名下方,该坐标是条形码左上角的位置
barcode.Draw({ page: page, location: new pdfModule.PointF(20, y + labelFont.Size + 4) });
// 用实际占用的下边界确定下一枚的位置
y = barcode.Bounds.Bottom + 10;
}
// 保存文档
const outputFileName = '多种条形码结果.pdf';
doc.SaveToFile(outputFileName);
doc.Close();
// 从 VFS 读取生成的文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>绘制多种条形码</h1>
<button onClick={drawBarcodeTypes}>
开始绘制
</button>
</div>
);
}
export default App;
十种条形码在同一页面依次绘制,类型名标在条码上方,可读文本排在条码下方

自定义条形码的外观
默认外观是黑条白底、文字排在下方,需要时可以从颜色、条高、留白到文字字体逐项覆盖。条和文字分别由 BarColor 与 TextColor 着色,BackColor 铺在条码下面当底色;BarHeight、NarrowBarWidth 与 BarcodeToTextGapHeight 控制尺寸细节,QuietZone 是条码四周需要留出的空白。
function App() {
const customizeBarcode = async () => {
// 获取 Spire.PDF WASM 模块
const pdfModule = window.wasmModule?.spirepdf;
// 检查模块是否就绪
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// 把字体文件载入 VFS,供条形码文字使用
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// 创建 PDF 文档并添加一个页面
const doc = new pdfModule.PdfDocument();
const page = doc.Pages.Add();
// 第一枚保持默认外观,用于对比
const plain = new pdfModule.PdfCode39Barcode({ text: 'ORDER-2026-0007' });
plain.TextDisplayLocation = pdfModule.TextLocation.Bottom;
plain.Draw({ page: page, location: new pdfModule.PointF(20, 20) });
// 第二枚逐项设置外观
const barcode = new pdfModule.PdfCode39Barcode({ text: 'ORDER-2026-0007' });
barcode.TextDisplayLocation = pdfModule.TextLocation.Bottom;
// 条、文字与底色分别设置
barcode.BarColor = new pdfModule.PdfRGBColor({ color: pdfModule.Color.FromArgb(0, 60, 160) });
barcode.TextColor = new pdfModule.PdfRGBColor({ color: pdfModule.Color.FromArgb(200, 0, 0) });
barcode.BackColor = new pdfModule.PdfRGBColor({ color: pdfModule.Color.FromArgb(255, 255, 0) });
// 条高、窄条宽度、条到文字的间距
barcode.BarHeight = 45;
barcode.NarrowBarWidth = 1.6;
barcode.BarcodeToTextGapHeight = 4;
// 文字居中,四周各留 5 磅空白
barcode.TextAlignment = pdfModule.PdfBarcodeTextAlignment.Center;
barcode.QuietZone.Top = 5;
barcode.QuietZone.Bottom = 5;
barcode.QuietZone.Left = 5;
barcode.QuietZone.Right = 5;
// 文字改用 12 磅的 Arial
barcode.Font = new pdfModule.PdfTrueTypeFont({ fontFile: '/Library/Fonts/ARIAL.TTF', size: 12 });
// 排在第一枚下方
barcode.Draw({ page: page, location: new pdfModule.PointF(20, plain.Bounds.Bottom + 30) });
// 保存文档
const outputFileName = '自定义条形码样式结果.pdf';
doc.SaveToFile(outputFileName);
doc.Close();
// 从 VFS 读取生成的文件,触发下载
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>自定义条形码样式</h1>
<button onClick={customizeBarcode}>
开始设置
</button>
</div>
);
}
export default App;
下方条形码更换了条的颜色、高度、留白与文字字体

常见问题
构造 PdfRGBColor 时提示 Ambiguous call
原因:PdfRGBColor 的构造函数只接受 Color 对象,直接按 RGB 三个分量传参(如 new pdfModule.PdfRGBColor(0, 60, 160) 或 { r: 0, g: 60, b: 160 })会命中多个重载而报错:Ambiguous call: arguments (object) match multiple overloads.。
解决:先用 Color.FromArgb 生成 Color,再交给 PdfRGBColor:
// 正确写法:先得到 Color 对象
barcode.BarColor = new pdfModule.PdfRGBColor({ color: pdfModule.Color.FromArgb(0, 60, 160) });
// 也可以直接取预设颜色
barcode.TextColor = new pdfModule.PdfRGBColor({ color: pdfModule.Color.get_Blue() });
同一段数据,条形码的长度却不一样
原因:不同符号的编码密度不同,同样的文本用 Code128 画出来比用 Code39 短,Code128C 则还要更短;此外 NarrowBarWidth 调大后整条条码会同步变宽。
解决:需要固定版面时,可以用接收 RectangleF 的 Draw 重载限定条码占用的区域,或统一调整 NarrowBarWidth:
// 无论数据多长,条形码都落在同一个矩形内
barcode.Draw({ page: page, rect: new pdfModule.RectangleF(20, 20, 250, 80) });
可以在 PDF 中添加二维码吗
原因:Spire.PDF for JavaScript 提供的一维条码类是 PdfCodabarBarcode、PdfCode39Barcode、PdfCode128BBarcode 等,没有二维码类,用 PdfQRCodeBarcode 这样的类名取到的是 undefined。
解决:二维码在前端生成图片,再通过 PdfImage.FromStream 与 page.Canvas.DrawImage 绘入页面,定位与缩放交给画布:
// qrBytes 是前端生成的二维码 PNG 字节
const image = pdfModule.PdfImage.FromStream(new pdfModule.Stream(qrBytes));
page.Canvas.DrawImage({ image: image, x: 20, y: 20, width: 100, height: 100 });
获取免费许可证
如果您希望删除结果文档中的评估消息,或者摆脱功能限制,请该Email地址已收到反垃圾邮件插件保护。要显示它您需要在浏览器中启用JavaScript。获取有效期 30 天的临时许可证。









