二维码扫不出来怎么办:纠错级别、模块尺寸与印刷的硬约束

扫不出只有四类原因:模块太小、对比度不足、纠错级别不够、内容超容量。讲清 L/M/Q/H 分别能遮住多少、版本与容量的换算、条码和二维码怎么选,以及批量生成与嵌入页面的实际做法。

约 7 分钟读完 · 更新于 2026-10-21 · 文中每条都能在下面的配套工具里动手验证

结论先行:扫不出只有四类原因

排查按这个顺序,两分钟能定位。第一,尺寸:模块小于约 2 像素,扫码器或手机根本采样不到有效信息,尤其是屏幕截图后又被压缩过。第二,对比度:浅灰底配深灰码、深色底配深色码都会让自动曝光后的二值化失败,浅底深码最稳。第三,纠错级别:盖了 logo、贴了胶带、被折了一道,错误率超过 L 级(7%)就废了。第四,容量:内容超出所选版本能容纳的字节数,码根本画不出来或画出残缺矩阵。所以生成时不要把这些交给运气,参数一次给对。

纠错级别 L / M / Q / H 分别能盖住多少

级别容错率(约)模块边长代价什么时候选它
L7%最少,密度最高内容长、印在高清介质上、不会被遮挡
M15%略增通用默认值,屏幕与打印都稳
Q25%明显增大要加 logo、贴在包装或设备外壳上
H30%最大,密度最低内容短且环境差:户外、磨损、遮挡面积大

容量与版本:内容越长,码越大

二维码有 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 或中文的用二维码;需要手机和扫码枪都能读、又不想换硬件的,条形码更稳。混合方案也常见:外箱印一维条码做物流分拣,内侧印二维码做溯源详情。

二维码中间能加 logo 吗

  • 可以,但要用 H 级(30% 容错)并把 logo 面积控制在总面积的 25% 以内。
  • logo 必须是正方形、四边留出完整的定位图案(三个角上的方块),别压住它们。
  • logo 背景要与模块颜色一致,不要用渐变或半透明,边缘留一圈白色更稳。
  • 内容越长,同样的 logo 占比对应的实际遮挡越严重——长内容建议去掉 logo。

嵌入页面与压缩

页面里最省事的是把 PNG 转成 Base64 data URI 直接内联,省掉一次请求,但要清楚代价:Base64 会让体积增加约三分之一,所以务必先压缩到刚好够扫的尺寸再编码——二维码是纯黑白图形,用调色板化或质量 60 左右的 WebP/JPEG 通常还能再省一半。大量二维码(几百张以上)不要内联,改用打包下载。批量场景记得固定三个参数:纠错级别、模块尺寸、静区,参数不统一会让后续替换某一张时扫不出来的投诉无从复现。

常见问题

二维码为什么扫不出来?

按顺序查四项:模块是否小于 2 像素、对比度是否足够、错误率是否超过纠错级别、内容是否超出容量。最常见的是尺寸太小和背景不够浅——生成时把浅底深码、四模块静区、纠错级别至少设成 M,基本能解决绝大部分场景。

二维码 L、M、Q、H 怎么选?

默认选 M。要加 logo 或贴到会被磨损的表面用 Q 或 H(logo 面积别超 25%)。内容很长、印在高清介质上且不会脏,可以用密度最高的 L 省空间。

二维码最多能存多少字?

字节模式从版本 1 的 17 字节到版本 40 的 2953 字节,UTF-8 中文每个字占 3 字节。纯数字最省,版本 40 能放 7089 位;大写字母加数字的混合模式容量居中。实际工程里把内容压到 100 字节以内,一百多像素的码就能稳定扫。

条形码和二维码我该用哪个?

看读取设备:已有扫码枪和固定流程的仓库、零售,用 EAN-13 / CODE128,速度快、对印刷更宽容;需要手机摄像头直接扫,或者要存网址、JSON、中文,用二维码。两者都要支持时,条形码通常更容易同时兼容。

📂

松开以自动格式化

支持 .json / .sql / .csv / .html / .css / .xml / .yaml 文件