ZXing 条码生成底层全解:一行 URL 如何变成 300×300 的 BitMatrix 像素矩阵 ZXing 条码生成底层全解一行 URL 如何变成 300×300 的 BitMatrix 像素矩阵【免费下载链接】zxingZXing (Zebra Crossing) barcode scanning library for Java, Android项目地址: https://gitcode.com/gh_mirrors/zx/zxing把一段 URL 贴进扫码 App摄像头快门还没响芯片里已经在并行干活了这段文本被拆成字节、掺进纠错码、排进 25×25 的格子、放大成几百个像素。ZXingZebra Crossing一个开源条码扫描与生成库的条码生成链路全程跑完通常不到 200 毫秒而承载这条链路核心的是BitMatrix位矩阵——生成时它被一层层填上 bit扫描时它又被一行行读出来。下面用追踪一段数据的一生来拆这条链路每一步都以数据此刻长什么样作为锚点文本编码URL 字符串被选模式、切字节变成一条 BitArray 位流纠错编码里德-所罗门算法追加冗余字节数据流变长矩阵布局位流被排进 25×25 版本矩阵贴上定位图案与掩码像素放大25×25 的 module 被 setRegion 放大成 300×300图像输出BitMatrix 渲染成 BufferedImage写出 PNG反向识别摄像头帧二值化后走回同一条路还原出 URL一行 URL 进入 ZXing 后先被拆成了什么第一步发生在com.google.zxing.qrcode.encoder.Encoder负责把输入文本翻译成符合 QR 码规范的位流里。chooseMode会先判断内容属于哪种编码模式全是数字走数字模式4 个 bit 表示两位数字、大小写字母加数字走字母数字模式6 个 bit 表示两个符号、其余一律走字节模式按 UTF-8 转字节。对https://example.com这样的 URL 来说字节模式胜出。数据此刻长这样先写 4 位模式标志再写长度字段然后是 URL 的 UTF-8 字节。这些零碎全部串进一条BitArray负责存连续比特序列的一维容器里——它还是裸数据既没纠错、也没有任何几何结构。这一步决定了二维码底层原理里最容易被忽略的一环你输入的多半是 ASCII 文本但矩阵里真正摆上去的是模式标志、长度头和字节序列拼成的位流而不是原文本身。纠错码塞进来之后数据流变长了多少接着ReedSolomonEncoder负责按里德-所罗门算法生成冗余校验字节登场。QR 码的纠错等级 L/M/Q/H 分别意味着能恢复约 7%、15%、25%、30% 的损坏模块。等级越高追加的校验字节越多。编码器把数据块和纠错块交错排列防止损坏集中在同一块上——哪怕你拿指甲在码上划一道只要破损没超过恢复上限扫描照样能读。数据此刻长这样一条比原文长出一截的比特流后半段全是故意算出来的垃圾。这条变长的位流随后决定矩阵尺寸版本 1 是 21×21版本 2 是 25×25版本 n 每升一级边长加 4。内容越短、纠错等级越低矩阵越小。25×25 的格子是怎么被一层层填上的QRCodeWriter负责把编码结果渲染成 BitMatrix 的输出器入口长这样MapEncodeHintType, Object hints new HashMap(); hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M); hints.put(EncodeHintType.CHARACTER_SET, UTF-8); hints.put(EncodeHintType.MARGIN, 2); BitMatrix matrix new QRCodeWriter().encode( https://example.com, BarcodeFormat.QR_CODE, 300, 300, hints);EncodeHintType就是 encode 参数的开关枚举纠错等级、字符集、边距都从这里传进去。返回的BitMatrix负责以位压缩方式存储二维黑白格子的核心数据结构内部只有一个 int 数组rowSize (width 31) / 32每行恰好从 int 边界开始一个 int 存 32 个模块。取某个格子的黑白色只需三行位运算int offset y * rowSize (x / 32); return ((bits[offset] (x 0x1f)) 1) ! 0;实现见 BitMatrix.java。填格顺序是先摆三处回字形定位图案、格式信息区和 Z 字形时序图案再把数据位按 Z 字形扫进去最后套上掩码。QR 编码器会对 15 种候选掩码各算一次罚分连续同色、2×2 色块、类似定位图案的纹理都扣分选出最不像定位图案的那张。填完之后数据长这样一张 25×25 的 0/1 方阵。这也是理解一维条码与二维条码区别的关键一维码如 Code128输出的是条空宽度序列最终仍要排成一根条一列白的矩阵二维码输出的是真正的 2D BitMatrix直接可渲染。一个 bit 怎么变成 25 个像素QRCodeWriter.renderResult负责放大。它先算multiple min(outputWidth / qrWidth, outputHeight / qrHeight)——25×25 加边距要填到 300×300倍数就是 10。然后双层循环逐格检查凡input.get(x, y) 1的格子就用setRegion(outputX, outputY, multiple, multiple)把矩形区域整体置黑盖掉一块 10×10 像素。数据此刻长这样300×300 的 BitMatrix其中每个原 module 都膨胀成了 10×10 的色块边距quiet zone留白保住扫描识别需要的安静区。内存上这很划算300×300 的矩阵只占300 × 10 × 4 ≈ 12KB的 int 数组比同尺寸 byte 矩阵省 8 倍。从 BitMatrix 到文件这一步叫 BitMatrix 渲染MatrixToImageWriter负责把位矩阵画成 BufferedImage 并写文件的工具类逐行调getRow(y, row)拷出一行 bit把黑白值映射成 RGB一行setRGB写进BufferedImage再交给ImageIO压成 PNG。不同格式的差异主要在几何结构上格式典型尺寸定位图案数据区占比QR 码21×21 起步版本 1 边长 4三角落回字形 finder 中央十字 timing约 60%Data Matrix10×10 起步仅左下 L 形 finder约 75%Aztec 码37×37 起楔形可扩中心同心方环约 70%PDF417三行条带起始/数据/终止左右起始与终止图案数据行占 2/3 高度扫描时同一条链路是怎么倒着走的反向识别的输入是一张摄像头帧。LuminanceSource负责从原始图像里逐像素取灰度值的抽象层先把帧包起来HybridBinarizer负责用局部均值加高斯权重算出每个像素的自适应阈值、把灰度图切成黑白二值图再把光照不均的画面裁成干净的黑白格——这一步正是前面渲染链路的逆操作。MultiFormatReader负责按候选格式依次调度识别器尝试解码的总入口接手后QR 识别器先在二值图里找三个回字形定位角算出三条中心线用PerspectiveTransform负责把拍摄歪斜的透视图像拉回正视图的变换器把画面矫正采样出一张端正的 25×25BitMatrix。随后QRCodeDecoder负责按 QR 规范把解码完的位流还原成文本的解码器反着做读格式信息、按掩码还原数据位、按 Z 字形倒序读出数据流、用里德-所罗门校验找回坏块字节、按字节模式解码吐出Result负责承载最终文本、格式、方向等元信息的结构体。生成时数据走过的每一关这里都原样折返。8 行代码自己把这条链路跑一遍关掉页面前把这段贴进任何带 zxing-core 依赖的 Java 项目立刻验证今天讲的所有东西QRCodeWriter writer new QRCodeWriter(); BitMatrix matrix writer.encode( https://example.com, BarcodeFormat.QR_CODE, 300, 300, null); System.out.println(matrix: matrix.getWidth() x matrix.getHeight()); System.out.println(matrix.toString(■ , ));打印出的 300 行字符方阵就是本文跟踪了一整篇的BitMatrix位矩阵——每个■都是那个 int 数组里某个 bit 被右移出来的结果。更多 API 细节可翻 docs/index.html。【免费下载链接】zxingZXing (Zebra Crossing) barcode scanning library for Java, Android项目地址: https://gitcode.com/gh_mirrors/zx/zxing创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考