让我们开发一个二维码生成器,第一部分:基本概念

2025-06-09

让我们开发一个二维码生成器,第一部分:基本概念

最近,我正在开发一款小型的益智网页游戏,我觉得如果大家能用二维码这样常见的分享方式来分享谜题,那一定很酷。毕竟,基于 Chromium 的浏览器自 2020 年 5 月 v83 发布以来就支持条形码检测 API,既然有这个 API,为什么不用呢?

可惜的是,这个 API 只能读取二维码(这确实是最难的部分),无法生成二维码,所以我们只能自己动手了。这能有多难?!

哦天哪。

让我们深入研究一系列相当先进的数学概念和一系列从“几乎合理”到看似“完全荒谬”的规则,最终创造出一堆单色像素。

为了方便本系列文章,我们将专注于二维码的生成,暂不讨论检测。我们还将开始研究更简单的 8 位字符短码情况。

dev.to 主页的二维码

数据类型

二维码确实包含数据,这是可以理解的。数据类型可以确定,但它当然也决定了二维码能够存储的最大信息量:

  • 数字(最多 7089 个);
  • 字母数字(数字、大写字母、一堆符号:比数字贵约 65%);
  • 字节(仅 8 位 Latin-1 编码字符,价格贵约 140%);
  • 汉字(价格贵约 290%)。

汉字是主要符号集之一并不奇怪,因为二维码是由日本自动化公司 Denso Wave 开发的。

实际上,在较新的版本中还有其他编码模式,但如前所述,我们现在将重点介绍 8 位字节。归根结底,二维码是由一系列位组成的——因此,如果您想按自己的意愿对信息进行编码,完全可以。

另外,二维码还可以在数据中途切换不同的编码模式,但我们暂时不考虑这种情况。

尺寸

QR 码始终为正方形,但其大小会有所不同。其大小由不常见的术语“版本”决定,因此版本 1 的大小为 21×21 像素,而版本 40(最大的版本)的大小为 177×177 像素。版本 1 的 QR 码宽度和高度分别增加了 4 像素,因此其大小为 (17 +版本* 4) 像素。

此外,我们不应该称它们为像素,而应该称它们为“模块”(同样,这很不寻常,但也许是日语翻译时丢失了一些东西)。

由于二维码越大越难解码(计算成本也越高),因此我们的目标是针对我们想要存储的数据量使用尽可能小的“版本”。

较大的二维码将其数据分成多个块(最多 81 个)。

错误纠正

每个二维码都包含纠错“模块”——我们无法移除它们以最大化可用空间。但我们可以选择四种级别的纠错方式:

等级 数据恢复
低的 ~7%
中等的 ~15%
四分位数 ~25%
高的 ~30%

更高级别的错误修正可能会被滥用来创建部分被徽标和图片覆盖的二维码,但由于错误修正,二维码仍然可以读取。

我的 GitHub 主页的二维码仍然可读,中间有 GitHub 的标志

固定模式

我们中的许多人一眼就能认出二维码,这是因为二维码具有一些共同的特征:

  • 它们是方形的图片;
  • 它们是黑色和白色的——或者至少是亮度光谱中两种非常遥远的颜色(所以我们将它们称为“暗”和“亮”);
  • 它们由方点网格组成;
  • 图片周围有一些容易识别的图案。

关于最后一个,易于识别的重点正是它们被这样设计的原因:让我们记住,QR(=快速响应)代码已经开发用于工业自动化机器。

这些模式是:

  • 定位图案:位于左上角、右上角和左下角的 7×7 方块,由一行空模块隔开;二维码,其中定位图案以绿色突出显示
  • 对准图案:放置在n × n网格的角落和交叉点上的 5×5 方格(除非被定位图案占据);n 的范围在 2 到 6 之间,因此共有n 2 - 3 个对准图案,但版本 1 除外,因为它没有对准图案;对齐图案以红色突出显示的二维码
  • 时间图案:一条水平和一条垂直的交替暗模块线,连接定位图案(只有深入检查一些二维码才会注意到这一点);带有绿色突出显示的时间模式的二维码
  • 一个暗模块:只是一个始终暗的模块,放置在第 9 列和 (4 *版本) + 10) 行(我敢打赌你从来没有注意到它!)。带有红色圆圈的深色模块的二维码

此外,在较大的二维码(从版本 7 开始)中,有几个区域是为格式数据保留的。

容量

给定版本、编码模式和纠错级别,二维码的容量就确定了。未被固定图案或保留区域占用的可用空间被划分为 8 个模块组,这些模块称为“码字”:可以将其视为经典的 8 位字节。

因此,每个版本的总可用代码字数是固定的:版本 1 为 26 个,版本 2 为 44 个,依此类推,版本 40 最多为 3706 个。

对于每个版本,为纠错保留的代码字也是确定的,可以在像这样的表中找到。

不用多说,让我们开始构建一些小型二维码,使用 ISO-8859-1 字节编码!

等一下,ISO-8859-1?

是的,二维码使用ISO-8859-1(也称为 Latin-1)来编码字节串。如今 UTF-8 更为常见,但不久前还不常见。

这里的基本问题是,UTF-8 可以包含数百万个字符(或“代码点”),而 Latin-1 只有 255 个符号。仅此而已。没有表情符号,也没有其他字母。如果您想检查一个字符串是否对 Latin-1 有效,检查很简单:



const LATIN1_RE = /^[\x00-\xff]*$/;
function isLatin1(string) {
  return LATIN1_RE.test(string);
}


Enter fullscreen mode Exit fullscreen mode

如果某些字符符合 ISO-8859-1 标准,那么……你要么丢弃它们,要么使用 ECI 模式。此外,有些二维码读取器会自动识别是否使用了 UTF-8 编码,但对于公共二维码来说,这可能不是一个可靠的选择。

保持联系以了解下一部分:编码数据!

鏂囩珷鏉ユ簮锛�https://dev.to/maxart2501/let-s-develop-a-qr-code-generator-part-i-basic-concepts-510a
PREV
BeautifulSoup 是 2000 年及以后的产物:2020 年的网页抓取 1. 无依赖项 2. 内置电池 4. 从原型设计到生产 5. 符合 PEP 561 6. 自动格式化 7. 速度 8. 部分匹配 9. 无债务 10. 开放(且友好)!
NEXT
关于 async/await 和 Promises 的陷阱