跳转到内容

在 PDF 中生成 1D 与 2D 条码

本 recipe(示例)会将 1D 与 2D 条码直接绘制到 PDF 页面上。核心的 HasBarcodes trait 提供 write1DBarcode()write2DBarcode()。两者都会在当前页面上使用原生 PDF 路径运算符绘制符号,因此输出是简洁且确定性的矢量内容。本 recipe 取材自 examples/10-barcodes.php

Terminal window
composer require nextpdf/core:^3

你不需要安装额外扩展。条码编码器由纯 PHP 实现,符号则使用标准的 PDF 矩形运算符绘制(ISO 32000-2 §8.5)。

条码是绘制出来的,而不是以图像形式嵌入。payload 是你要编码的数据,例如产品编号或网址。

write1DBarcode() 会将 payload 编码成所选 BarcodeType 的 bar/space 样式,再输出一连串填充矩形。write2DBarcode() 会根据所选 Barcode2DType 构造一个模块矩阵,并为每个暗模块输出一个填充矩形。Data Matrix 与 QR Code 采用 Reed-Solomon 纠错,因此即使符号的一部分受损,扫描器仍能还原数据。

每个模块都对应一条确定性的 re … f 路径,不引入任何熵源,因此条码内容本身可以完全重现。可重现性级别为 structural,因为外围文档仍带有每次保存时才会变化的原子值:trailer 的 /ID,以及 /CreationDate/ModDate 时间戳。测试夹具会先剥除这些原子值,再比对经 qpdf 规范化后的结构。

NextPDF\Core\Concerns\HasBarcodes(混入 Document):

  • write1DBarcode(string $code, BarcodeType $type, ?float $x = null, ?float $y = null, float $w = 0, float $h = 30, float $barWidth = 0.4, bool $skipZeroWidthBars = true): static
  • write2DBarcode(string $code, Barcode2DType $type, ?float $x = null, ?float $y = null, float $w = 0, float $h = 0, float $moduleSize = 1.0, string $ecLevel = 'L', ?int $mask = null, ?int $version = null, bool $gs1 = false, bool $dmre = false, bool $rectangular = false): static

symbology(条码编码规格)是一类条码标准,用于定义数据如何转换成条或模块。BarcodeType 列出 1D symbology(C128EAN13UPCAI25CODABARISBNGS1_128 等),Barcode2DType 则列出 2D symbology(QRCodeDataMatrixPDF417HanXinMicroQR 等)。

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Barcode\Barcode2DType;
use NextPDF\Barcode\BarcodeType;
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setTitle('Barcode Quick Start');
$doc->addPage();
$doc->write1DBarcode('NEXTPDF-2026', BarcodeType::C128, x: 15, y: 30, w: 80, h: 20);
$doc->write2DBarcode('https://nextpdf.dev', Barcode2DType::QRCode, x: 15, y: 60, w: 40, h: 40);
$doc->save(__DIR__ . '/barcodes.pdf');
echo "Wrote barcodes.pdf\n";

下面这个完整且可由测试夹具执行的示例,对应 examples/10-barcodes.php。它会将 PDF 写入测试夹具通过 NEXTPDF_COOKBOOK_OUTPUT 提供的路径;手动执行时,则回退为写入本地文件。随后,可重现性测试夹具可以运行两次,并断言结构完全相同。该结构经过 qpdf 规范化,并剥除了每次保存时才会变化的 /ID 与时间戳原子值。

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Barcode\Barcode2DType;
use NextPDF\Barcode\BarcodeType;
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setTitle('Barcode Examples');
$doc->addPage();
$doc->setFont('helvetica', 'B', 18);
$doc->cell(0, 12, 'Barcode Examples', newLine: true);
$doc->ln(5);
// --- 1D barcodes ---
$doc->setFont('helvetica', 'B', 14);
$doc->cell(0, 10, '1D Barcodes', newLine: true);
$doc->ln(3);
$doc->setFont('helvetica', '', 10);
$doc->cell(0, 6, 'Code 128:', newLine: true);
$doc->write1DBarcode('NEXTPDF-2026', BarcodeType::C128, x: 15, y: null, w: 80, h: 20);
$doc->ln(28);
$doc->cell(0, 6, 'EAN-13:', newLine: true);
$doc->write1DBarcode('4006381333931', BarcodeType::EAN13, x: 15, y: null, w: 60, h: 20);
$doc->ln(28);
// --- 2D barcodes ---
$doc->setFont('helvetica', 'B', 14);
$doc->cell(0, 10, '2D Barcodes', newLine: true);
$doc->ln(3);
$doc->setFont('helvetica', '', 10);
$doc->cell(0, 6, 'QR Code (URL):', newLine: true);
$doc->write2DBarcode('https://nextpdf.dev', Barcode2DType::QRCode, x: 15, y: null, w: 40, h: 40);
$doc->ln(48);
$doc->cell(0, 6, 'DataMatrix:', newLine: true);
$doc->write2DBarcode('NextPDF-DM-2026', Barcode2DType::DataMatrix, x: 15, y: null, w: 30, h: 30);
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT');
$doc->save($out !== false ? $out : __DIR__ . '/barcodes.pdf');
echo "Wrote barcodes PDF (Code 128, EAN-13, QR Code, DataMatrix)\n";

预期输出:

Wrote barcodes PDF (Code 128, EAN-13, QR Code, DataMatrix)
  • payload 的有效性因 symbology 而异。 EAN13 需要 12 或 13 位数字。无效的 payload 会在写入任何内容之前先抛出异常。UPCAISBNISSN 各有自己的长度与校验位规则。
  • x/y 是可选的。 省略它们时,条码会放在当前光标位置。传入明确的坐标,可以获得可预测的布局。
  • w = 0 会自动调整尺寸。 宽度设为零时,编码器会选择自然的模块宽度。传入正的宽度,即可适配到固定方框中。
  • 2D 纠错级别。 write2DBarcode() 默认为 ecLevel: 'L',也就是最低级别。对于必须经受打印损伤的 QR Code,可以提高该级别('M''Q''H')。级别越高,矩阵也会越大。
  • GS1 应用标识符。gs1: true 传入 write2DBarcode(),或改用 BarcodeType::GS1_128,即可处理带有 FNC1 前缀的 GS1 结构化数据。
  • 会隐式创建一个页面。 当你在 addPage() 之前调用条码方法时,NextPDF 会先补上一个页面。这虽然方便,但当页面几何很重要时,请明确调用 addPage()

编码复杂度方面,1D 为 O(payload 长度)、2D 为 O(矩阵面积),两者都在微秒级别。每个模块都是一个 re … f 路径运算符,因此密集的 QR Code 会让内容流增加几 KB。过程中没有栅格化步骤,因此无论符号多大,内存用量都保持平稳。本 recipe 仍稳定保持在 1500 ms / 64 MB 的预算之内。

条码会承载你传入的任何 payload,因此在使用端应把条码值视同其他任何不可信的输入来处理。这个库不会对 payload 签名,也不会验证其真实性。2D 符号并不是加密:任何拥有扫描器的人都能读取它。

陈述规格条款参考 ID
条码模块使用矩形路径构造运算符绘制。ISO 32000-2§8.5
Code 128 符号字符使用已定义的 bar/space 元素结构。ISO/IEC 15417§4.3.1
Data Matrix 符号采用 Reed-Solomon 纠错。ISO/IEC 16022§7.6.1
QR Code 数据会切分成多个纠错块。ISO/IEC 18004§7.5.2

NextPDF 实现了所引用的 symbology 编码,但并未声称已通过条码标准的正式认证。条码 symbology 语料库文档在授权上受限于 Tier C。引用仅以 clause-id 与 reference_id 指针标示,并未复制任何标准原文。