Code128 条形码最早由美国 Intermec 公司于 1981 年推出,旨在解决当时传统条形码(如 Code39)编码字符有限、数据密度低的问题。它属于高密度线性条形码,通过不同宽度的黑条与空白(称为 “模块”)的组合,来表示数字、字母、符号及控制字符,是目前唯一能同时编码 ASCII 0-127 全部 128 个字符的线性条形码(这也是其名称 “Code128” 的由来)
1. 数据载体
-
包含 0-9 的数字、A-Z 的大写字母、a-z 的小写字母;
-
覆盖所有 ASCII 特殊符号(如!、@、#、$、% 等);
2. 编码集
Code128 包含三个 “编码子集”(Subset),可根据数据类型灵活切换,进一步优化编码效率:
-
128 A:编码 ASCII 0-95(含数字、大写字母、控制字符),适合以大写字母和控制字符为主的数据;
-
128 B:编码 ASCII 32-127(含数字、大小写字母、特殊符号),适合混合字母、数字、符号的数据(最常用子集);
-
128 C:仅编码 00-99 的双位数字,适合纯数字数据(如物流单号、身份证号),可将数据密度提升一倍;
-
128 Auto:根据数据内容自动选择A\B\C字符集,以最短的方式编码图形。
3、“黑白线条” 的逻辑
看似复杂的 Code128 条形码,其实由固定的 5 个部分组成,每一部分都有明确的功能,缺一不可:
- 起始字符 :条形码的 “开头标识”,用于告诉扫描设备 “这是 Code128 条形码,且当前使用的是哪个子集”(共 3 种起始字符,分别对应 Subset A/B/C);
- 数据字符 :条形码的 “核心内容”,承载需要传递的实际数据(如产品号、单号),每个数据字符由 11 个模块(黑条 + 空白)组成;
- 校验字符 :条形码的 “纠错保险”,通过特定算法(将起始字符、数据字符的 “值” 按权重累加后取模)计算得出,确保数据传输的准确性;
- 终止字符 :条形码的 “结尾标识”,由 3 个连续的黑条组成,用于告诉扫描设备 “数据已读取完毕”;
-
静区 :条形码两侧的 “空白区域”,宽度至少为 10 个模块,用于避免扫描设备将其他图案误识别为条形码的一部分(静区不足是导致条形码无法识别的常见原因之一)。
举个例子:如果要编码 “CODE128” 这个字符串,Code128 的结构会是:
起始字符(Subset B)→ 数据字符(C、O、D、E、1、2、8)→ 校验字符(计算得出)→ 终止字符 → 两侧静区
-
黑白条纹:128A和128B子集每个字符对应一组黑白条纹,128 C子集的数据字符是每两位对应一组黑白条纹,所以128C的数据字符只能是偶数位, 数据字符的长度相同的情况下,128C的条形码比A和B更短。
每组黑白条纹由10条黑白竖线构成(终止字符13条),所有字符对应黑白条纹加在一起就形成了条条形码;
-
每个字符对应的黑白条纹可以参考 国家标准|GB/T 15425-2014
3、校验字符算法
Code128 校验位的计算公式为:校验位=(起始字符值+每位数据在整个数据中的位置 × 每位数据对应值)% 103。 具体计算步骤如下:
- 确定起始位对应值:128A:103,128B:104,128C:105。
- 确定每位数据对应的值:根据数据所采用的编码类型(Code128A、Code128B 或 Code128C),对照相应的编码表确定每位数据对应的值。例如,在 Code128A 中,字符 “A” 对应的33,字符 “B” 对应为34;
- 计算乘积和:将每位数据在整个数据中的位置(从 1 开始)乘以其对应的值,然后将所有乘积相加,再加上起始位对应值。
- 计算校验位:将上述乘积和对 103 取模,所得结果即为校验位的值。
例如,对于字符串 “ABC” 以 Code128A 的方式编码,其校验位计算如下:起始位为 Start A,值为 103,“A” 的 值为 33,“B” 的值为 34,“C” 的值为 35。校验位=(103 + 33×1 + 34×2 + 35×3)% 103 =(103 + 33 + 68 + 105)% 103 = 309 % 103 = 0。
4、自己写的一个简单的128C生成方法供大家参考
"CODE128_BARS" 变量放的是每个字符的对应的黑白条纹(弄丢了),大家可以参看国家标准自己整理,别随便用其他网上分享的,很多错的。
/**
* 生成Code128C格式的条形码
* @param {string} code - 要编码的数据字符串(必须是偶数位数字)
* @description
* Code128C是一种高密度数字条形码格式,仅支持偶数位数字
* 每个字符表示2位数字,使用105作为起始字符,106作为停止字符
*/
function generateCode128CBarcode(options) {
const { code, barHeight = 30, barWidth = 1, type = "html", svgScale = 1 } = options;
// 参数验证
if (!code || !/^\d+$/.test(code) || code.length % 2 !== 0) {
console.error("Code128C仅支持偶数位数字字符串");
return;
}
// 步骤1: 将输入字符串分割成2位数字的数组
const digitPairs = [];
for (let i = 0; i < code.length / 2; i++) {
const startIndex = i * 2;
const endIndex = startIndex + 2;
digitPairs.push(code.slice(startIndex, endIndex));
}
// 步骤2: 构建条形码数据
const barcodePatterns = [CODE128_BARS[105]]; // 起始字符START C (值为105)
let checksum = 105; // 初始校验和为起始字符的值
// 步骤3: 添加数据字符并计算校验和
for (let i = 0; i < digitPairs.length; i++) {
const numericValue = Number(digitPairs[i]);
barcodePatterns.push(CODE128_BARS[numericValue]);
checksum += numericValue * (i + 1); // 权重从1开始递增
}
// 步骤4: 计算并添加校验码
const checkDigit = checksum % 103;
barcodePatterns.push(CODE128_BARS[checkDigit]);
barcodePatterns.push(CODE128_BARS[106]); // 停止字符STOP
// 步骤5: 渲染
if (type === "html") {
return drawCode128CHTML(barcodePatterns, barHeight, barWidth);
} else if (type === "svg") {
return drawCode128CSVG(barcodePatterns, barHeight, barWidth, svgScale);
}
}
// 通过html渲染
function drawCode128CHTML(barcodePatterns, barHeight, barWidth) {
const barcodeElements = [];
for (let i = 0; i < barcodePatterns.length; i++) {
const pattern = barcodePatterns[i];
for (let j = 0; j < pattern.length; j++) {
const color = pattern[j] === "b" ? "black" : "white";
barcodeElements.push(
`<div style="display: inline-block; width: ${barWidth}px; height: ${barHeight}px; background: ${color}; margin: 0;"></div>`
);
}
}
const barcodeHTML = barcodeElements.join("");
return "<div>" + barcodeHTML + "</div>";
}
// 通过html渲染
function drawCode128CSVG(barcodePatterns, barHeight, barWidth, svgScale) {
// svg的宽度
let svgWidth = 0;
// 生成SVG路径
let xPosition = 0;
let svgElements = [];
for (const pattern of barcodePatterns) {
for (const char of pattern) {
if (char === "b") {
// 黑色条
svgElements.push(
`<rect x="${xPosition}" y="0" width="${barWidth}" height="${barHeight}" fill="black"/>`
);
} else {
// 白色条
svgElements.push(
`<rect x="${xPosition}" y="0" width="${barWidth}" height="${barHeight}" fill="white"/>`
);
}
xPosition += barWidth;
svgWidth++;
}
}
svgWidth = svgWidth * barWidth;
let outSvgWidth = svgScale * svgWidth
// 构建完整的SVG
const svg = `
<svg class="barcode-svg" width="${outSvgWidth}" height="${barHeight}" viewBox="0 0 ${svgWidth} ${barHeight}">
<g>
${svgElements.join("\n ")}
</g>
</svg>
`;
return svg;
}