使用JavaScript创建SVG矢量图Code128编码

起因

本来设计使用20开头的EAN13 作为店内码的, 实际查询发现. 一些20开头的也是商品条码. 这就有点尴尬了, 为了不和商品条码冲突, 只好改变编码规则, 因此需要实现输出SVG格式的Code128条码.

设计

Code128是支持ABC混合编码的, 在生成条码过程中可以切换码表. 考虑字符密度,优先使用 Code128-C 作为数字编码, 如果有字母,则切换到Code128-B.

这里附上 Code-128码表

IDCode128ACode128BCode128CBandCode编码值
0SPSP0212222bbsbbssbbss
1!!1222122bbssbbsbbss
2""2222221bbssbbssbbs
3##3121223bssbssbbsss
4$$4121322bssbsssbbss
5%%5131222bsssbssbbss
6&&6122213bssbbssbsss
77122312bssbbsssbss
8((8132212bsssbbssbss
9))9221213bbssbssbsss
10**10221312bbssbsssbss
11++11231212bbsssbssbss
12,,12112232bsbbssbbbss
13--13122132bssbbsbbbss
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编码:

位类型码表线校验值
起始位StartAbbsbssssbss103
数据位Code128A中的1bssbbbssbbs103 + 17 * 1
数据位Code128A中的3bbssbsbbbss103 + 19 * 2
数据位Code128A中的4bbssbssbbbs103 + 20 * 3
数据位Code128A中的6bbssbbbsbss103 + 22 * 4
校验位校验值 % 103----前面的求和 % 103后查表.
停止位Stopbbsssbbbsbsbb

对于Code128B编码:

位类型码表线校验值
起始位StartBbbsbssssbss104
数据位Code128B中的1bssbbbssbbs17 * 1
数据位Code128B中的3bbssbsbbbss19 * 2
数据位Code128B中的4bbssbssbbbs20 * 3
数据位Code128B中的6bbssbbbsbss22 * 4
校验位校验值 % 103----前面的求和 % 103后查表.
停止位Stopbbsssbbbsbsbb

对于Code128C编码:

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

位类型码表线校验值
起始位StartCbbsbssbbbss105
数据位Code128C中的13bssbbsbbbss13 * 1
数据位Code128C中的46bsbbbsssbbs46 * 2
校验位校验值 % 103----前面的求和 % 103 后查表
停止位Stopbbsssbbbsbsbb

混合编码

中间要切换编码只需加入切换编码查表线值表即可,索引需要计入校验,计算方法一致。

实现代码

const codeC = [
    1740,1644,1638,1176,1164,1100,1224,1220,1124,1608,1604,1572,1436,1244,1230,1484,1260,1254,1650,1628,
    1614,1764,1652,1902,1868,1836,1830,1892,1844,1842,1752,1734,1590,1304,1112,1094,1416,1128,1122,1672,
    1576,1570,1464,1422,1134,1496,1478,1142,1910,1678,1582,1768,1762,1774,1880,1862,1814,1896,1890,1818,
    1914,1602,1930,1328,1292,1200,1158,1068,1062,1424,1412,1232,1218,1076,1074,1554,1616,1978,1556,1146,
    1340,1212,1182,1508,1268,1266,1956,1940,1938,1758,1782,1974,1400,1310,1118,1512,1506,1960,1954,1502,
    1518,1886,1966,1668,1680,1692,6379
],codeB=[
    null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,
    null,null,null,null,null,null,null,null,null,null,null,null,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,
    18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,76,42,43,44,45,46,47,48,49,50,51,52,
    53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,null,77,78,79,80,81,82,83,84,85,86,87,
    88,89,90,91,92,93,94,95,102,97,96,100
];

function Code128B(code, conf){
    let chars = code.split(/(\d{2}|[^\d]{1})/).filter(v=>v!=''), sum = 105, n=[], bits = [], pos = 1;
    var enc;
    const modeB=0,modeC=1;
    chars.forEach((ch, i)=>{
        let len = ch.length, v;
        if(i == 0){
            if(len == 1){
                sum = 104;
                enc = modeB; 
                v = codeB[ch.charCodeAt(0)];
                n.push(codeC[104]);
            }else{
                sum = 105;
                enc = modeC;
                v = parseInt(ch);
                n.push(codeC[105]);
                //console.log('start C', ch, v);
            }
            n.push(codeC[v]);
        }else{
            if(enc == modeC){
                if(len == 1){
                    enc = modeB;
                    sum += 100 * pos++;
                    n.push(codeC[100]);
                    v = codeB[ch.charCodeAt(0)];
                }else{
                    v = parseInt(ch);
                }
            }else{
                if(len == 1){
                    v = codeB[ch.charCodeAt(0)];
                }else{
                    enc = modeC;
                    sum += 99 * pos++;
                    n.push(codeC[99]); //codeB => codeC
                    v = parseInt(ch);
                }
            }
            n.push(codeC[v]);
        }
        sum += v * pos++;
    });

    n.push(codeC[sum % 103], 6379);
    n.forEach(v=>{
        var b = []
        do{
            b.push(v & 1 ? 1:0);
            v >>=1;
        }while(v > 0)
        bits.push(...b.reverse());
    })
    //console.log(bits);
    var x=-1, w = 0, nCount = bits.length+6, y = conf.name ? (2+conf.fsize) : 0,s = [],
    bar = [`<svg viewBox="0 0 ${nCount} ${conf.h}" width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" xmlns:xlink= "http://www.w3.org/1999/xlink">`];

    bits.forEach((v,i)=>{
        if(0 == v || i == bits.length-1){
            if(w > 0){
                var h = (x < 14 || x > bits.length - 12)? conf.h - y : conf.h - y - 6.5;
                s.push('M', x, ' ', y,'h', w, 'v', h, 'h', -w, 'Z')
                x = -1;w = 0;
            }
        }else{
            if(-1 == x ){x = i+3;}
            w++;
        }
    })

    bar.push('<path d="', s.join(''),'"/>')
    const unit = (nCount - (6 + 13 + 14)) / code.length;
    for(var i = 0; i < code.length;i ++){
        bar.push('<text x="', 16 + i * unit ,'" y="', conf.h - 0.4,'" text-anchor="left" font-size="7" font-family="Verdana">', code[i] , '</text>')
    }
    if(conf.name){
        bar.push('<text x="',nCount/2,'" y="',conf.fsize - 0.5,'" font-size="',conf.fsize,'" width="',nCount,'" text-anchor="middle" font-family="Verdana">',conf.name,'</text>')
    }
    bar.push('</svg>')
    return {
        svg: bar.join(''),
        lines: nCount
    }
}

var svg = Code128B('Z65432189120', {h:45, name:'很好', fsize:9});

上面的代码执行效果如下:

Z 6 5 4 3 2 1 8 9 1 2 0 很好
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值