做二维码的时候常遇到一个困惑:明明内容不多,生成的码已经密得看不清了;而别人的二维码扫的是个挺长的网址,看起来却稀疏得多。
原因在于二维码(QR Code)内部有四种不同的编码模式,不同字符走的通道不一样,占用的空间能差好几倍。理解这一点,你就能主动控制二维码的密度。
四种编码模式:同一条信息,大小差很多
QR 码为不同类型的字符准备了专门的编码方式,每种方式的「打包效率」不同:
| 模式 | 适用字符 | 每个字符占位 | 相对效率 |
|---|---|---|---|
| 数字模式 | 0-9 | 约 3.33 比特 | 最高(省 40%) |
| 字母数字模式 | 0-9 A-Z 空格 $%*+-./: | 约 5.5 比特 | 较高 |
| 字节模式 | 其他所有字符(含中文) | 8 比特 | 基准 |
| 汉字模式 | Shift-JIS 汉字 | 13 比特 | 对中日常用字略优 |
关键在于:一个汉字在 UTF-8 编码下占 3 个字节,也就是 24 比特。而一个英文字母只占 1 个字节(8 比特)。所以同样「20 个字」,中文要 480 比特,英文只要 160 比特——差 3 倍。
这就是中文二维码更密的最直接原因。
汉字模式能救一点,但有条件
QR 标准里有个专门的「汉字模式」,每个汉字只用 13 比特,比字节模式的 24 比特省将近一半。听起来很棒,但它有个硬性限制:只支持 Shift-JIS 编码里存在的汉字。
Shift-JIS 是日文编码,收录的汉字集合和 GB2312 或 Unicode 并不完全重合。所以:
- 很多常见中文字能命中,能省空间;
- 部分简体字、生僻字、以及所有非汉字字符(比如中文标点、emoji)只能退回字节模式;
- 生成器要能在两种模式间智能切换,否则省不下多少。
实际使用中,很多生成器为了保证兼容性和正确性,干脆统一用字节模式。结果就是中文内容全部按 24 比特/字计算,二维码自然偏密。
顺便说个实用技巧:中文标点也是 3 字节。句号「。」、逗号「,」、顿号「、」都是全角字符,同样占 3 字节。如果内容里标点很多,可以改用半角标点试试,能省一些空间。
纠错等级:冗余换来的容错
二维码另一个吃空间的地方是纠错码。它用里德-所罗门算法给数据加了冗余,使得即使图案被污损一部分,仍然能还原出原始内容。四个等级:
- L 级:约 7% 冗余,能恢复约 7% 的损坏
- M 级:约 15% 冗余(最常用的默认档)
- Q 级:约 25% 冗余
- H 级:约 30% 冗余,最高容错
冗余是实打实占地方的。同样是版本 10(57×57 格),L 级能存 271 字节,H 级只能存 119 字节——少了将近 56%。
所以如果你的二维码只需要印在屏幕上扫,用 L 或 M 就够了,图案会明显稀疏一些、更好扫。只有在二维码要印在可能磨损的实物上、或者中间要放 logo 时,才值得用 Q 或 H 级。
中间放 logo 的原理正是如此:logo 遮住的区域被当作损坏,靠 H 级那 30% 的冗余补回来。如果用 L 级再放 logo,基本就扫不出来了。
版本:二维码的「尺寸档位」
QR 码一共 40 个版本,版本 n 的边长是 4n + 17 个格点:
- 版本 1:21 × 21
- 版本 2:25 × 25
- 版本 10:57 × 57
- 版本 20:97 × 97
- 版本 40:177 × 177
容量从版本 1 的几十字节,一路涨到版本 40 的 2953 字节(L 级、字节模式)。生成器会根据你的内容长度自动选最小的够用版本。
这里有两点值得注意:
- 格点数量是边长平方增长的。 版本从 20 涨到 40,边长只多了不到一倍,但格点数多了 3.3 倍。所以高版本二维码的单个格点会非常小。
- 格点太小就扫不出来。 理论上每个格点至少要占 2 到 3 个像素,识别才稳定。如果你的内容太多导致版本冲到 20 以上,打印尺寸又不大,实际很可能扫不出来。
实用结论:让二维码更好扫
想让二维码又清楚又好扫,按这个优先级优化:
- 缩短内容。 这是最有效的手段。网址能短就短,参数能删就删,中间加个短链接跳转是最常见的做法。内容减一半,版本可能降好几级。
- 降低纠错等级。 屏幕展示用 L 或 M,不要无脑用 H。只有需要放 logo 或印在易损材质上才用高等级。
- 保证静区。 二维码四周必须留出至少 4 个格点宽的白边(静区),这是识别算法定位二维码边界用的。裁掉白边是识别失败的头号原因,比清晰度问题更常见。
- 留足像素。 每个格点至少 4 像素比较稳妥,也就是版本 10(57 格)至少要 228 像素宽。
- 别用小字号的位图。 如果一定要在图片里嵌二维码,导出时用足够的分辨率,或者直接用矢量格式(SVG)避免缩放糊掉。
怎么知道自己的二维码有多密
两个办法:
一是生成的时候看工具给出的版本号——版本越低越好扫。如果用二维码生成器,它会显示当前内容占用的版本和字节数,你可以边改内容边看版本变化,直观感受「删掉几个字能降一个版本」。
二是拿现成的二维码去二维码解码看看它的版本、纠错等级和内容类型。如果你看到一个号称很长的内容却是低版本的二维码,多半是内容里有短链接。
两个工具都在浏览器本地运行,生成的图片、上传的图片都不经过服务器。
一句话总结
二维码的密度 = 内容字节数 ÷ 编码效率 + 纠错冗余。 中文按 3 字节算、标点也按 3 字节算,所以中文码天然更密;想变稀疏,最有效的办法是减内容和降纠错等级,而不是换生成工具。