使用方法
- 点「选择图片」,挑一张包含二维码的图片,格式可以是 PNG、JPG、WebP、BMP 或 GIF,文件不能超过 5MB(5242880 字节)。
- 点「识别图片中的二维码」。识别在浏览器本地完成,图片不会被上传,断网状态下这一步照常能跑。
- 看结果区:识别成功时,表格逐行列出每个码的内容、字符数和 UTF-8 字节数;下方的文本框是所有内容的纯文本,方便直接复制。
- 点「复制识别结果」把纯文本带走,或点「导出 CSV」存成带表头的表格文件(带 BOM,Excel 打开不乱码)。
- 识别失败时看红色提示:它会写清是文件超了 5MB、不是图片,还是画面里没有检测到二维码,按提示处理后重试。
这个二维码读取上传能解决什么问题
一是读图不扫码:二维码出现在截图、聊天记录、PDF 导出页里,手机相机对着屏幕扫常常失灵,把截图存下来上传,一次就能读出内容。
二是先看内容再决定要不要打开:二维码读取上传的输出是纯文本,解出来的网址原样摆在你眼前,不会自动跳转。遇到来路不明的码,先看清域名再动手,是避开钓鱼页的第一道检查。
三是读出非网址内容:Wi-Fi 分享码解出来是 WIFI:T:WPA;S:HomeWiFi;P:pass1234;; 这样的配置串(34 个字符),电话码是 TEL:+8601012345678(18 个字符),从里面直接抄 SSID 和密码,比再装一个扫码 App 省事。
四是批量核对:打印物料上的二维码是否扫得出来、内容是否正确,把样品拍照上传就能核对,不用逐个拿设备扫。
本页不做这些事:不生成二维码(那是「二维码生成器」的活,两者互为逆操作)、不解一维条形码(EAN-13 之类的码请用「条形码读取上传」)、不调用摄像头实时取景(怀疑摄像头坏了可以用「摄像头测试」先查设备)。
原理与规则说明:BarcodeDetector 与画布预处理
解码调用的是浏览器内置的 BarcodeDetector 接口(W3C Shape Detection API 的一部分),不是页面自带的解码算法。构造时传 { formats: ['qr_code'] },只登记二维码这一种格式;随后把图片传给 detect(),它返回一个 Promise,兑现为数组,每个元素带 rawValue(解码出的文本)字段。数组可能不止一个元素——一张图里印了几个二维码,就逐行出几条结果。
上传的文件先走三条校验:文件为 0 字节直接拒绝;超过 5242880 字节(5MB)拒绝;类型不是 image/ 开头也不是常见图片扩展名拒绝。通过后再经 URL.createObjectURL 交给 Image 解码,画到 canvas 上。画布有 4096 像素的边长上限:原图更大时等比缩小,例如一张 8000×6000 的照片,缩放因子是 4096÷8000 = 0.5120,画布实际为 4096×3072。上限的道理是内存——解码后的位图每像素占 4 字节,4096×4096 = 16777216 个像素就是 64MB,再大就会让低配设备卡顿。
为什么 5MB 和 4096 这两个数字取在这里:条码检测对相对尺寸敏感而不是绝对尺寸,手机照片动辄 12MP 以上,等比缩到 4096 边长以内不损失可识别性,却把计算量压掉了九成以上。实测经验是二维码边长不小于画面短边的 44.7%(即约占画面面积五分之一)时识别最稳。
浏览器不支持 BarcodeDetector 时,本页给出降级提示而不是硬解——手写一个 QR 解码器要实现伽罗瓦域纠错、掩码评分等一整套规范,体积远超本站的内联脚本预算,所以不支持的环境会明确告诉你换 Chrome、Edge 等 Blink 内核浏览器打开。
完整示例(数值仅作演示)
示例文件 demo-qr.png 里印着一个二维码,内容是本站二维码生成器的地址:
- 解码内容:
https://liuquan.net/shengchengqi/erweimashengchengqi/; - 53 个字符,全部是 ASCII,UTF-8 编码后也是 53 字节——纯英文网址字符数与字节数相等;
- 按上面的规则,这个内容如果重新生成二维码,模块规模在版本 1~2 之间就够了(见下面的对照表)。
工具区那段「示例展示」就是按这份演示数据写好的,打开页面即可看到结果长什么样;上传真实图片并识别成功后,它会被真实结果替换。若你把这个地址复制进「二维码生成器」再上传回来,识别结果应与原地址逐字符一致——这就是生成与读取互为逆操作的直观验证。
输入范围与对照表
文件侧的限制汇总如下:
| 检查项 | 允许范围 | 超界行为 |
|---|---|---|
| 文件大小 | 1 ~ 5242880 字节(5MB) | 0 字节提示空文件;超出提示实际字节数与上限 |
| 文件类型 | PNG、JPG、WebP、BMP、GIF | 非图片类型提示实际 MIME 类型 |
| 画布边长 | 最长边缩放到 4096 像素内 | 更大的图等比缩小后识别 |
| 二维码数量 | 1 张图内多个码都识别 | 逐行列出,互不干扰 |
| 识别结果 | 纯文本(rawValue 原样输出) | 不自动打开链接、不执行任何内容 |
二维码本身的规格由 ISO/IEC 18004 定义,40 个版本按「边长 = 21 + 4 ×(版本号 − 1)」递增:
| 版本 | 模块边长 | 总格数 | 典型用途 |
|---|---|---|---|
| v1 | 21 × 21 | 441 | 十几个字符的短网址 |
| v2 | 25 × 25 | 625 | 普通网址、名片项 |
| v5 | 37 × 37 | 1369 | 带参数的推广链接 |
| v10 | 57 × 57 | 3249 | Wi-Fi 配置串、长文本 |
| v25 | 117 × 117 | 13689 | 整段说明文字 |
| v40 | 177 × 177 | 31329 | 规格上限,接近容量极限 |
版本越高格越密,对拍摄清晰度的要求也越高,正文内容超过几百字节时应该换短链接而不是追求高版本。
输入范围、边界与精度说明
- 0 字节与超 5MB 是硬拒绝,提示里带实际数字:空文件通常是导出中断造成的,超限的常见原因是原图直出,截图或另存为 JPG 后一般能压进 5242880 字节以内。
- 「不是图片」看两个信号:MIME 类型不是
image/开头、且扩展名也不在白名单里才拒绝,两者满足其一即放行——很多系统给截图返回空的类型标记,不能一刀切。 - 识别不出不等于码坏了:检测对对比度、清晰度和占比敏感,先裁剪掉无关背景再试;反光、褶皱、二维码边角被裁掉是最常见的三个原因。
- 多个码会全部列出,但同一位置重叠的码只会出一个结果;结果顺序跟检测器返回顺序一致,不代表画面里的排版顺序。
- rawValue 是字节流的 UTF-8 解读:码里存的是中文字符时能正常还原;存的是私有协议(例如某些支付码)时解出来是一串没有可读性的字符,这属于正常现象,不代表解码失败。
- 不支持的环境不会假装支持:Firefox、Safari 目前没有实现 Shape Detection API,页面会在你点识别时给出降级提示,而不是返回一个可疑的空结果。
- 本页不保留任何记录:二维码读取上传的图片经临时 URL 解码后立刻释放,刷新页面结果清空,开发者工具的 Network 面板里看不到任何图片外发请求。
常见问题
为什么 Firefox 和 Safari 打开这个页会提示不支持?
本页解码依赖浏览器原生 BarcodeDetector(Shape Detection API),目前 Chrome、Edge 等 Blink 内核浏览器实现了它,Firefox、Safari 还没有。页内不引第三方解码库、也不手写解码器,所以检测不到接口时直接说明情况并建议换浏览器,而不是给出不可靠的结果。
为什么限制 5MB?我手机拍的照片普遍比这大。
限制针对的是解码位图的内存:图片缩放到最长边 4096 像素后,16777216 个像素每像素 4 字节,约 64MB,已经够低配设备消化。原图超出 5242880 字节时,用系统截图工具截二维码区域,或另存为 JPG,几乎总能压进限制,且识别率反而更高。
一张图里有多个二维码,能一次全读出来吗?
能。detect() 返回数组,有几个码就出几行,每行带各自的字符数与字节数。但靠得太近或部分重叠的码可能只识别出一个,需要分开截图逐个读。
解出来的网址会自动打开或跳转吗?
不会。结果区是纯文本,本页没有绑定任何跳转行为。要访问时自己复制到地址栏,这正是「先看清再打开」的设计意图;解出 %E4 之类的百分号串时先用 URL 解码工具还原成中文再看。
Wi-Fi 码解出来那串分号是什么意思?
那是 WXF 规范定义的 WIFI: 格式:T 是认证方式,S 是网络名,P 是密码,双分号收尾。工具解出原文后你直接照抄 S 和 P 两段即可,不需要再处理。
付款码、微信码这类也能解吗?
格式上它们也是二维码,能解出内容,但内容是各家私有协议的编码串,没有可读性。解出来通常只能看到一长串字母数字,这是正常的——这类码本来就不是给通用解码器读的。
为什么识别率比手机相机扫码差一些?
相机扫码有取景框引导和连续帧尝试,几十帧里挑最清晰的一帧;本页只有你上传的这一张静态图。裁剪紧凑、光线均匀、码占比不低于画面面积五分之一的图,识别效果接近相机。
识别结果会被上传或保存吗?
不会。文件经浏览器临时 URL 在本地解码,Network 面板全程没有外发请求,刷新后结果清空。想长期留存用「导出 CSV」自己存文件。