文档扫描与图像处理

条码结构图解:悬停任意区域,看清 EAN-13 和 QR Code 的内部构造

条码结构图解界面

「条码是怎么工作的」是一个搜索量很大、答案很稳定的问题——稳定到几乎所有答案都是一段文字配一张静态图。静态图有说不清的事:EAN-13 的第 13 位数字其实不占用任何独立的图案,它藏在前六位的奇偶性里;Code 128 的校验值不是一个数字,而是一个完整的 11 模块字符;QR Code 的定位图形为什么长成三个角上的同心方块而第四个角没有。条码结构图解(英文名 Online Barcode Structure Diagram)把这些做成可交互的:悬停任意区域,看它占几个模块、起什么作用、缺了它会发生什么;输入任意内容,实时看它变成模块序列。

在线演示

条码结构图解(英文名 Online Barcode Structure Diagram):覆盖 EAN-13、Code 128、Code 39、ITF-14 和 QR Code 五种符号。页面自包含,没有 CDN 和构建步骤,键盘 Tab 也能遍历所有区域。

配合本文验证时可以这样走一遍:切到 EAN-13,悬停最左边的保护条看它为什么是 3 个模块;再悬停校验位,对照页面上的加权算式手算一遍;最后切到 QR Code,输入一段文字看版本和纠错等级如何改变分块布局。

关键要点

  • 五种符号、一套渲染器:编码器返回同一形状的数据(模块序列 + 结构分组),app.js 从不硬编码任何模块数,全部问编码器要。
  • ROLES 是与码制无关的词汇表(静区、保护条、起始符、数据、校验、终止符……),一种角色一种颜色,全页通用——「青色是保护条」在五种码里都成立。
  • 页面说明由编码结果生成而非转录:每步算式、每个图案都从编码器输出读回,两者不可能各自漂移。
  • 编码器经过三层验证:QR 按 ISO/IEC 18004 测试向量并与 python-qrcode 比对 160 种版本/纠错组合;一维码与 bwip-js 和公开符号表交叉核对;页面本身有无头浏览器全量巡检。
  • 验证过程发现了参考库自己的问题:bwip-js 的 ITF 编码会改写数字内容,某些 EAN-13 载荷的校验位与 GS1 加权规则算出的不一致。

悬停能读到什么

每个区域都回答三个问题:这是什么(角色和一句话说明)、它占多少模块、如果它缺失或错位会破坏什么。以 EAN-13 为例:

区域 模块数 缺了会怎样
静区 各 9 读取器找不到符号起点
起始符 3 无法确定解码起点
左侧数据字符 6 × 7 丢失前六位数据
校验位 7 无法检测读取错误
终止符 3 无法确认符号结束

细节都在面板里:每个数据字符的 7 模块图案并排展示,校验位算式带着你输入的数字一步步算给你看,QR Code 的分块布局按版本和纠错等级实时重排。对 EAN-13,悬停左侧数据字符时还会展示奇偶表——那是最多被静态图漏掉的事实。

说明是生成的,不是抄的

这个页面最不一样的设计在于:解释文字不是从规范书里抄过来贴在图旁边的,而是从编码器的返回值里读出来的。编码器返回的不只是黑白模块序列,还有每个结构分组拥有哪些模块:

// 编码器返回同一形状:模块 + 结构分组 + 角色
{
  modules: [1,0,1, /* ... */],
  groups: [
    { role: "guard",  start: 3,  length: 3, title: "左侧保护条", /* ... */ },
    { role: "data",   start: 7,  length: 42, /* ... */ },
    { role: "check",  start: 43, length: 7,  /* ... */ }
  ]
}

app.js 因此不需要知道「EAN-13 校验位在第 43 到 49 模块」这类事实——它只画编码器给的东西。编码器错了,页面会明显地错,而不是错得悄无声息。这个性质让页面和编码器可以被同一套测试看住。

交叉验证时发现的三个事实

页面自带的一维编码器与 bwip-js 做了逐模块交叉核对,结果里三条值得记录:

  1. bwip-js 的 interleaved2of5 会改写数字内容:给它 6 位数字,返回的符号实际编码了 4 位;14 位进来 8 位出去。符号本身合法,但不是你给的那个值,所以不能作为 GS1 ITF-14 的参照。本页面的 ITF 改为按公开的宽元素位置表独立验证——那是真实解码器使用的同一张表。
  2. bwip-js 在某些 EAN-13 载荷上算出不同的校验位:对 400638133393 它要 1,而 GS1 加权规则的两种等价写法(从左 3,1,3… 或从右 1,3,1…)都得到 7,两种写法在偶数长度载荷上完全一致。模块比对只在不争议的码上运行,分歧被写成独立断言,防止将来被悄悄抹掉。
  3. 两个编码器为 ABC123456789 选了不同的 Code 128 码集:都是合法的——规范并不规定选择算法——页面编码器的选择短一个符号字符。测试断言的是真正重要的性质(切换发生在哪、是否真的省了),而不是逐模块比对。

这三条都写进了验证脚本,所以它们不是「注意事项」,而是被测试固定住的事实。

边界

这是一个解释工具,不是认证编码器。EAN/UPC 附加码、Code 128 的 GS1 应用标识符功能字符、Code 39 全 ASCII 转义、QR 的数字/字母数字/字节之外的模式,都不在范围内。要看懂结构,它够了;要生成贴到商品上的标签,用在线条码与二维码生成器这类正式工具;要识别真实世界的条码,用在线条码扫描器。