简单解析微信、支付宝,付款码的条形码生成原理

最近做了一个项目,其中用到了条形码的生成,为了避免时间太长自己忘记相关的知识点,同时也为了方便给后来人减少一些坑,所以就先用这篇文章做一个简单的记录。
by chenxublog.com

付款码用的条形码编码规则

条形码编码规则有不少,付款码现在用的是Code128编码规则。

Code128编码的特性

  • 具有A、B、C三种不同的编码类型,可提供标准ASCII中128个字元的编码使用

  • 允许双向扫描(正着反着都能扫)

  • 可自行决定是否加上检验位(但付款码必须要校验位)

  • 条码长度可调,但包括开始位和结束位在内,不可超过232个字元(付款码也就十几二十位数字)

  • 同一个128码,可以由A、B、C三种不同编码规则互换,既可扩大字元选择的范围,也可缩短编码的长度(这点十分重要,后面会讲到)

优先选用的编码规则

由于编码规则越复杂,二维码就越复杂,所以条形码编码优先使用的是Code128C这个编码规则。

Code128C将数字两个两个组合在一起,大大减小了条码的复杂度。

code128的编码规则

为了方便表达,我们用b代表一条黑色像素宽度的线,s代表一条白色像素宽度的线,当bs组合时,中间不留任何缝隙

ABC三种编码的编码表如下,后面会用到这张表:

IDCode128ACode128BCode128CBandCode编码值
0SP SP0212222bbsbbssbbss
1!!1222122bbssbbsbbss
22222221bbssbbssbbs
3##3121223bssbssbbsss
4$$4121322bssbsssbbss
5%%5131222bsssbssbbss
6&&6122213bssbbssbsss
77122312bssbbsssbss
8((8132212bsssbbssbss
9))9221213bbssbssbsss
10**10221312bbssbsssbss
11++11231212bbsssbssbss
12,,12112232bsbbssbbbss
1313122132bssbbsbbbss
14..14122231bssbbssbbbs
15//15113222bsbbbssbbss
160016123122bssbbbsbbss
171117123221bssbbbssbbs
182218223211bbssbbbssbs
193319221132bbssbsbbbss
204420221231bbssbssbbbs
215521213212bbsbbbssbss
226622223112bbssbbbsbss
237723312131bbbsbbsbbbs
248824311222bbbsbssbbss
259925321122bbbssbsbbss
26::26321221bbbssbssbbs
27;;27312212bbbsbbssbss
28<<28322112bbbssbbsbss
29==29322211bbbssbbssbs
30>>30212123bbsbbsbbsss
31??31212321bbsbbsssbbs
32@@32232121bbsssbbsbbs
33AA33111323bsbsssbbsss
34BB34131123bsssbsbbsss
35CC35131321bsssbsssbbs
36DD36112313bsbbsssbsss
37EE37132113bsssbbsbsss
38FF38132311bsssbbsssbs
39GG39211313bbsbsssbsss
40HH40231113bbsssbsbsss
41II41231311bbsssbsssbs
42JJ42112133bsbbsbbbsss
43KK43112331bsbbsssbbbs
44LL44132131bsssbbsbbbs
45MM45113123bsbbbsbbsss
46NN46113321bsbbbsssbbs
47OO47133121bsssbbbsbbs
48PP48313121bbbsbbbsbbs
49QQ49211331bbsbsssbbbs
50RR50231131bbsssbsbbbs
51SS51213113bbsbbbsbsss
52TT52213311bbsbbbsssbs
53UU53213131bbsbbbsbbbs
54VV54311123bbbsbsbbsss
55WW55311321bbbsbsssbbs
56XX56331121bbbsssbsbbs
57YY57312113bbbsbbsbsss
58ZZ58312311bbbsbbsssbs
59[[59332111bbbsssbbsbs
60\\60314111bbbsbbbbsbs
61]]61221411bbssbssssbs
62^^62431111bbbbsssbsbs
63__63111224bsbssbbssss
64NUL`64111422bsbssssbbss
65SOHa65121124bssbsbbssss
66STXb66121421bssbssssbbs
67ETXc67141122bssssbsbbss
68EOTd68141221bssssbssbbs
69ENQe69112214bsbbssbssss
70ACKf70112412bsbbssssbss
71BELg71122114bssbbsbssss
72BSh72122411bssbbssssbs
73HTi73142112bssssbbsbss
74LFj74142211bssssbbssbs
75VTk75241211bbssssbssbs
76FFI76221114bbssbsbssss
77CRm77413111bbbbsbbbsbs
78SOn78241112bbssssbsbss
79SIo79134111bsssbbbbsbs
80DLEp80111242bsbssbbbbss
81DC1q81121142bssbsbbbbss
82DC2r82121241bssbssbbbbs
83DC3s83114212bsbbbbssbss
84DC4t84124112bssbbbbsbss
85NAKu85124211bssbbbbssbs
86SYNv86411212bbbbsbssbss
87ETBw87421112bbbbssbsbss
88CANx88421211bbbbssbssbs
89EMy89212141bbsbbsbbbbs
90SUBz90214121bbsbbbbsbbs
91ESC{91412121bbbbsbbsbbs
92FS|92111143bsbsbbbbsss
93GS}93111341bsbsssbbbbs
94RS~94131141bsssbsbbbbs
95USDEL95114113bsbbbbsbsss
96FNC3FNC396114311bsbbbbsssbs
97FNC2FNC297411113bbbbsbsbsss
98SHIFTSHIFT98411311bbbbsbsssbs
99CODECCODEC99113141bsbbbsbbbbs
100CODEBFNC4CODEB114131bsbbbbsbbbs
101FNC4CODEACODEA311141bbbsbsbbbbs
102FNC1FNC1FNC1411131bbbbsbsbbbs
103StartAStartAStartA211412bbsbssssbss
104StartBStartBStartB211214bbsbssbssss
105StartCStartCStartC211232bbsbssbbbss
106StopStopStop2331112bbsssbbbsbsbb

对于某种条码的编码规则为:

开始位 + 后面所有的数据按顺序拼接 + 校验位 + 结束位

编码的103-106为起始位于结束位,只会在开头或结尾出现

我们首先使用一个简单的例子来解释如何使用三种编码方式进行条形码的编码:

需要编码成条形码的数据:1346

对于Code128A编码:

起始位(StartA:bbsbssssbss)+
数据位(Code128A中的1:bssbbbssbbs)+
数据位(Code128A中的3:bbssbsbbbss)+
数据位(Code128A中的4:bbssbssbbbs)+
数据位(Code128A中的6:bbssbbbsbss)+
校验位((StartA的id + Code128A中的1的id*1 + Code128A中的3的id*2 + Code128A中的4的id*3 + Code128A中的6的id*4) % 103 = (103 + 17*1 + 19*2 + 20*3 + 22*4) % 103 = 自己算去吧:Code128A中对应的id值所表示的编码)
停止位(Stop:bbsssbbbsbsbb)

对于Code128B编码:

B类编码和A几乎完全一样,只有起始位和校验位所使用的开头不一样:

起始位(StartB:bbsbssbssss)+
数据位(Code128B中的1:bssbbbssbbs)+
数据位(Code128B中的3:bbssbsbbbss)+
数据位(Code128B中的4:bbssbssbbbs)+
数据位(Code128B中的6:bbssbbbsbss)+
校验位((StartB的id + Code128B中的1的id*1 + Code128B中的3的id*2 + Code128B中的4的id*3 + Code128B中的6的id*4) % 103 = (104 + 17*1 + 19*2 + 20*3 + 22*4) % 103 = 自己算去吧:Code128B中对应的id值所表示的编码)
停止位(Stop:bbsssbbbsbsbb)

对于Code128C编码:

Code128C编码时,只能编码数字内容,并且在编码前会将偶数个的数字两个两个分为一组,进行编码:

起始位(StartC:bbsbssbbbss)+
数据位(Code128C中的13:bssbbsbbbss)+
数据位(Code128C中的46:bsbbbsssbbs)+
校验位((StartC的id + 数据位1*1 + 数据位2*2) % 103 = (105 + 13*1 + 46*2) % 103 = 自己算去吧:Code128C中对应的值所表示的编码)
停止位(Stop:bbsssbbbsbsbb)

这时候就应该可以明白,为什么付款码优先使用的是Code128C编码了。

实际的例子

95270078用Code128A表示的结果为:

bbsbssssbss开头
bbbssbsbbss数据位
bbsbbbssbss数据位
bbssbbbssbs数据位
bbbsbbsbbbs数据位
bssbbbsbbss数据位
bssbbbsbbss数据位
bbbsbbsbbbs数据位
bbbsbssbbss数据位
bbsbbbssbss校验位
bbsssbbbsbsbb停止位

即:bbsbssssbssbbbssbsbbssbbsbbbssbssbbssbbbssbsbbbsbbsbbbsbssbbbsbbssbssbbbsbbssbbbsbbsbbbsbbbsbssbbssbbsbbbssbssbbsssbbbsbsbb

实际使用

在实际按此方法使用的过程中,也遇到了一个坑,下面就简单讲一下这个坑人的地方

生成偶数位数字的条形码

这个简单,直接用Code128C编码方式编码即可,不再重复说明

生成奇数位数字的条形码

这个需求在一开始听到之后,我是十分疑惑的:完全不可能嘛!Code128C编码怎么可能生成一个奇数位数字的条形码呢?

不过在bing中翻阅过不少资料后,发现这个是可行的,原因在文章开头也讲到了:

同一个128码,可以由A、B、C三种不同编码规则互换,既可扩大字元选择的范围,也可缩短编码的长度

也就是说,我们可以在Code128C的编码中插入Code128A编码,以此来实现奇数位数字的表示,同时保证条形码不会太复杂,具体如下。

首先我们假定一个数字吧:7434012

第一步需要将数字分组:74、34、01、2

两位数的部分就用Code128C表示,一位数的部分就用Code128A表示。那么问题来了,校验位怎么求呢?这里经过查阅资料,校验位是要把Code128A的编码值也算进去,按code128C的校验值计算方法来计算。。。

具体编码结构如下:

Code128C的开始位
数据位74
数据位34
数据位01
Code128C编码中的`CODEA`(id为101)
数据位(Code128A中的2,id为18)
校验位=(StartC的id:105 + 74*1 + 34*2 + 1*3 + CODEA的id:101*4 + Code128A中2的id:18*5) % 103
停止位

其他编码方式开头,中途更换编码方式的算法也可以进行类推。

END

既然条码生成算法讲完了,下一篇文章就可以使用lua来生成条形码,显示到屏幕上面了

如果文章有错误,请在下方留言,谢谢!

1 Comment

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注