手绘QR码

QRCode

用手机扫描一下,显示“HELLO”。在此声明,没有计算机我是完成不了这个任务的。

首先我当然是阅读教程:QR码编码原理QR Code Tutorial。打格子之类的事情我就不说了。把“HELLO”按混合模式(Alphanumeric Mode)手工编码,从图上看得出来(铅笔写的部分),得32,43,11,120,204,0,236,17,236。于是进入纠错码环节。读了《QR Code Tutorial》的纠错码部分,本来想自己算的,但计算实在太繁杂,不得不用网站提供的工具计算出了纠错码。想学习算法的同学自己看教程。然后,我自编了一个小程序(VB)帮忙把这些数字转为了二进制。数据如下:

32,43,11,120,204,0,236,17,236,109,149,156,18,217,41,246,36,42,84,46,225,190,218,251,27,196

代码如下(中文吓死你!)(其中InputText(2)是输入这些数字,OutputText是输出,可以用Debug.Print之类的代替。这是在我自己做的一个专门用于测试片段代码的vb程序中的输入输出函数):

Private Sub Command1_Click()
    Dim i As Integer, Str() As String
    Str = Split(InputText(2), ",")
    For i = LBound(Str) To UBound(Str)
        OutputText (Format(CLng(进制转换(Str(i), 10, 2)), "00000000"))
    Next
End Sub

Function 进制转换(ByVal 被转换文本 As String, 被转换进制 As Integer, 转换的进制 As Integer) As String '进行转换的子程序
    '转换自易语言例程(易语言例程有时还是很有用的)
    Dim 欲转换文本 As String        '输入的文本串
    Dim 临时文本 As String          '存放从输入的文本串中取出的一个文本
    Dim 临时数值 As Long
    Dim 计次变量1 As Integer
    Dim 计次变量2 As Integer
    Dim 次方数 As Currency          '每一位数字对应的10的次方数
    Dim 转换的进制大数1 As Currency  '要转换的进制-1
    Dim 转换的进制大数 As Currency   '要转换的进制
    Dim 被转换进制大数 As Currency   '被转换的进制
    Dim 临时大数 As Currency        '将被转换数字转换成的大数
    Dim 余数大数 As Currency        '存放求出的余数大数
    Dim 数值1大数 As Currency       '只存放1
    Dim 临时大数1 As Currency       '将被转换数字的每一位转换成的大数
    Dim 临时变量 As Integer
    If 被转换进制 < 2 Or 转换的进制 < 2 Or 被转换进制 > 36 Or 转换的进制 > 36 Then     ' 判断两个“进制系数”是否正确
        进制转换 = "参数错误-进制只能在2-36之间"
        Exit Function
    End If
    被转换文本 = UCase(StrConv(被转换文本, vbNarrow))     ' 规范参数
    For 计次变量1 = 1 To Len(被转换文本)   ' 判断输入的数字文本是否有效
        临时文本 = Mid(被转换文本, 计次变量1, 1)
        If InStr(Left("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", 被转换进制), 临时文本) = -1 Then
            '临时文本 = "参数错误-" & 被转换文本 & "不是一个有效的" & Left(daxie(被转换进制, True), LenB(StrConv(daxie(被转换进制, True), vbFromUnicode)) - 4) & "进制数!"
            临时文本 = "参数错误-" & 被转换文本 & "不是一个有效的" & 被转换进制 & "进制数!"
            Exit For
        End If
        ' 全部查找完毕
        If 计次变量1 = Len(被转换文本) Then
            临时文本 = ""
        End If
    Next

    ' 如果临时文本不为空,说明此数字文本无效!
    If 临时文本 <> "" Then
        进制转换 = "临时文本"
        Exit Function
    End If
    ' 以上为数据正确性校验处理代码

    If 被转换进制 = 转换的进制 Then   ' 相同时,不用进行转换
        进制转换 = 被转换文本
        Exit Function
    End If

    For 计次变量1 = 1 To Len(被转换文本)  ' 先将要转换的数字放入大数中
        次方数 = 1 ' 数值1不能直接和大数类型计算,所以先放入一个大数中
        被转换进制大数 = 被转换进制
        For 计次变量2 = 1 To Len(被转换文本) - 计次变量1        ' 求次方
            次方数 = 次方数 * 被转换进制大数
        Next
        临时变量 = InStr("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", Mid(被转换文本, 计次变量1, 1)) - 1
        临时大数1 = 临时变量
        临时大数1 = 临时大数1 * 次方数
        临时大数 = 临时大数1 + 临时大数  ' 临时大数即为最后转换成的大数
    Next
    转换的进制大数1 = 转换的进制 - 1
    转换的进制大数 = 转换的进制
    数值1大数 = 1 ' 数值1不能直接和大数类型计算,所以先放入一个大数中
    While 临时大数 > 转换的进制大数1    ' 开始进制转换,除进制数取余数
        余数大数 = 临时大数 Mod 转换的进制大数    ' 求出的余数
        临时大数1 = 余数大数 + 数值1大数  ' 求出的余数+1
        临时数值 = CCur(StrConv(临时大数1, vbNarrow))    ' 最后的余数
        欲转换文本 = Mid("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", 临时数值, 1) + 欲转换文本     ' 找出每一个余数对应的数字
        临时大数 = 临时大数 / 转换的进制大数      ' 取出剩余的数字
        临时大数 = Fix(临时大数)
    Wend
    临时数值 = 临时大数    ' 最后剩下的余数
    欲转换文本 = Mid("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", 临时数值 + 1, 1) + 欲转换文本      ' 整数转换结束
    进制转换 = 欲转换文本
End Function

好了,你们想要测试就试一下。输出如下:

00100000
00101011
00001011
01111000
11001100
00000000
11101100
00010001
11101100
01101101
10010101
10011100
00010010
11011001
00101001
11110110
00100100
00101010
01010100
00101110
11100001
10111110
11011010
11111011
00011011
11000100

为了图省事,我用了Mask1(y mod 2 == 0)。从右到左,从下到上,用铅笔点上这些点。我深知这违反了QR码Mask的优选法则,但由于是手绘,有点力不从心。至少手机可以扫描才是目的。手绘一位码简单得多,DM码好像不是很普遍。今天就讲到这儿。有兴趣自己去看那两个教程。最后得出结论:有些事情还是应该交给计算机去做。它们被发明出来就是为了简化人们的工作的。