手绘二维码攻略

news/2025/1/16 5:44:09/

提到二维码想必大家都不陌生,扫码支付、添加好友以及关注公众号等,随处可见二维码身影。通常我们见到的二维码会有三个用于定位的黑白嵌套的方块,这基本上就是 QR 二维码(Quick Response Code)。

 

今天我们就手动编码生成一个可以被识别的二维码~

初次尝试,我们把要编码的文本设置得简单些:"HELLO WORLD",只包含大写字母和空格。相应地,我们要采用 QR 二维码中较为简单的字符编码模式来将信息转化为一串由 1 和 0 组成的数据编码。

QR 二维码中有版本和纠错级别的概念,这里我们选用版本 1-M,即版本 1,纠错级别 M,编码模式选用字节编码。

首先得到编码模式指示符:字节编码对应 0100

其次计算文本信息中字符数,"HELLO WORLD" 10 个字母 1 个空格共计 11 个字符,转化为 9 位的二进制串:000001011

字符编码

接下来我们进入字符编码,先把文本字符分成两两一组:

HE,LL,O空格,WO,RL,D

根据字符索引表查得每个字符对应的索引值:

然后将每组中第一个字符索引值乘以 45 加上第二个字符索引值,将结果转化为 11 位的二进制数,不足 11 位在左侧补 0 以达到长度。

HE 对应 779 转化为 01100001011

LL 最终转化为 01111000110

O空格 最终转化为 10001011100

WO 最终转化为 10110111000

RL 最终转化为 10011010100

如果要转化的是奇数位字符,那么最后单独的字符这一组将转化为 6 位二进制位:

D 对应 13 转化为 001101

二维码数据编码

这样我们得出了 61 位的字符编码。根据 QR 二维码规范,版本 1-M 的二维码需要 128 位长度的数据来填充,目前我们有 4 位编码指示符(0100),9 位字符计数符(000001011) ,和 61 位的字符编码,共计 74 位,还差 54位。

接下来由于差 54 位,很明显大于 4,所以要添加一个 4 位的终止符 0000。这样长度来到了 78 位,接下来我们要继续补 0 使得长度恰好为 8 的整倍数,这里要继续补 2 个 0 得到 80 位。换言之,在本段中相当于在之前 74 位字符后加了 6 位的 0:000000,目前以达 80 位长度。

接下来的规则是在其后交替添加 11101100 和  00010001 直到字符长度达到 128 位。80 位 到 128 位差 48 位,需要交替添加 6 次上述字符串,即在其后添加 11101100  00010001 11101100 11101100  00010001 11101100。

最终我们可以得到 QR 二维码所需的 128 位数据编码:

00100000 01011011 00001011 01111000 11010001 01110010 11011100 01001101 01000011 01000000 11101100 00010001 11101100 11101100  00010001 11101100

纠错码

将之前产生的 128 位数据编码每 8 位一组,每组转化为 10 进制数字,由此得到 16 个数字:

32, 91, 11, 120, 209, 114, 220, 77, 67, 64, 236, 17, 236, 17, 236, 17

将其作为信息多项式系数,得到信息多项式:

32 * x^15 + 91 * x^14 + ... + 17 * x^0

由 QR 二维码规范或者相关小工具查得,1-M 二维码需要 10 个纠错码,对应的生成多项式如下:

通过信息多项式与生成多项式除法(过程较复杂,详情可见《QR 二维码纠错码(三)》),我们可以得到 10 个纠错码:

196  35  39  119  235  215  231  226  93  23

转化为 10 个 8 位二进制:

11000100 00100011 00100111 01110111 11101011 11010111 11100111 11100010 01011101 00010111

至此,我们已经得到 128 位数据编码,80 位纠错码。

开始手绘

二维码说白了就是在一系列方格中填充黑白块,版本 1-M QR二维码是 21 x 21 单位的方格集合。为了在电脑端手绘,我采用 Excel 表格来模拟绘制。原理也很简单,打开空白表格,将行高和列宽设置成相同,挑选出 21 x 21 的方格区域作为 QR 二维码绘制区域。

首先向其中左上、左下和右上角添加定位模块、隔离模块、时间模块和黑色码元,以及蓝色标注的预留信息区域:

 

以上标注的黑、白、蓝色区域在 QR 版本 1 的二维码中是固定的,蓝色区域等待之后填充格式信息,浅绿色区域即我们之前得到的 128 位数据编码和 80 位纠错码要填充的区域,我们可以计算下在这 21 x 21 = 441 个格子里,目前黑白蓝色已占据了 233 个,恰好剩余 208 个位置填充数据相关信息。

接下来按照图示红色路线从右下角开始填充这 208 位二进制(因为图示以版本 3 为例,我们的版本 1 更简略):

经过一番填充,进展如下:

预留格式信息

目前只剩蓝色区域的预留格式信息尚未填充,这里预留格式信息需要选择二维码的掩码模式,选定掩码模式后,需要按照掩码规则对该二维码特定位置的单元格进行修改变换。

其实按流程,我们需要将 8 中掩码模式都采用并生成结果二维码,然后根据一个损失评分挑选其中损失分最低的掩码模式。

这里我们随机选择掩码模式 0。根据 QR 二维码的格式版本信息表查得,纠错级别 M、掩码模式 0 情况下的格式信息15 位二进制为 101010000010010。

将 15 位格式信息按照下图 0 到 14 的顺序依次填入二维码表中:

填充完毕如图:

 

掩码

最后一步,掩码。我们采用的掩码模式 0,即对行和列之和为偶数的坐标点进行变换,例如 [0,0] [1,1] [0,3] [1,3]等坐标点处,若之前为白色则转为黑色,若之前为黑色则转为白色。

掩码只对我们填充的 208 为数据编码和纠错码进行处理,其余预先填好的功能模块和预留区域都不受掩码影响。

经过掩码处理后的 QR 二维码结果如图:

用微信扫一扫,得到扫描结果 "HELLO WORLD",成功~!


http://www.ppmy.cn/news/660351.html

相关文章

springboot实现控制层返回二维码,扫描后打开PDF文件

公司要求是弹出一个二维码,扫描二维码后进入对应的PDF文件, 一. google ZXing 简介 Java 操作二维码的开源项目很多,如 SwetakeQRCode、BarCode4j、Zxing 等等 本文将介绍简单易用的 google 公司的 zxing,zxing 使用方便&#xff…

让你的电脑也识得二维码图片(二)

让你的电脑也识得二维码图片(二) 继续主要问题获取图片 新的思路实现右键最后 继续 之前写了一份能够让电脑识别二维码图片的脚本,详细参见《让你的电脑也识得二维码图片(一)》 虽然已经可以做到比较方便的识别电脑上…

如何在线解决微信扫二维码无法打开网页的难题

场景分析 当我们在微信内分享链接或二维码的时候,我们会发现我们的网站是可以在浏览器里正常打开的,但就是不能在微信里打开,提示 “ 已停止访问该网页 ”,无论是聊天框也一样。说是系统检测到您的网址被微信策略屏蔽&#xff0c…

【javascript】浏览器调用摄像头扫二维码踩坑记录

前言 最近做一个项目需要用浏览器调用摄像头扫二维码,然后就踩了几个坑记录下。 踩坑记录 我一开始发现了zxing这个库,他分为https://www.npmjs.com/package/zxing/library 与 https://www.npmjs.com/package/zxing/browserzxing/browser是最近才建立…

原生小程序使用二维码扫码调用接口

1、点击扫码直接打开文件&#xff0c;通过二维码得到了个后台反的url地址(https://....?参数值&参数值)&#xff0c;把地址的参数拿取出来&#xff0c;之后调用接口就完成了&#xff0c;如果是和我一样操作的&#xff0c;建议复制。 //按钮样式跳转扫码 <button class…

iOS开发——扫二维码下载APP

注意&#xff1a;苹果手机只有UDID被加入到开发者的设备中之后才可以扫描二维码安装否则不能安装&#xff0c;如果没有请将UDID加入到开发者设备中重新下载证书点击运行就可以了&#xff08;电脑证书不用动&#xff09;。 查看苹果设备UDID并添加到开发者账号设备目录请查看我这…

微信二维码扫码登录的原理

扫二维码登录现在比较常见&#xff0c;比如微信、支付宝等 PC 端登录&#xff0c;并且越来越多的APP支持扫码登录&#xff0c;其中原理如何呢&#xff1f; PC端Cookie Session 登录 HTTP 是一种无状态的协议&#xff0c;客户端每次发送请求时&#xff0c;首先要和服务器端建立…

扫二维码时判断手机是安卓还是IOS

1.使用情景&#xff0c;有个需要扫描二维码下载的APP&#xff0c;需要区分IOS和安卓&#xff0c;跳转到相应的下载链接去 var browser { versions: function() { var u navigator.userAgent, app navigator.appVersion; return { trident: u.indexOf(Trident) > -1, //I…