@10yun/cv-mobile-ui 0.5.34 → 0.5.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1046 @@
1
+ /**
2
+ * 获取单个字符的utf8编码
3
+ * unicode BMP平面约65535个字符
4
+ * @param {num} code
5
+ * return {array}
6
+ */
7
+ function unicodeFormat8(code) {
8
+ // 1 byte
9
+ var c0, c1, c2;
10
+ if (code < 128) {
11
+ return [code];
12
+ // 2 bytes
13
+ } else if (code < 2048) {
14
+ c0 = 192 + (code >> 6);
15
+ c1 = 128 + (code & 63);
16
+ return [c0, c1];
17
+ // 3 bytes
18
+ } else {
19
+ c0 = 224 + (code >> 12);
20
+ c1 = 128 + ((code >> 6) & 63);
21
+ c2 = 128 + (code & 63);
22
+ return [c0, c1, c2];
23
+ }
24
+ }
25
+ /**
26
+ * 获取字符串的utf8编码字节串
27
+ * @param {string} string
28
+ * @return {array}
29
+ */
30
+ function getUTF8Bytes(string) {
31
+ var utf8codes = [];
32
+ for (var i = 0; i < string.length; i++) {
33
+ var code = string.charCodeAt(i);
34
+ var utf8 = unicodeFormat8(code);
35
+ for (var j = 0; j < utf8.length; j++) {
36
+ utf8codes.push(utf8[j]);
37
+ }
38
+ }
39
+ return utf8codes;
40
+ }
41
+ /**
42
+ * 二维码算法实现
43
+ * @param {string} data 要编码的信息字符串
44
+ * @param {num} errorCorrectLevel 纠错等级
45
+ */
46
+ export default function QRCodeAlg(data, errorCorrectLevel) {
47
+ this.typeNumber = -1; //版本
48
+ this.errorCorrectLevel = errorCorrectLevel;
49
+ this.modules = null; //二维矩阵,存放最终结果
50
+ this.moduleCount = 0; //矩阵大小
51
+ this.dataCache = null; //数据缓存
52
+ this.rsBlocks = null; //版本数据信息
53
+ this.totalDataCount = -1; //可使用的数据量
54
+ this.data = data;
55
+ this.utf8bytes = getUTF8Bytes(data);
56
+ this.make();
57
+ }
58
+ QRCodeAlg.prototype = {
59
+ constructor: QRCodeAlg,
60
+ /**
61
+ * 获取二维码矩阵大小
62
+ * @return {num} 矩阵大小
63
+ */
64
+ getModuleCount: function () {
65
+ return this.moduleCount;
66
+ },
67
+ /**
68
+ * 编码
69
+ */
70
+ make: function () {
71
+ this.getRightType();
72
+ this.dataCache = this.createData();
73
+ this.createQrcode();
74
+ },
75
+ /**
76
+ * 设置二位矩阵功能图形
77
+ * @param {bool} test 表示是否在寻找最好掩膜阶段
78
+ * @param {num} maskPattern 掩膜的版本
79
+ */
80
+ makeImpl: function (maskPattern) {
81
+ this.moduleCount = this.typeNumber * 4 + 17;
82
+ this.modules = new Array(this.moduleCount);
83
+ for (var row = 0; row < this.moduleCount; row++) {
84
+ this.modules[row] = new Array(this.moduleCount);
85
+ }
86
+ this.setupPositionProbePattern(0, 0);
87
+ this.setupPositionProbePattern(this.moduleCount - 7, 0);
88
+ this.setupPositionProbePattern(0, this.moduleCount - 7);
89
+ this.setupPositionAdjustPattern();
90
+ this.setupTimingPattern();
91
+ this.setupTypeInfo(true, maskPattern);
92
+ if (this.typeNumber >= 7) {
93
+ this.setupTypeNumber(true);
94
+ }
95
+ this.mapData(this.dataCache, maskPattern);
96
+ },
97
+ /**
98
+ * 设置二维码的位置探测图形
99
+ * @param {num} row 探测图形的中心横坐标
100
+ * @param {num} col 探测图形的中心纵坐标
101
+ */
102
+ setupPositionProbePattern: function (row, col) {
103
+ for (var r = -1; r <= 7; r++) {
104
+ if (row + r <= -1 || this.moduleCount <= row + r) continue;
105
+ for (var c = -1; c <= 7; c++) {
106
+ if (col + c <= -1 || this.moduleCount <= col + c) continue;
107
+ if (
108
+ (0 <= r && r <= 6 && (c == 0 || c == 6)) ||
109
+ (0 <= c && c <= 6 && (r == 0 || r == 6)) ||
110
+ (2 <= r && r <= 4 && 2 <= c && c <= 4)
111
+ ) {
112
+ this.modules[row + r][col + c] = true;
113
+ } else {
114
+ this.modules[row + r][col + c] = false;
115
+ }
116
+ }
117
+ }
118
+ },
119
+ /**
120
+ * 创建二维码
121
+ * @return {[type]} [description]
122
+ */
123
+ createQrcode: function () {
124
+ var minLostPoint = 0;
125
+ var pattern = 0;
126
+ var bestModules = null;
127
+ for (var i = 0; i < 8; i++) {
128
+ this.makeImpl(i);
129
+ var lostPoint = QRUtil.getLostPoint(this);
130
+ if (i == 0 || minLostPoint > lostPoint) {
131
+ minLostPoint = lostPoint;
132
+ pattern = i;
133
+ bestModules = this.modules;
134
+ }
135
+ }
136
+ this.modules = bestModules;
137
+ this.setupTypeInfo(false, pattern);
138
+ if (this.typeNumber >= 7) {
139
+ this.setupTypeNumber(false);
140
+ }
141
+ },
142
+ /**
143
+ * 设置定位图形
144
+ * @return {[type]} [description]
145
+ */
146
+ setupTimingPattern: function () {
147
+ for (var r = 8; r < this.moduleCount - 8; r++) {
148
+ if (this.modules[r][6] != null) {
149
+ continue;
150
+ }
151
+ this.modules[r][6] = r % 2 == 0;
152
+ if (this.modules[6][r] != null) {
153
+ continue;
154
+ }
155
+ this.modules[6][r] = r % 2 == 0;
156
+ }
157
+ },
158
+ /**
159
+ * 设置矫正图形
160
+ * @return {[type]} [description]
161
+ */
162
+ setupPositionAdjustPattern: function () {
163
+ var pos = QRUtil.getPatternPosition(this.typeNumber);
164
+ for (var i = 0; i < pos.length; i++) {
165
+ for (var j = 0; j < pos.length; j++) {
166
+ var row = pos[i];
167
+ var col = pos[j];
168
+ if (this.modules[row][col] != null) {
169
+ continue;
170
+ }
171
+ for (var r = -2; r <= 2; r++) {
172
+ for (var c = -2; c <= 2; c++) {
173
+ if (r == -2 || r == 2 || c == -2 || c == 2 || (r == 0 && c == 0)) {
174
+ this.modules[row + r][col + c] = true;
175
+ } else {
176
+ this.modules[row + r][col + c] = false;
177
+ }
178
+ }
179
+ }
180
+ }
181
+ }
182
+ },
183
+ /**
184
+ * 设置版本信息(7以上版本才有)
185
+ * @param {bool} test 是否处于判断最佳掩膜阶段
186
+ * @return {[type]} [description]
187
+ */
188
+ setupTypeNumber: function (test) {
189
+ var bits = QRUtil.getBCHTypeNumber(this.typeNumber);
190
+ for (var i = 0; i < 18; i++) {
191
+ var mod = !test && ((bits >> i) & 1) == 1;
192
+ this.modules[Math.floor(i / 3)][(i % 3) + this.moduleCount - 8 - 3] = mod;
193
+ this.modules[(i % 3) + this.moduleCount - 8 - 3][Math.floor(i / 3)] = mod;
194
+ }
195
+ },
196
+ /**
197
+ * 设置格式信息(纠错等级和掩膜版本)
198
+ * @param {bool} test
199
+ * @param {num} maskPattern 掩膜版本
200
+ * @return {}
201
+ */
202
+ setupTypeInfo: function (test, maskPattern) {
203
+ var data = (QRErrorCorrectLevel[this.errorCorrectLevel] << 3) | maskPattern;
204
+ var bits = QRUtil.getBCHTypeInfo(data);
205
+ // vertical
206
+ for (var i = 0; i < 15; i++) {
207
+ var mod = !test && ((bits >> i) & 1) == 1;
208
+ if (i < 6) {
209
+ this.modules[i][8] = mod;
210
+ } else if (i < 8) {
211
+ this.modules[i + 1][8] = mod;
212
+ } else {
213
+ this.modules[this.moduleCount - 15 + i][8] = mod;
214
+ }
215
+ // horizontal
216
+ var mod = !test && ((bits >> i) & 1) == 1;
217
+ if (i < 8) {
218
+ this.modules[8][this.moduleCount - i - 1] = mod;
219
+ } else if (i < 9) {
220
+ this.modules[8][15 - i - 1 + 1] = mod;
221
+ } else {
222
+ this.modules[8][15 - i - 1] = mod;
223
+ }
224
+ }
225
+ // fixed module
226
+ this.modules[this.moduleCount - 8][8] = !test;
227
+ },
228
+ /**
229
+ * 数据编码
230
+ * @return {[type]} [description]
231
+ */
232
+ createData: function () {
233
+ var buffer = new QRBitBuffer();
234
+ var lengthBits = this.typeNumber > 9 ? 16 : 8;
235
+ buffer.put(4, 4); //添加模式
236
+ buffer.put(this.utf8bytes.length, lengthBits);
237
+ for (var i = 0, l = this.utf8bytes.length; i < l; i++) {
238
+ buffer.put(this.utf8bytes[i], 8);
239
+ }
240
+ if (buffer.length + 4 <= this.totalDataCount * 8) {
241
+ buffer.put(0, 4);
242
+ }
243
+ // padding
244
+ while (buffer.length % 8 != 0) {
245
+ buffer.putBit(false);
246
+ }
247
+ // padding
248
+ while (true) {
249
+ if (buffer.length >= this.totalDataCount * 8) {
250
+ break;
251
+ }
252
+ buffer.put(QRCodeAlg.PAD0, 8);
253
+ if (buffer.length >= this.totalDataCount * 8) {
254
+ break;
255
+ }
256
+ buffer.put(QRCodeAlg.PAD1, 8);
257
+ }
258
+ return this.createBytes(buffer);
259
+ },
260
+ /**
261
+ * 纠错码编码
262
+ * @param {buffer} buffer 数据编码
263
+ * @return {[type]}
264
+ */
265
+ createBytes: function (buffer) {
266
+ var offset = 0;
267
+ var maxDcCount = 0;
268
+ var maxEcCount = 0;
269
+ var length = this.rsBlock.length / 3;
270
+ var rsBlocks = new Array();
271
+ for (var i = 0; i < length; i++) {
272
+ var count = this.rsBlock[i * 3 + 0];
273
+ var totalCount = this.rsBlock[i * 3 + 1];
274
+ var dataCount = this.rsBlock[i * 3 + 2];
275
+ for (var j = 0; j < count; j++) {
276
+ rsBlocks.push([dataCount, totalCount]);
277
+ }
278
+ }
279
+ var dcdata = new Array(rsBlocks.length);
280
+ var ecdata = new Array(rsBlocks.length);
281
+ for (var r = 0; r < rsBlocks.length; r++) {
282
+ var dcCount = rsBlocks[r][0];
283
+ var ecCount = rsBlocks[r][1] - dcCount;
284
+ maxDcCount = Math.max(maxDcCount, dcCount);
285
+ maxEcCount = Math.max(maxEcCount, ecCount);
286
+ dcdata[r] = new Array(dcCount);
287
+ for (var i = 0; i < dcdata[r].length; i++) {
288
+ dcdata[r][i] = 0xff & buffer.buffer[i + offset];
289
+ }
290
+ offset += dcCount;
291
+ var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
292
+ var rawPoly = new QRPolynomial(dcdata[r], rsPoly.getLength() - 1);
293
+ var modPoly = rawPoly.mod(rsPoly);
294
+ ecdata[r] = new Array(rsPoly.getLength() - 1);
295
+ for (var i = 0; i < ecdata[r].length; i++) {
296
+ var modIndex = i + modPoly.getLength() - ecdata[r].length;
297
+ ecdata[r][i] = modIndex >= 0 ? modPoly.get(modIndex) : 0;
298
+ }
299
+ }
300
+ var data = new Array(this.totalDataCount);
301
+ var index = 0;
302
+ for (var i = 0; i < maxDcCount; i++) {
303
+ for (var r = 0; r < rsBlocks.length; r++) {
304
+ if (i < dcdata[r].length) {
305
+ data[index++] = dcdata[r][i];
306
+ }
307
+ }
308
+ }
309
+ for (var i = 0; i < maxEcCount; i++) {
310
+ for (var r = 0; r < rsBlocks.length; r++) {
311
+ if (i < ecdata[r].length) {
312
+ data[index++] = ecdata[r][i];
313
+ }
314
+ }
315
+ }
316
+ return data;
317
+ },
318
+ /**
319
+ * 布置模块,构建最终信息
320
+ * @param {} data
321
+ * @param {} maskPattern
322
+ * @return {}
323
+ */
324
+ mapData: function (data, maskPattern) {
325
+ var inc = -1;
326
+ var row = this.moduleCount - 1;
327
+ var bitIndex = 7;
328
+ var byteIndex = 0;
329
+ for (var col = this.moduleCount - 1; col > 0; col -= 2) {
330
+ if (col == 6) col--;
331
+ while (true) {
332
+ for (var c = 0; c < 2; c++) {
333
+ if (this.modules[row][col - c] == null) {
334
+ var dark = false;
335
+ if (byteIndex < data.length) {
336
+ dark = ((data[byteIndex] >>> bitIndex) & 1) == 1;
337
+ }
338
+ var mask = QRUtil.getMask(maskPattern, row, col - c);
339
+ if (mask) {
340
+ dark = !dark;
341
+ }
342
+ this.modules[row][col - c] = dark;
343
+ bitIndex--;
344
+ if (bitIndex == -1) {
345
+ byteIndex++;
346
+ bitIndex = 7;
347
+ }
348
+ }
349
+ }
350
+ row += inc;
351
+ if (row < 0 || this.moduleCount <= row) {
352
+ row -= inc;
353
+ inc = -inc;
354
+ break;
355
+ }
356
+ }
357
+ }
358
+ }
359
+ };
360
+ /**
361
+ * 填充字段
362
+ */
363
+ QRCodeAlg.PAD0 = 0xec;
364
+ QRCodeAlg.PAD1 = 0x11;
365
+ //---------------------------------------------------------------------
366
+ // 纠错等级对应的编码
367
+ //---------------------------------------------------------------------
368
+ var QRErrorCorrectLevel = [1, 0, 3, 2];
369
+ //---------------------------------------------------------------------
370
+ // 掩膜版本
371
+ //---------------------------------------------------------------------
372
+ var QRMaskPattern = {
373
+ PATTERN000: 0,
374
+ PATTERN001: 1,
375
+ PATTERN010: 2,
376
+ PATTERN011: 3,
377
+ PATTERN100: 4,
378
+ PATTERN101: 5,
379
+ PATTERN110: 6,
380
+ PATTERN111: 7
381
+ };
382
+ //---------------------------------------------------------------------
383
+ // 工具类
384
+ //---------------------------------------------------------------------
385
+ var QRUtil = {
386
+ /*
387
+ 每个版本矫正图形的位置
388
+ */
389
+ PATTERN_POSITION_TABLE: [
390
+ [],
391
+ [6, 18],
392
+ [6, 22],
393
+ [6, 26],
394
+ [6, 30],
395
+ [6, 34],
396
+ [6, 22, 38],
397
+ [6, 24, 42],
398
+ [6, 26, 46],
399
+ [6, 28, 50],
400
+ [6, 30, 54],
401
+ [6, 32, 58],
402
+ [6, 34, 62],
403
+ [6, 26, 46, 66],
404
+ [6, 26, 48, 70],
405
+ [6, 26, 50, 74],
406
+ [6, 30, 54, 78],
407
+ [6, 30, 56, 82],
408
+ [6, 30, 58, 86],
409
+ [6, 34, 62, 90],
410
+ [6, 28, 50, 72, 94],
411
+ [6, 26, 50, 74, 98],
412
+ [6, 30, 54, 78, 102],
413
+ [6, 28, 54, 80, 106],
414
+ [6, 32, 58, 84, 110],
415
+ [6, 30, 58, 86, 114],
416
+ [6, 34, 62, 90, 118],
417
+ [6, 26, 50, 74, 98, 122],
418
+ [6, 30, 54, 78, 102, 126],
419
+ [6, 26, 52, 78, 104, 130],
420
+ [6, 30, 56, 82, 108, 134],
421
+ [6, 34, 60, 86, 112, 138],
422
+ [6, 30, 58, 86, 114, 142],
423
+ [6, 34, 62, 90, 118, 146],
424
+ [6, 30, 54, 78, 102, 126, 150],
425
+ [6, 24, 50, 76, 102, 128, 154],
426
+ [6, 28, 54, 80, 106, 132, 158],
427
+ [6, 32, 58, 84, 110, 136, 162],
428
+ [6, 26, 54, 82, 110, 138, 166],
429
+ [6, 30, 58, 86, 114, 142, 170]
430
+ ],
431
+ G15: (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0),
432
+ G18: (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0),
433
+ G15_MASK: (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1),
434
+ /*
435
+ BCH编码格式信息
436
+ */
437
+ getBCHTypeInfo: function (data) {
438
+ var d = data << 10;
439
+ while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0) {
440
+ d ^= QRUtil.G15 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15));
441
+ }
442
+ return ((data << 10) | d) ^ QRUtil.G15_MASK;
443
+ },
444
+ /*
445
+ BCH编码版本信息
446
+ */
447
+ getBCHTypeNumber: function (data) {
448
+ var d = data << 12;
449
+ while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0) {
450
+ d ^= QRUtil.G18 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18));
451
+ }
452
+ return (data << 12) | d;
453
+ },
454
+ /*
455
+ 获取BCH位信息
456
+ */
457
+ getBCHDigit: function (data) {
458
+ var digit = 0;
459
+ while (data != 0) {
460
+ digit++;
461
+ data >>>= 1;
462
+ }
463
+ return digit;
464
+ },
465
+ /*
466
+ 获取版本对应的矫正图形位置
467
+ */
468
+ getPatternPosition: function (typeNumber) {
469
+ return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1];
470
+ },
471
+ /*
472
+ 掩膜算法
473
+ */
474
+ getMask: function (maskPattern, i, j) {
475
+ switch (maskPattern) {
476
+ case QRMaskPattern.PATTERN000:
477
+ return (i + j) % 2 == 0;
478
+ case QRMaskPattern.PATTERN001:
479
+ return i % 2 == 0;
480
+ case QRMaskPattern.PATTERN010:
481
+ return j % 3 == 0;
482
+ case QRMaskPattern.PATTERN011:
483
+ return (i + j) % 3 == 0;
484
+ case QRMaskPattern.PATTERN100:
485
+ return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 == 0;
486
+ case QRMaskPattern.PATTERN101:
487
+ return ((i * j) % 2) + ((i * j) % 3) == 0;
488
+ case QRMaskPattern.PATTERN110:
489
+ return (((i * j) % 2) + ((i * j) % 3)) % 2 == 0;
490
+ case QRMaskPattern.PATTERN111:
491
+ return (((i * j) % 3) + ((i + j) % 2)) % 2 == 0;
492
+ default:
493
+ throw new Error('bad maskPattern:' + maskPattern);
494
+ }
495
+ },
496
+ /*
497
+ 获取RS的纠错多项式
498
+ */
499
+ getErrorCorrectPolynomial: function (errorCorrectLength) {
500
+ var a = new QRPolynomial([1], 0);
501
+ for (var i = 0; i < errorCorrectLength; i++) {
502
+ a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0));
503
+ }
504
+ return a;
505
+ },
506
+ /*
507
+ 获取评价
508
+ */
509
+ getLostPoint: function (qrCode) {
510
+ var moduleCount = qrCode.getModuleCount(),
511
+ lostPoint = 0,
512
+ darkCount = 0;
513
+ for (var row = 0; row < moduleCount; row++) {
514
+ var sameCount = 0;
515
+ var head = qrCode.modules[row][0];
516
+ for (var col = 0; col < moduleCount; col++) {
517
+ var current = qrCode.modules[row][col];
518
+ //level 3 评价
519
+ if (col < moduleCount - 6) {
520
+ if (
521
+ current &&
522
+ !qrCode.modules[row][col + 1] &&
523
+ qrCode.modules[row][col + 2] &&
524
+ qrCode.modules[row][col + 3] &&
525
+ qrCode.modules[row][col + 4] &&
526
+ !qrCode.modules[row][col + 5] &&
527
+ qrCode.modules[row][col + 6]
528
+ ) {
529
+ if (col < moduleCount - 10) {
530
+ if (
531
+ qrCode.modules[row][col + 7] &&
532
+ qrCode.modules[row][col + 8] &&
533
+ qrCode.modules[row][col + 9] &&
534
+ qrCode.modules[row][col + 10]
535
+ ) {
536
+ lostPoint += 40;
537
+ }
538
+ } else if (col > 3) {
539
+ if (
540
+ qrCode.modules[row][col - 1] &&
541
+ qrCode.modules[row][col - 2] &&
542
+ qrCode.modules[row][col - 3] &&
543
+ qrCode.modules[row][col - 4]
544
+ ) {
545
+ lostPoint += 40;
546
+ }
547
+ }
548
+ }
549
+ }
550
+ //level 2 评价
551
+ if (row < moduleCount - 1 && col < moduleCount - 1) {
552
+ var count = 0;
553
+ if (current) count++;
554
+ if (qrCode.modules[row + 1][col]) count++;
555
+ if (qrCode.modules[row][col + 1]) count++;
556
+ if (qrCode.modules[row + 1][col + 1]) count++;
557
+ if (count == 0 || count == 4) {
558
+ lostPoint += 3;
559
+ }
560
+ }
561
+ //level 1 评价
562
+ if (head ^ current) {
563
+ sameCount++;
564
+ } else {
565
+ head = current;
566
+ if (sameCount >= 5) {
567
+ lostPoint += 3 + sameCount - 5;
568
+ }
569
+ sameCount = 1;
570
+ }
571
+ //level 4 评价
572
+ if (current) {
573
+ darkCount++;
574
+ }
575
+ }
576
+ }
577
+ for (var col = 0; col < moduleCount; col++) {
578
+ var sameCount = 0;
579
+ var head = qrCode.modules[0][col];
580
+ for (var row = 0; row < moduleCount; row++) {
581
+ var current = qrCode.modules[row][col];
582
+ //level 3 评价
583
+ if (row < moduleCount - 6) {
584
+ if (
585
+ current &&
586
+ !qrCode.modules[row + 1][col] &&
587
+ qrCode.modules[row + 2][col] &&
588
+ qrCode.modules[row + 3][col] &&
589
+ qrCode.modules[row + 4][col] &&
590
+ !qrCode.modules[row + 5][col] &&
591
+ qrCode.modules[row + 6][col]
592
+ ) {
593
+ if (row < moduleCount - 10) {
594
+ if (
595
+ qrCode.modules[row + 7][col] &&
596
+ qrCode.modules[row + 8][col] &&
597
+ qrCode.modules[row + 9][col] &&
598
+ qrCode.modules[row + 10][col]
599
+ ) {
600
+ lostPoint += 40;
601
+ }
602
+ } else if (row > 3) {
603
+ if (
604
+ qrCode.modules[row - 1][col] &&
605
+ qrCode.modules[row - 2][col] &&
606
+ qrCode.modules[row - 3][col] &&
607
+ qrCode.modules[row - 4][col]
608
+ ) {
609
+ lostPoint += 40;
610
+ }
611
+ }
612
+ }
613
+ }
614
+ //level 1 评价
615
+ if (head ^ current) {
616
+ sameCount++;
617
+ } else {
618
+ head = current;
619
+ if (sameCount >= 5) {
620
+ lostPoint += 3 + sameCount - 5;
621
+ }
622
+ sameCount = 1;
623
+ }
624
+ }
625
+ }
626
+ // LEVEL4
627
+ var ratio = Math.abs((100 * darkCount) / moduleCount / moduleCount - 50) / 5;
628
+ lostPoint += ratio * 10;
629
+ return lostPoint;
630
+ }
631
+ };
632
+ //---------------------------------------------------------------------
633
+ // QRMath使用的数学工具
634
+ //---------------------------------------------------------------------
635
+ var QRMath = {
636
+ /*
637
+ 将n转化为a^m
638
+ */
639
+ glog: function (n) {
640
+ if (n < 1) {
641
+ throw new Error('glog(' + n + ')');
642
+ }
643
+ return QRMath.LOG_TABLE[n];
644
+ },
645
+ /*
646
+ 将a^m转化为n
647
+ */
648
+ gexp: function (n) {
649
+ while (n < 0) {
650
+ n += 255;
651
+ }
652
+ while (n >= 256) {
653
+ n -= 255;
654
+ }
655
+ return QRMath.EXP_TABLE[n];
656
+ },
657
+ EXP_TABLE: new Array(256),
658
+ LOG_TABLE: new Array(256)
659
+ };
660
+ for (var i = 0; i < 8; i++) {
661
+ QRMath.EXP_TABLE[i] = 1 << i;
662
+ }
663
+ for (var i = 8; i < 256; i++) {
664
+ QRMath.EXP_TABLE[i] = QRMath.EXP_TABLE[i - 4] ^ QRMath.EXP_TABLE[i - 5] ^ QRMath.EXP_TABLE[i - 6] ^ QRMath.EXP_TABLE[i - 8];
665
+ }
666
+ for (var i = 0; i < 255; i++) {
667
+ QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]] = i;
668
+ }
669
+ //---------------------------------------------------------------------
670
+ // QRPolynomial 多项式
671
+ //---------------------------------------------------------------------
672
+ /**
673
+ * 多项式类
674
+ * @param {Array} num 系数
675
+ * @param {num} shift a^shift
676
+ */
677
+ function QRPolynomial(num, shift) {
678
+ if (num.length == undefined) {
679
+ throw new Error(num.length + '/' + shift);
680
+ }
681
+ var offset = 0;
682
+ while (offset < num.length && num[offset] == 0) {
683
+ offset++;
684
+ }
685
+ this.num = new Array(num.length - offset + shift);
686
+ for (var i = 0; i < num.length - offset; i++) {
687
+ this.num[i] = num[i + offset];
688
+ }
689
+ }
690
+ QRPolynomial.prototype = {
691
+ get: function (index) {
692
+ return this.num[index];
693
+ },
694
+ getLength: function () {
695
+ return this.num.length;
696
+ },
697
+ /**
698
+ * 多项式乘法
699
+ * @param {QRPolynomial} e 被乘多项式
700
+ * @return {[type]} [description]
701
+ */
702
+ multiply: function (e) {
703
+ var num = new Array(this.getLength() + e.getLength() - 1);
704
+ for (var i = 0; i < this.getLength(); i++) {
705
+ for (var j = 0; j < e.getLength(); j++) {
706
+ num[i + j] ^= QRMath.gexp(QRMath.glog(this.get(i)) + QRMath.glog(e.get(j)));
707
+ }
708
+ }
709
+ return new QRPolynomial(num, 0);
710
+ },
711
+ /**
712
+ * 多项式模运算
713
+ * @param {QRPolynomial} e 模多项式
714
+ * @return {}
715
+ */
716
+ mod: function (e) {
717
+ var tl = this.getLength(),
718
+ el = e.getLength();
719
+ if (tl - el < 0) {
720
+ return this;
721
+ }
722
+ var num = new Array(tl);
723
+ for (var i = 0; i < tl; i++) {
724
+ num[i] = this.get(i);
725
+ }
726
+ while (num.length >= el) {
727
+ var ratio = QRMath.glog(num[0]) - QRMath.glog(e.get(0));
728
+
729
+ for (var i = 0; i < e.getLength(); i++) {
730
+ num[i] ^= QRMath.gexp(QRMath.glog(e.get(i)) + ratio);
731
+ }
732
+ while (num[0] == 0) {
733
+ num.shift();
734
+ }
735
+ }
736
+ return new QRPolynomial(num, 0);
737
+ }
738
+ };
739
+
740
+ //---------------------------------------------------------------------
741
+ // RS_BLOCK_TABLE
742
+ //---------------------------------------------------------------------
743
+ /*
744
+ 二维码各个版本信息[块数, 每块中的数据块数, 每块中的信息块数]
745
+ */
746
+ var RS_BLOCK_TABLE = [
747
+ // L
748
+ // M
749
+ // Q
750
+ // H
751
+ // 1
752
+ [1, 26, 19],
753
+ [1, 26, 16],
754
+ [1, 26, 13],
755
+ [1, 26, 9],
756
+
757
+ // 2
758
+ [1, 44, 34],
759
+ [1, 44, 28],
760
+ [1, 44, 22],
761
+ [1, 44, 16],
762
+
763
+ // 3
764
+ [1, 70, 55],
765
+ [1, 70, 44],
766
+ [2, 35, 17],
767
+ [2, 35, 13],
768
+
769
+ // 4
770
+ [1, 100, 80],
771
+ [2, 50, 32],
772
+ [2, 50, 24],
773
+ [4, 25, 9],
774
+
775
+ // 5
776
+ [1, 134, 108],
777
+ [2, 67, 43],
778
+ [2, 33, 15, 2, 34, 16],
779
+ [2, 33, 11, 2, 34, 12],
780
+
781
+ // 6
782
+ [2, 86, 68],
783
+ [4, 43, 27],
784
+ [4, 43, 19],
785
+ [4, 43, 15],
786
+
787
+ // 7
788
+ [2, 98, 78],
789
+ [4, 49, 31],
790
+ [2, 32, 14, 4, 33, 15],
791
+ [4, 39, 13, 1, 40, 14],
792
+
793
+ // 8
794
+ [2, 121, 97],
795
+ [2, 60, 38, 2, 61, 39],
796
+ [4, 40, 18, 2, 41, 19],
797
+ [4, 40, 14, 2, 41, 15],
798
+
799
+ // 9
800
+ [2, 146, 116],
801
+ [3, 58, 36, 2, 59, 37],
802
+ [4, 36, 16, 4, 37, 17],
803
+ [4, 36, 12, 4, 37, 13],
804
+
805
+ // 10
806
+ [2, 86, 68, 2, 87, 69],
807
+ [4, 69, 43, 1, 70, 44],
808
+ [6, 43, 19, 2, 44, 20],
809
+ [6, 43, 15, 2, 44, 16],
810
+
811
+ // 11
812
+ [4, 101, 81],
813
+ [1, 80, 50, 4, 81, 51],
814
+ [4, 50, 22, 4, 51, 23],
815
+ [3, 36, 12, 8, 37, 13],
816
+
817
+ // 12
818
+ [2, 116, 92, 2, 117, 93],
819
+ [6, 58, 36, 2, 59, 37],
820
+ [4, 46, 20, 6, 47, 21],
821
+ [7, 42, 14, 4, 43, 15],
822
+
823
+ // 13
824
+ [4, 133, 107],
825
+ [8, 59, 37, 1, 60, 38],
826
+ [8, 44, 20, 4, 45, 21],
827
+ [12, 33, 11, 4, 34, 12],
828
+
829
+ // 14
830
+ [3, 145, 115, 1, 146, 116],
831
+ [4, 64, 40, 5, 65, 41],
832
+ [11, 36, 16, 5, 37, 17],
833
+ [11, 36, 12, 5, 37, 13],
834
+
835
+ // 15
836
+ [5, 109, 87, 1, 110, 88],
837
+ [5, 65, 41, 5, 66, 42],
838
+ [5, 54, 24, 7, 55, 25],
839
+ [11, 36, 12],
840
+
841
+ // 16
842
+ [5, 122, 98, 1, 123, 99],
843
+ [7, 73, 45, 3, 74, 46],
844
+ [15, 43, 19, 2, 44, 20],
845
+ [3, 45, 15, 13, 46, 16],
846
+
847
+ // 17
848
+ [1, 135, 107, 5, 136, 108],
849
+ [10, 74, 46, 1, 75, 47],
850
+ [1, 50, 22, 15, 51, 23],
851
+ [2, 42, 14, 17, 43, 15],
852
+
853
+ // 18
854
+ [5, 150, 120, 1, 151, 121],
855
+ [9, 69, 43, 4, 70, 44],
856
+ [17, 50, 22, 1, 51, 23],
857
+ [2, 42, 14, 19, 43, 15],
858
+
859
+ // 19
860
+ [3, 141, 113, 4, 142, 114],
861
+ [3, 70, 44, 11, 71, 45],
862
+ [17, 47, 21, 4, 48, 22],
863
+ [9, 39, 13, 16, 40, 14],
864
+
865
+ // 20
866
+ [3, 135, 107, 5, 136, 108],
867
+ [3, 67, 41, 13, 68, 42],
868
+ [15, 54, 24, 5, 55, 25],
869
+ [15, 43, 15, 10, 44, 16],
870
+
871
+ // 21
872
+ [4, 144, 116, 4, 145, 117],
873
+ [17, 68, 42],
874
+ [17, 50, 22, 6, 51, 23],
875
+ [19, 46, 16, 6, 47, 17],
876
+
877
+ // 22
878
+ [2, 139, 111, 7, 140, 112],
879
+ [17, 74, 46],
880
+ [7, 54, 24, 16, 55, 25],
881
+ [34, 37, 13],
882
+
883
+ // 23
884
+ [4, 151, 121, 5, 152, 122],
885
+ [4, 75, 47, 14, 76, 48],
886
+ [11, 54, 24, 14, 55, 25],
887
+ [16, 45, 15, 14, 46, 16],
888
+
889
+ // 24
890
+ [6, 147, 117, 4, 148, 118],
891
+ [6, 73, 45, 14, 74, 46],
892
+ [11, 54, 24, 16, 55, 25],
893
+ [30, 46, 16, 2, 47, 17],
894
+
895
+ // 25
896
+ [8, 132, 106, 4, 133, 107],
897
+ [8, 75, 47, 13, 76, 48],
898
+ [7, 54, 24, 22, 55, 25],
899
+ [22, 45, 15, 13, 46, 16],
900
+
901
+ // 26
902
+ [10, 142, 114, 2, 143, 115],
903
+ [19, 74, 46, 4, 75, 47],
904
+ [28, 50, 22, 6, 51, 23],
905
+ [33, 46, 16, 4, 47, 17],
906
+
907
+ // 27
908
+ [8, 152, 122, 4, 153, 123],
909
+ [22, 73, 45, 3, 74, 46],
910
+ [8, 53, 23, 26, 54, 24],
911
+ [12, 45, 15, 28, 46, 16],
912
+
913
+ // 28
914
+ [3, 147, 117, 10, 148, 118],
915
+ [3, 73, 45, 23, 74, 46],
916
+ [4, 54, 24, 31, 55, 25],
917
+ [11, 45, 15, 31, 46, 16],
918
+
919
+ // 29
920
+ [7, 146, 116, 7, 147, 117],
921
+ [21, 73, 45, 7, 74, 46],
922
+ [1, 53, 23, 37, 54, 24],
923
+ [19, 45, 15, 26, 46, 16],
924
+
925
+ // 30
926
+ [5, 145, 115, 10, 146, 116],
927
+ [19, 75, 47, 10, 76, 48],
928
+ [15, 54, 24, 25, 55, 25],
929
+ [23, 45, 15, 25, 46, 16],
930
+
931
+ // 31
932
+ [13, 145, 115, 3, 146, 116],
933
+ [2, 74, 46, 29, 75, 47],
934
+ [42, 54, 24, 1, 55, 25],
935
+ [23, 45, 15, 28, 46, 16],
936
+
937
+ // 32
938
+ [17, 145, 115],
939
+ [10, 74, 46, 23, 75, 47],
940
+ [10, 54, 24, 35, 55, 25],
941
+ [19, 45, 15, 35, 46, 16],
942
+
943
+ // 33
944
+ [17, 145, 115, 1, 146, 116],
945
+ [14, 74, 46, 21, 75, 47],
946
+ [29, 54, 24, 19, 55, 25],
947
+ [11, 45, 15, 46, 46, 16],
948
+
949
+ // 34
950
+ [13, 145, 115, 6, 146, 116],
951
+ [14, 74, 46, 23, 75, 47],
952
+ [44, 54, 24, 7, 55, 25],
953
+ [59, 46, 16, 1, 47, 17],
954
+
955
+ // 35
956
+ [12, 151, 121, 7, 152, 122],
957
+ [12, 75, 47, 26, 76, 48],
958
+ [39, 54, 24, 14, 55, 25],
959
+ [22, 45, 15, 41, 46, 16],
960
+
961
+ // 36
962
+ [6, 151, 121, 14, 152, 122],
963
+ [6, 75, 47, 34, 76, 48],
964
+ [46, 54, 24, 10, 55, 25],
965
+ [2, 45, 15, 64, 46, 16],
966
+
967
+ // 37
968
+ [17, 152, 122, 4, 153, 123],
969
+ [29, 74, 46, 14, 75, 47],
970
+ [49, 54, 24, 10, 55, 25],
971
+ [24, 45, 15, 46, 46, 16],
972
+
973
+ // 38
974
+ [4, 152, 122, 18, 153, 123],
975
+ [13, 74, 46, 32, 75, 47],
976
+ [48, 54, 24, 14, 55, 25],
977
+ [42, 45, 15, 32, 46, 16],
978
+
979
+ // 39
980
+ [20, 147, 117, 4, 148, 118],
981
+ [40, 75, 47, 7, 76, 48],
982
+ [43, 54, 24, 22, 55, 25],
983
+ [10, 45, 15, 67, 46, 16],
984
+
985
+ // 40
986
+ [19, 148, 118, 6, 149, 119],
987
+ [18, 75, 47, 31, 76, 48],
988
+ [34, 54, 24, 34, 55, 25],
989
+ [20, 45, 15, 61, 46, 16]
990
+ ];
991
+
992
+ /**
993
+ * 根据数据获取对应版本
994
+ * @return {[type]} [description]
995
+ */
996
+ QRCodeAlg.prototype.getRightType = function () {
997
+ for (var typeNumber = 1; typeNumber < 41; typeNumber++) {
998
+ var rsBlock = RS_BLOCK_TABLE[(typeNumber - 1) * 4 + this.errorCorrectLevel];
999
+ if (rsBlock == undefined) {
1000
+ throw new Error('bad rs block @ typeNumber:' + typeNumber + '/errorCorrectLevel:' + this.errorCorrectLevel);
1001
+ }
1002
+ var length = rsBlock.length / 3;
1003
+ var totalDataCount = 0;
1004
+ for (var i = 0; i < length; i++) {
1005
+ var count = rsBlock[i * 3 + 0];
1006
+ var dataCount = rsBlock[i * 3 + 2];
1007
+ totalDataCount += dataCount * count;
1008
+ }
1009
+ var lengthBytes = typeNumber > 9 ? 2 : 1;
1010
+ if (this.utf8bytes.length + lengthBytes < totalDataCount || typeNumber == 40) {
1011
+ this.typeNumber = typeNumber;
1012
+ this.rsBlock = rsBlock;
1013
+ this.totalDataCount = totalDataCount;
1014
+ break;
1015
+ }
1016
+ }
1017
+ };
1018
+
1019
+ //---------------------------------------------------------------------
1020
+ // QRBitBuffer
1021
+ //---------------------------------------------------------------------
1022
+ function QRBitBuffer() {
1023
+ this.buffer = new Array();
1024
+ this.length = 0;
1025
+ }
1026
+ QRBitBuffer.prototype = {
1027
+ get: function (index) {
1028
+ var bufIndex = Math.floor(index / 8);
1029
+ return (this.buffer[bufIndex] >>> (7 - (index % 8))) & 1;
1030
+ },
1031
+ put: function (num, length) {
1032
+ for (var i = 0; i < length; i++) {
1033
+ this.putBit((num >>> (length - i - 1)) & 1);
1034
+ }
1035
+ },
1036
+ putBit: function (bit) {
1037
+ var bufIndex = Math.floor(this.length / 8);
1038
+ if (this.buffer.length <= bufIndex) {
1039
+ this.buffer.push(0);
1040
+ }
1041
+ if (bit) {
1042
+ this.buffer[bufIndex] |= 0x80 >>> this.length % 8;
1043
+ }
1044
+ this.length++;
1045
+ }
1046
+ };