约 7 分钟读完 · 更新于 2026-10-21 · 文中每条都能在下面的配套工具里动手验证
排查按这个顺序,两分钟能定位。第一,尺寸:模块小于约 2 像素,扫码器或手机根本采样不到有效信息,尤其是屏幕截图后又被压缩过。第二,对比度:浅灰底配深灰码、深色底配深色码都会让自动曝光后的二值化失败,浅底深码最稳。第三,纠错级别:盖了 logo、贴了胶带、被折了一道,错误率超过 L 级(7%)就废了。第四,容量:内容超出所选版本能容纳的字节数,码根本画不出来或画出残缺矩阵。所以生成时不要把这些交给运气,参数一次给对。
| 级别 | 容错率(约) | 模块边长代价 | 什么时候选它 |
|---|---|---|---|
| L | 7% | 最少,密度最高 | 内容长、印在高清介质上、不会被遮挡 |
| M | 15% | 略增 | 通用默认值,屏幕与打印都稳 |
| Q | 25% | 明显增大 | 要加 logo、贴在包装或设备外壳上 |
| H | 30% | 最大,密度最低 | 内容短且环境差:户外、磨损、遮挡面积大 |
二维码有 1-40 共 40 个版本,版本越高模块越多、容量越大,边长按 4(n+17) 模块增长,n 为版本号。粗略换算:字节模式(任意内容,UTF-8 中文按每字 3 字节)从版本 1 的 17 字节到版本 40 的 2953 字节;纯数字最省,版本 1 可放 41 位,版本 40 可放 7089 位;大写字母加数字的字母数字模式介于两者之间,同版本约 25 到 4296 个字符。升一级版本不只是「大一点」——纠错级别和模式都会改变每模块承载的位数,所以先把内容压短,再谈尺寸。URL 里带一串查询参数往往比换更高版本更有效。
| 场景 | 最小模块尺寸 | 整体建议 | 备注 |
|---|---|---|---|
| 屏幕展示(页面 / 屏幕) | 2-3 px | 不小于 120px 见方 | 深色底需要反色码,否则对比度反转 |
| 打印(普通纸 300dpi) | 0.4-0.5 mm | 不小于 20mm 见方 | 静电复印会模糊,宁大勿小 |
| 标签 / 包装印刷 | 0.33 mm | 不小于 12mm 见方 | 避开覆膜反光区,logo 不超 25% 面积 |
| 户外大牌 / 远距离 | 0.8 mm 以上 | 按观看距离放大 | 内容要短,优先用短链或编号 |
const fs = require("fs");
const QR = require("qrcode");
// 每行一个标识;二维码只放短内容,详情放落地页
const codes = fs.readFileSync("assets.csv", "utf8")
.trim().split("\n").slice(1)
.map(r => r.split(",")[0]);
(async () => {
for (const id of codes) {
// 贴到设备上会脏,用 Q 起步;带 logo 直接上 H
await QR.toFile(`out/${id}.png`, `https://s.example.com/d/${id}`, {
errorCorrectionLevel: "Q",
width: 512, // 输出像素,务必是模块尺寸的整数倍
margin: 4, // 静区:约等于 4 个模块,缺了容易扫不出
color: { dark: "#000000ff", light: "#ffffffff" },
});
}
})();1. 把导出的 PNG 拖进解码工具,看能否读回原始 URL 2. 用另一台手机实测,而不是同一台(同一台的解码库可能"将就") 3. 打印一张实物再扫,油墨和覆膜的影响只有实物能测出来 4. 别用微信内置的"扫一扫"当唯一验收标准,它的容错策略偏保守
区别不只是长得不一样。二维码是二维矩阵,容量从几十字节到近 3KB,能存网址、JSON、汉字甚至一段短文本,读取靠手机摄像头,允许 360 度旋转但需要足够的模块尺寸;条形码是一维黑白条,容量通常几十个字符,读取靠激光扫描枪,速度快、允许从任意角度扫,对印刷质量更宽容。所以选型按场景:商品零售、图书馆、仓库这类已有扫码枪流程的用 EAN-13 / UPC / CODE128;需要手机直接扫、需要存 URL 或中文的用二维码;需要手机和扫码枪都能读、又不想换硬件的,条形码更稳。混合方案也常见:外箱印一维条码做物流分拣,内侧印二维码做溯源详情。
页面里最省事的是把 PNG 转成 Base64 data URI 直接内联,省掉一次请求,但要清楚代价:Base64 会让体积增加约三分之一,所以务必先压缩到刚好够扫的尺寸再编码——二维码是纯黑白图形,用调色板化或质量 60 左右的 WebP/JPEG 通常还能再省一半。大量二维码(几百张以上)不要内联,改用打包下载。批量场景记得固定三个参数:纠错级别、模块尺寸、静区,参数不统一会让后续替换某一张时扫不出来的投诉无从复现。
按顺序查四项:模块是否小于 2 像素、对比度是否足够、错误率是否超过纠错级别、内容是否超出容量。最常见的是尺寸太小和背景不够浅——生成时把浅底深码、四模块静区、纠错级别至少设成 M,基本能解决绝大部分场景。
默认选 M。要加 logo 或贴到会被磨损的表面用 Q 或 H(logo 面积别超 25%)。内容很长、印在高清介质上且不会脏,可以用密度最高的 L 省空间。
字节模式从版本 1 的 17 字节到版本 40 的 2953 字节,UTF-8 中文每个字占 3 字节。纯数字最省,版本 40 能放 7089 位;大写字母加数字的混合模式容量居中。实际工程里把内容压到 100 字节以内,一百多像素的码就能稳定扫。
看读取设备:已有扫码枪和固定流程的仓库、零售,用 EAN-13 / CODE128,速度快、对印刷更宽容;需要手机摄像头直接扫,或者要存网址、JSON、中文,用二维码。两者都要支持时,条形码通常更容易同时兼容。