@oguzhnatly/react-native-custom-qr-codes 2.0.0

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,1862 @@
1
+ /**
2
+ * @fileoverview
3
+ * - modified davidshimjs/qrcodejs library for use in node.js
4
+ * - Using the 'QRCode for Javascript library'
5
+ * - Fixed dataset of 'QRCode for Javascript library' for support full-spec.
6
+ * - this library has no dependencies.
7
+ *
8
+ * @version 0.9.1 (2016-02-12)
9
+ * @author davidshimjs, papnkukn
10
+ * @see <a href="http://www.d-project.com/" target="_blank">http://www.d-project.com/</a>
11
+ * @see <a href="http://jeromeetienne.github.com/jquery-qrcode/" target="_blank">http://jeromeetienne.github.com/jquery-qrcode/</a>
12
+ * @see <a href="https://github.com/davidshimjs/qrcodejs" target="_blank">https://github.com/davidshimjs/qrcodejs</a>
13
+ */
14
+
15
+ //---------------------------------------------------------------------
16
+ // QRCode for JavaScript
17
+ //
18
+ // Copyright (c) 2009 Kazuhiko Arase
19
+ //
20
+ // URL: http://www.d-project.com/
21
+ //
22
+ // Licensed under the MIT license:
23
+ // http://www.opensource.org/licenses/mit-license.php
24
+ //
25
+ // The word "QR Code" is registered trademark of
26
+ // DENSO WAVE INCORPORATED
27
+ // http://www.denso-wave.com/qrcode/faqpatent-e.html
28
+ //
29
+ //---------------------------------------------------------------------
30
+
31
+ //Returns an SVG of a QR Code created using the properties object
32
+ export function generateQRCode(props) {
33
+ var myQRCode = new QRCode(props);
34
+ return myQRCode;
35
+ }
36
+
37
+ function QR8bitByte(data) {
38
+ this.mode = QRMode.MODE_8BIT_BYTE;
39
+ this.data = data;
40
+ this.parsedData = [];
41
+
42
+ // Added to support UTF-8 Characters
43
+ for (var i = 0, l = this.data.length; i < l; i++) {
44
+ var byteArray = [];
45
+ var code = this.data.charCodeAt(i);
46
+
47
+ if (code > 0x10000) {
48
+ byteArray[0] = 0xf0 | ((code & 0x1c0000) >>> 18);
49
+ byteArray[1] = 0x80 | ((code & 0x3f000) >>> 12);
50
+ byteArray[2] = 0x80 | ((code & 0xfc0) >>> 6);
51
+ byteArray[3] = 0x80 | (code & 0x3f);
52
+ } else if (code > 0x800) {
53
+ byteArray[0] = 0xe0 | ((code & 0xf000) >>> 12);
54
+ byteArray[1] = 0x80 | ((code & 0xfc0) >>> 6);
55
+ byteArray[2] = 0x80 | (code & 0x3f);
56
+ } else if (code > 0x80) {
57
+ byteArray[0] = 0xc0 | ((code & 0x7c0) >>> 6);
58
+ byteArray[1] = 0x80 | (code & 0x3f);
59
+ } else {
60
+ byteArray[0] = code;
61
+ }
62
+
63
+ this.parsedData.push(byteArray);
64
+ }
65
+
66
+ this.parsedData = Array.prototype.concat.apply([], this.parsedData);
67
+
68
+ if (this.parsedData.length != this.data.length) {
69
+ this.parsedData.unshift(191);
70
+ this.parsedData.unshift(187);
71
+ this.parsedData.unshift(239);
72
+ }
73
+ }
74
+
75
+ QR8bitByte.prototype = {
76
+ getLength: function (buffer) {
77
+ return this.parsedData.length;
78
+ },
79
+ write: function (buffer) {
80
+ for (var i = 0, l = this.parsedData.length; i < l; i++) {
81
+ buffer.put(this.parsedData[i], 8);
82
+ }
83
+ },
84
+ };
85
+
86
+ function QRCodeModel(typeNumber, errorCorrectLevel) {
87
+ this.typeNumber = typeNumber;
88
+ this.errorCorrectLevel = errorCorrectLevel;
89
+ this.modules = null;
90
+ this.moduleCount = 0;
91
+ this.dataCache = null;
92
+ this.dataList = [];
93
+ }
94
+
95
+ QRCodeModel.prototype = {
96
+ addData: function (data) {
97
+ var newData = new QR8bitByte(data);
98
+ this.dataList.push(newData);
99
+ this.dataCache = null;
100
+ },
101
+ isDark: function (row, col) {
102
+ if (
103
+ row < 0 ||
104
+ this.moduleCount <= row ||
105
+ col < 0 ||
106
+ this.moduleCount <= col
107
+ ) {
108
+ throw new Error(row + "," + col);
109
+ }
110
+ return this.modules[row][col];
111
+ },
112
+ getModuleCount: function () {
113
+ return this.moduleCount;
114
+ },
115
+ make: function () {
116
+ this.makeImpl(false, this.getBestMaskPattern());
117
+ },
118
+ makeImpl: function (test, maskPattern) {
119
+ this.moduleCount = this.typeNumber * 4 + 17;
120
+ this.modules = new Array(this.moduleCount);
121
+ for (var row = 0; row < this.moduleCount; row++) {
122
+ this.modules[row] = new Array(this.moduleCount);
123
+ for (var col = 0; col < this.moduleCount; col++) {
124
+ this.modules[row][col] = null;
125
+ }
126
+ }
127
+ this.setupPositionProbePattern(0, 0);
128
+ this.setupPositionProbePattern(this.moduleCount - 7, 0);
129
+ this.setupPositionProbePattern(0, this.moduleCount - 7);
130
+ this.setupPositionAdjustPattern();
131
+ this.setupTimingPattern();
132
+ this.setupTypeInfo(test, maskPattern);
133
+ if (this.typeNumber >= 7) {
134
+ this.setupTypeNumber(test);
135
+ }
136
+ if (this.dataCache == null) {
137
+ this.dataCache = QRCodeModel.createData(
138
+ this.typeNumber,
139
+ this.errorCorrectLevel,
140
+ this.dataList
141
+ );
142
+ }
143
+ this.mapData(this.dataCache, maskPattern);
144
+ },
145
+ setupPositionProbePattern: function (row, col) {
146
+ for (var r = -1; r <= 7; r++) {
147
+ if (row + r <= -1 || this.moduleCount <= row + r) continue;
148
+ for (var c = -1; c <= 7; c++) {
149
+ if (col + c <= -1 || this.moduleCount <= col + c) continue;
150
+ if (
151
+ (0 <= r && r <= 6 && (c == 0 || c == 6)) ||
152
+ (0 <= c && c <= 6 && (r == 0 || r == 6)) ||
153
+ (2 <= r && r <= 4 && 2 <= c && c <= 4)
154
+ ) {
155
+ this.modules[row + r][col + c] = true;
156
+ } else {
157
+ this.modules[row + r][col + c] = false;
158
+ }
159
+ }
160
+ }
161
+ },
162
+ getBestMaskPattern: function () {
163
+ var minLostPoint = 0;
164
+ var pattern = 0;
165
+ for (var i = 0; i < 8; i++) {
166
+ this.makeImpl(true, i);
167
+ var lostPoint = QRUtil.getLostPoint(this);
168
+ if (i == 0 || minLostPoint > lostPoint) {
169
+ minLostPoint = lostPoint;
170
+ pattern = i;
171
+ }
172
+ }
173
+ return pattern;
174
+ },
175
+ createMovieClip: function (target_mc, instance_name, depth) {
176
+ var qr_mc = target_mc.createEmptyMovieClip(instance_name, depth);
177
+ var cs = 1;
178
+ this.make();
179
+ for (var row = 0; row < this.modules.length; row++) {
180
+ var y = row * cs;
181
+ for (var col = 0; col < this.modules[row].length; col++) {
182
+ var x = col * cs;
183
+ var dark = this.modules[row][col];
184
+ if (dark) {
185
+ qr_mc.beginFill(0, 100);
186
+ qr_mc.moveTo(x, y);
187
+ qr_mc.lineTo(x + cs, y);
188
+ qr_mc.lineTo(x + cs, y + cs);
189
+ qr_mc.lineTo(x, y + cs);
190
+ qr_mc.endFill();
191
+ }
192
+ }
193
+ }
194
+ return qr_mc;
195
+ },
196
+ setupTimingPattern: function () {
197
+ for (var r = 8; r < this.moduleCount - 8; r++) {
198
+ if (this.modules[r][6] != null) {
199
+ continue;
200
+ }
201
+ this.modules[r][6] = r % 2 == 0;
202
+ }
203
+ for (var c = 8; c < this.moduleCount - 8; c++) {
204
+ if (this.modules[6][c] != null) {
205
+ continue;
206
+ }
207
+ this.modules[6][c] = c % 2 == 0;
208
+ }
209
+ },
210
+ setupPositionAdjustPattern: function () {
211
+ var pos = QRUtil.getPatternPosition(this.typeNumber);
212
+ for (var i = 0; i < pos.length; i++) {
213
+ for (var j = 0; j < pos.length; j++) {
214
+ var row = pos[i];
215
+ var col = pos[j];
216
+ if (this.modules[row][col] != null) {
217
+ continue;
218
+ }
219
+ for (var r = -2; r <= 2; r++) {
220
+ for (var c = -2; c <= 2; c++) {
221
+ if (r == -2 || r == 2 || c == -2 || c == 2 || (r == 0 && c == 0)) {
222
+ this.modules[row + r][col + c] = true;
223
+ } else {
224
+ this.modules[row + r][col + c] = false;
225
+ }
226
+ }
227
+ }
228
+ }
229
+ }
230
+ },
231
+ setupTypeNumber: function (test) {
232
+ var bits = QRUtil.getBCHTypeNumber(this.typeNumber);
233
+ for (var i = 0; i < 18; i++) {
234
+ var mod = !test && ((bits >> i) & 1) == 1;
235
+ this.modules[Math.floor(i / 3)][(i % 3) + this.moduleCount - 8 - 3] = mod;
236
+ }
237
+ for (var i = 0; i < 18; i++) {
238
+ var mod = !test && ((bits >> i) & 1) == 1;
239
+ this.modules[(i % 3) + this.moduleCount - 8 - 3][Math.floor(i / 3)] = mod;
240
+ }
241
+ },
242
+ setupTypeInfo: function (test, maskPattern) {
243
+ var data = (this.errorCorrectLevel << 3) | maskPattern;
244
+ var bits = QRUtil.getBCHTypeInfo(data);
245
+ for (var i = 0; i < 15; i++) {
246
+ var mod = !test && ((bits >> i) & 1) == 1;
247
+ if (i < 6) {
248
+ this.modules[i][8] = mod;
249
+ } else if (i < 8) {
250
+ this.modules[i + 1][8] = mod;
251
+ } else {
252
+ this.modules[this.moduleCount - 15 + i][8] = mod;
253
+ }
254
+ }
255
+ for (var i = 0; i < 15; i++) {
256
+ var mod = !test && ((bits >> i) & 1) == 1;
257
+ if (i < 8) {
258
+ this.modules[8][this.moduleCount - i - 1] = mod;
259
+ } else if (i < 9) {
260
+ this.modules[8][15 - i - 1 + 1] = mod;
261
+ } else {
262
+ this.modules[8][15 - i - 1] = mod;
263
+ }
264
+ }
265
+ this.modules[this.moduleCount - 8][8] = !test;
266
+ },
267
+ mapData: function (data, maskPattern) {
268
+ var inc = -1;
269
+ var row = this.moduleCount - 1;
270
+ var bitIndex = 7;
271
+ var byteIndex = 0;
272
+ for (var col = this.moduleCount - 1; col > 0; col -= 2) {
273
+ if (col == 6) col--;
274
+ while (true) {
275
+ for (var c = 0; c < 2; c++) {
276
+ if (this.modules[row][col - c] == null) {
277
+ var dark = false;
278
+ if (byteIndex < data.length) {
279
+ dark = ((data[byteIndex] >>> bitIndex) & 1) == 1;
280
+ }
281
+ var mask = QRUtil.getMask(maskPattern, row, col - c);
282
+ if (mask) {
283
+ dark = !dark;
284
+ }
285
+ this.modules[row][col - c] = dark;
286
+ bitIndex--;
287
+ if (bitIndex == -1) {
288
+ byteIndex++;
289
+ bitIndex = 7;
290
+ }
291
+ }
292
+ }
293
+ row += inc;
294
+ if (row < 0 || this.moduleCount <= row) {
295
+ row -= inc;
296
+ inc = -inc;
297
+ break;
298
+ }
299
+ }
300
+ }
301
+ },
302
+ };
303
+ QRCodeModel.PAD0 = 0xec;
304
+ QRCodeModel.PAD1 = 0x11;
305
+ QRCodeModel.createData = function (typeNumber, errorCorrectLevel, dataList) {
306
+ var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel);
307
+ var buffer = new QRBitBuffer();
308
+ for (var i = 0; i < dataList.length; i++) {
309
+ var data = dataList[i];
310
+ buffer.put(data.mode, 4);
311
+ buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber));
312
+ data.write(buffer);
313
+ }
314
+ var totalDataCount = 0;
315
+ for (var i = 0; i < rsBlocks.length; i++) {
316
+ totalDataCount += rsBlocks[i].dataCount;
317
+ }
318
+ if (buffer.getLengthInBits() > totalDataCount * 8) {
319
+ throw new Error(
320
+ "code length overflow. (" +
321
+ buffer.getLengthInBits() +
322
+ ">" +
323
+ totalDataCount * 8 +
324
+ ")"
325
+ );
326
+ }
327
+ if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {
328
+ buffer.put(0, 4);
329
+ }
330
+ while (buffer.getLengthInBits() % 8 != 0) {
331
+ buffer.putBit(false);
332
+ }
333
+ while (true) {
334
+ if (buffer.getLengthInBits() >= totalDataCount * 8) {
335
+ break;
336
+ }
337
+ buffer.put(QRCodeModel.PAD0, 8);
338
+ if (buffer.getLengthInBits() >= totalDataCount * 8) {
339
+ break;
340
+ }
341
+ buffer.put(QRCodeModel.PAD1, 8);
342
+ }
343
+ return QRCodeModel.createBytes(buffer, rsBlocks);
344
+ };
345
+ QRCodeModel.createBytes = function (buffer, rsBlocks) {
346
+ var offset = 0;
347
+ var maxDcCount = 0;
348
+ var maxEcCount = 0;
349
+ var dcdata = new Array(rsBlocks.length);
350
+ var ecdata = new Array(rsBlocks.length);
351
+ for (var r = 0; r < rsBlocks.length; r++) {
352
+ var dcCount = rsBlocks[r].dataCount;
353
+ var ecCount = rsBlocks[r].totalCount - dcCount;
354
+ maxDcCount = Math.max(maxDcCount, dcCount);
355
+ maxEcCount = Math.max(maxEcCount, ecCount);
356
+ dcdata[r] = new Array(dcCount);
357
+ for (var i = 0; i < dcdata[r].length; i++) {
358
+ dcdata[r][i] = 0xff & buffer.buffer[i + offset];
359
+ }
360
+ offset += dcCount;
361
+ var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
362
+ var rawPoly = new QRPolynomial(dcdata[r], rsPoly.getLength() - 1);
363
+ var modPoly = rawPoly.mod(rsPoly);
364
+ ecdata[r] = new Array(rsPoly.getLength() - 1);
365
+ for (var i = 0; i < ecdata[r].length; i++) {
366
+ var modIndex = i + modPoly.getLength() - ecdata[r].length;
367
+ ecdata[r][i] = modIndex >= 0 ? modPoly.get(modIndex) : 0;
368
+ }
369
+ }
370
+ var totalCodeCount = 0;
371
+ for (var i = 0; i < rsBlocks.length; i++) {
372
+ totalCodeCount += rsBlocks[i].totalCount;
373
+ }
374
+ var data = new Array(totalCodeCount);
375
+ var index = 0;
376
+ for (var i = 0; i < maxDcCount; i++) {
377
+ for (var r = 0; r < rsBlocks.length; r++) {
378
+ if (i < dcdata[r].length) {
379
+ data[index++] = dcdata[r][i];
380
+ }
381
+ }
382
+ }
383
+ for (var i = 0; i < maxEcCount; i++) {
384
+ for (var r = 0; r < rsBlocks.length; r++) {
385
+ if (i < ecdata[r].length) {
386
+ data[index++] = ecdata[r][i];
387
+ }
388
+ }
389
+ }
390
+ return data;
391
+ };
392
+ var QRMode = {
393
+ MODE_NUMBER: 1 << 0,
394
+ MODE_ALPHA_NUM: 1 << 1,
395
+ MODE_8BIT_BYTE: 1 << 2,
396
+ MODE_KANJI: 1 << 3,
397
+ };
398
+ var QRErrorCorrectLevel = { L: 1, M: 0, Q: 3, H: 2 };
399
+ var QRMaskPattern = {
400
+ PATTERN000: 0,
401
+ PATTERN001: 1,
402
+ PATTERN010: 2,
403
+ PATTERN011: 3,
404
+ PATTERN100: 4,
405
+ PATTERN101: 5,
406
+ PATTERN110: 6,
407
+ PATTERN111: 7,
408
+ };
409
+ var QRUtil = {
410
+ PATTERN_POSITION_TABLE: [
411
+ [],
412
+ [6, 18],
413
+ [6, 22],
414
+ [6, 26],
415
+ [6, 30],
416
+ [6, 34],
417
+ [6, 22, 38],
418
+ [6, 24, 42],
419
+ [6, 26, 46],
420
+ [6, 28, 50],
421
+ [6, 30, 54],
422
+ [6, 32, 58],
423
+ [6, 34, 62],
424
+ [6, 26, 46, 66],
425
+ [6, 26, 48, 70],
426
+ [6, 26, 50, 74],
427
+ [6, 30, 54, 78],
428
+ [6, 30, 56, 82],
429
+ [6, 30, 58, 86],
430
+ [6, 34, 62, 90],
431
+ [6, 28, 50, 72, 94],
432
+ [6, 26, 50, 74, 98],
433
+ [6, 30, 54, 78, 102],
434
+ [6, 28, 54, 80, 106],
435
+ [6, 32, 58, 84, 110],
436
+ [6, 30, 58, 86, 114],
437
+ [6, 34, 62, 90, 118],
438
+ [6, 26, 50, 74, 98, 122],
439
+ [6, 30, 54, 78, 102, 126],
440
+ [6, 26, 52, 78, 104, 130],
441
+ [6, 30, 56, 82, 108, 134],
442
+ [6, 34, 60, 86, 112, 138],
443
+ [6, 30, 58, 86, 114, 142],
444
+ [6, 34, 62, 90, 118, 146],
445
+ [6, 30, 54, 78, 102, 126, 150],
446
+ [6, 24, 50, 76, 102, 128, 154],
447
+ [6, 28, 54, 80, 106, 132, 158],
448
+ [6, 32, 58, 84, 110, 136, 162],
449
+ [6, 26, 54, 82, 110, 138, 166],
450
+ [6, 30, 58, 86, 114, 142, 170],
451
+ ],
452
+ G15:
453
+ (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0),
454
+ G18:
455
+ (1 << 12) |
456
+ (1 << 11) |
457
+ (1 << 10) |
458
+ (1 << 9) |
459
+ (1 << 8) |
460
+ (1 << 5) |
461
+ (1 << 2) |
462
+ (1 << 0),
463
+ G15_MASK: (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1),
464
+ getBCHTypeInfo: function (data) {
465
+ var d = data << 10;
466
+ while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0) {
467
+ d ^=
468
+ QRUtil.G15 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15));
469
+ }
470
+ return ((data << 10) | d) ^ QRUtil.G15_MASK;
471
+ },
472
+ getBCHTypeNumber: function (data) {
473
+ var d = data << 12;
474
+ while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0) {
475
+ d ^=
476
+ QRUtil.G18 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18));
477
+ }
478
+ return (data << 12) | d;
479
+ },
480
+ getBCHDigit: function (data) {
481
+ var digit = 0;
482
+ while (data != 0) {
483
+ digit++;
484
+ data >>>= 1;
485
+ }
486
+ return digit;
487
+ },
488
+ getPatternPosition: function (typeNumber) {
489
+ return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1];
490
+ },
491
+ getMask: function (maskPattern, i, j) {
492
+ switch (maskPattern) {
493
+ case QRMaskPattern.PATTERN000:
494
+ return (i + j) % 2 == 0;
495
+ case QRMaskPattern.PATTERN001:
496
+ return i % 2 == 0;
497
+ case QRMaskPattern.PATTERN010:
498
+ return j % 3 == 0;
499
+ case QRMaskPattern.PATTERN011:
500
+ return (i + j) % 3 == 0;
501
+ case QRMaskPattern.PATTERN100:
502
+ return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 == 0;
503
+ case QRMaskPattern.PATTERN101:
504
+ return ((i * j) % 2) + ((i * j) % 3) == 0;
505
+ case QRMaskPattern.PATTERN110:
506
+ return (((i * j) % 2) + ((i * j) % 3)) % 2 == 0;
507
+ case QRMaskPattern.PATTERN111:
508
+ return (((i * j) % 3) + ((i + j) % 2)) % 2 == 0;
509
+ default:
510
+ throw new Error("bad maskPattern:" + maskPattern);
511
+ }
512
+ },
513
+ getErrorCorrectPolynomial: function (errorCorrectLength) {
514
+ var a = new QRPolynomial([1], 0);
515
+ for (var i = 0; i < errorCorrectLength; i++) {
516
+ a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0));
517
+ }
518
+ return a;
519
+ },
520
+ getLengthInBits: function (mode, type) {
521
+ if (1 <= type && type < 10) {
522
+ switch (mode) {
523
+ case QRMode.MODE_NUMBER:
524
+ return 10;
525
+ case QRMode.MODE_ALPHA_NUM:
526
+ return 9;
527
+ case QRMode.MODE_8BIT_BYTE:
528
+ return 8;
529
+ case QRMode.MODE_KANJI:
530
+ return 8;
531
+ default:
532
+ throw new Error("mode:" + mode);
533
+ }
534
+ } else if (type < 27) {
535
+ switch (mode) {
536
+ case QRMode.MODE_NUMBER:
537
+ return 12;
538
+ case QRMode.MODE_ALPHA_NUM:
539
+ return 11;
540
+ case QRMode.MODE_8BIT_BYTE:
541
+ return 16;
542
+ case QRMode.MODE_KANJI:
543
+ return 10;
544
+ default:
545
+ throw new Error("mode:" + mode);
546
+ }
547
+ } else if (type < 41) {
548
+ switch (mode) {
549
+ case QRMode.MODE_NUMBER:
550
+ return 14;
551
+ case QRMode.MODE_ALPHA_NUM:
552
+ return 13;
553
+ case QRMode.MODE_8BIT_BYTE:
554
+ return 16;
555
+ case QRMode.MODE_KANJI:
556
+ return 12;
557
+ default:
558
+ throw new Error("mode:" + mode);
559
+ }
560
+ } else {
561
+ throw new Error("type:" + type);
562
+ }
563
+ },
564
+ getLostPoint: function (qrCode) {
565
+ var moduleCount = qrCode.getModuleCount();
566
+ var lostPoint = 0;
567
+ for (var row = 0; row < moduleCount; row++) {
568
+ for (var col = 0; col < moduleCount; col++) {
569
+ var sameCount = 0;
570
+ var dark = qrCode.isDark(row, col);
571
+ for (var r = -1; r <= 1; r++) {
572
+ if (row + r < 0 || moduleCount <= row + r) {
573
+ continue;
574
+ }
575
+ for (var c = -1; c <= 1; c++) {
576
+ if (col + c < 0 || moduleCount <= col + c) {
577
+ continue;
578
+ }
579
+ if (r == 0 && c == 0) {
580
+ continue;
581
+ }
582
+ if (dark == qrCode.isDark(row + r, col + c)) {
583
+ sameCount++;
584
+ }
585
+ }
586
+ }
587
+ if (sameCount > 5) {
588
+ lostPoint += 3 + sameCount - 5;
589
+ }
590
+ }
591
+ }
592
+ for (var row = 0; row < moduleCount - 1; row++) {
593
+ for (var col = 0; col < moduleCount - 1; col++) {
594
+ var count = 0;
595
+ if (qrCode.isDark(row, col)) count++;
596
+ if (qrCode.isDark(row + 1, col)) count++;
597
+ if (qrCode.isDark(row, col + 1)) count++;
598
+ if (qrCode.isDark(row + 1, col + 1)) count++;
599
+ if (count == 0 || count == 4) {
600
+ lostPoint += 3;
601
+ }
602
+ }
603
+ }
604
+ for (var row = 0; row < moduleCount; row++) {
605
+ for (var col = 0; col < moduleCount - 6; col++) {
606
+ if (
607
+ qrCode.isDark(row, col) &&
608
+ !qrCode.isDark(row, col + 1) &&
609
+ qrCode.isDark(row, col + 2) &&
610
+ qrCode.isDark(row, col + 3) &&
611
+ qrCode.isDark(row, col + 4) &&
612
+ !qrCode.isDark(row, col + 5) &&
613
+ qrCode.isDark(row, col + 6)
614
+ ) {
615
+ lostPoint += 40;
616
+ }
617
+ }
618
+ }
619
+ for (var col = 0; col < moduleCount; col++) {
620
+ for (var row = 0; row < moduleCount - 6; row++) {
621
+ if (
622
+ qrCode.isDark(row, col) &&
623
+ !qrCode.isDark(row + 1, col) &&
624
+ qrCode.isDark(row + 2, col) &&
625
+ qrCode.isDark(row + 3, col) &&
626
+ qrCode.isDark(row + 4, col) &&
627
+ !qrCode.isDark(row + 5, col) &&
628
+ qrCode.isDark(row + 6, col)
629
+ ) {
630
+ lostPoint += 40;
631
+ }
632
+ }
633
+ }
634
+ var darkCount = 0;
635
+ for (var col = 0; col < moduleCount; col++) {
636
+ for (var row = 0; row < moduleCount; row++) {
637
+ if (qrCode.isDark(row, col)) {
638
+ darkCount++;
639
+ }
640
+ }
641
+ }
642
+ var ratio =
643
+ Math.abs((100 * darkCount) / moduleCount / moduleCount - 50) / 5;
644
+ lostPoint += ratio * 10;
645
+ return lostPoint;
646
+ },
647
+ };
648
+ var QRMath = {
649
+ glog: function (n) {
650
+ if (n < 1) {
651
+ throw new Error("glog(" + n + ")");
652
+ }
653
+ return QRMath.LOG_TABLE[n];
654
+ },
655
+ gexp: function (n) {
656
+ while (n < 0) {
657
+ n += 255;
658
+ }
659
+ while (n >= 256) {
660
+ n -= 255;
661
+ }
662
+ return QRMath.EXP_TABLE[n];
663
+ },
664
+ EXP_TABLE: new Array(256),
665
+ LOG_TABLE: new Array(256),
666
+ };
667
+ for (var i = 0; i < 8; i++) {
668
+ QRMath.EXP_TABLE[i] = 1 << i;
669
+ }
670
+ for (var i = 8; i < 256; i++) {
671
+ QRMath.EXP_TABLE[i] =
672
+ QRMath.EXP_TABLE[i - 4] ^
673
+ QRMath.EXP_TABLE[i - 5] ^
674
+ QRMath.EXP_TABLE[i - 6] ^
675
+ QRMath.EXP_TABLE[i - 8];
676
+ }
677
+ for (var i = 0; i < 255; i++) {
678
+ QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]] = i;
679
+ }
680
+ function QRPolynomial(num, shift) {
681
+ if (num.length == undefined) {
682
+ throw new Error(num.length + "/" + shift);
683
+ }
684
+ var offset = 0;
685
+ while (offset < num.length && num[offset] == 0) {
686
+ offset++;
687
+ }
688
+ this.num = new Array(num.length - offset + shift);
689
+ for (var i = 0; i < num.length - offset; i++) {
690
+ this.num[i] = num[i + offset];
691
+ }
692
+ }
693
+ QRPolynomial.prototype = {
694
+ get: function (index) {
695
+ return this.num[index];
696
+ },
697
+ getLength: function () {
698
+ return this.num.length;
699
+ },
700
+ multiply: function (e) {
701
+ var num = new Array(this.getLength() + e.getLength() - 1);
702
+ for (var i = 0; i < this.getLength(); i++) {
703
+ for (var j = 0; j < e.getLength(); j++) {
704
+ num[i + j] ^= QRMath.gexp(
705
+ QRMath.glog(this.get(i)) + QRMath.glog(e.get(j))
706
+ );
707
+ }
708
+ }
709
+ return new QRPolynomial(num, 0);
710
+ },
711
+ mod: function (e) {
712
+ if (this.getLength() - e.getLength() < 0) {
713
+ return this;
714
+ }
715
+ var ratio = QRMath.glog(this.get(0)) - QRMath.glog(e.get(0));
716
+ var num = new Array(this.getLength());
717
+ for (var i = 0; i < this.getLength(); i++) {
718
+ num[i] = this.get(i);
719
+ }
720
+ for (var i = 0; i < e.getLength(); i++) {
721
+ num[i] ^= QRMath.gexp(QRMath.glog(e.get(i)) + ratio);
722
+ }
723
+ return new QRPolynomial(num, 0).mod(e);
724
+ },
725
+ };
726
+ function QRRSBlock(totalCount, dataCount) {
727
+ this.totalCount = totalCount;
728
+ this.dataCount = dataCount;
729
+ }
730
+ QRRSBlock.RS_BLOCK_TABLE = [
731
+ [1, 26, 19],
732
+ [1, 26, 16],
733
+ [1, 26, 13],
734
+ [1, 26, 9],
735
+ [1, 44, 34],
736
+ [1, 44, 28],
737
+ [1, 44, 22],
738
+ [1, 44, 16],
739
+ [1, 70, 55],
740
+ [1, 70, 44],
741
+ [2, 35, 17],
742
+ [2, 35, 13],
743
+ [1, 100, 80],
744
+ [2, 50, 32],
745
+ [2, 50, 24],
746
+ [4, 25, 9],
747
+ [1, 134, 108],
748
+ [2, 67, 43],
749
+ [2, 33, 15, 2, 34, 16],
750
+ [2, 33, 11, 2, 34, 12],
751
+ [2, 86, 68],
752
+ [4, 43, 27],
753
+ [4, 43, 19],
754
+ [4, 43, 15],
755
+ [2, 98, 78],
756
+ [4, 49, 31],
757
+ [2, 32, 14, 4, 33, 15],
758
+ [4, 39, 13, 1, 40, 14],
759
+ [2, 121, 97],
760
+ [2, 60, 38, 2, 61, 39],
761
+ [4, 40, 18, 2, 41, 19],
762
+ [4, 40, 14, 2, 41, 15],
763
+ [2, 146, 116],
764
+ [3, 58, 36, 2, 59, 37],
765
+ [4, 36, 16, 4, 37, 17],
766
+ [4, 36, 12, 4, 37, 13],
767
+ [2, 86, 68, 2, 87, 69],
768
+ [4, 69, 43, 1, 70, 44],
769
+ [6, 43, 19, 2, 44, 20],
770
+ [6, 43, 15, 2, 44, 16],
771
+ [4, 101, 81],
772
+ [1, 80, 50, 4, 81, 51],
773
+ [4, 50, 22, 4, 51, 23],
774
+ [3, 36, 12, 8, 37, 13],
775
+ [2, 116, 92, 2, 117, 93],
776
+ [6, 58, 36, 2, 59, 37],
777
+ [4, 46, 20, 6, 47, 21],
778
+ [7, 42, 14, 4, 43, 15],
779
+ [4, 133, 107],
780
+ [8, 59, 37, 1, 60, 38],
781
+ [8, 44, 20, 4, 45, 21],
782
+ [12, 33, 11, 4, 34, 12],
783
+ [3, 145, 115, 1, 146, 116],
784
+ [4, 64, 40, 5, 65, 41],
785
+ [11, 36, 16, 5, 37, 17],
786
+ [11, 36, 12, 5, 37, 13],
787
+ [5, 109, 87, 1, 110, 88],
788
+ [5, 65, 41, 5, 66, 42],
789
+ [5, 54, 24, 7, 55, 25],
790
+ [11, 36, 12],
791
+ [5, 122, 98, 1, 123, 99],
792
+ [7, 73, 45, 3, 74, 46],
793
+ [15, 43, 19, 2, 44, 20],
794
+ [3, 45, 15, 13, 46, 16],
795
+ [1, 135, 107, 5, 136, 108],
796
+ [10, 74, 46, 1, 75, 47],
797
+ [1, 50, 22, 15, 51, 23],
798
+ [2, 42, 14, 17, 43, 15],
799
+ [5, 150, 120, 1, 151, 121],
800
+ [9, 69, 43, 4, 70, 44],
801
+ [17, 50, 22, 1, 51, 23],
802
+ [2, 42, 14, 19, 43, 15],
803
+ [3, 141, 113, 4, 142, 114],
804
+ [3, 70, 44, 11, 71, 45],
805
+ [17, 47, 21, 4, 48, 22],
806
+ [9, 39, 13, 16, 40, 14],
807
+ [3, 135, 107, 5, 136, 108],
808
+ [3, 67, 41, 13, 68, 42],
809
+ [15, 54, 24, 5, 55, 25],
810
+ [15, 43, 15, 10, 44, 16],
811
+ [4, 144, 116, 4, 145, 117],
812
+ [17, 68, 42],
813
+ [17, 50, 22, 6, 51, 23],
814
+ [19, 46, 16, 6, 47, 17],
815
+ [2, 139, 111, 7, 140, 112],
816
+ [17, 74, 46],
817
+ [7, 54, 24, 16, 55, 25],
818
+ [34, 37, 13],
819
+ [4, 151, 121, 5, 152, 122],
820
+ [4, 75, 47, 14, 76, 48],
821
+ [11, 54, 24, 14, 55, 25],
822
+ [16, 45, 15, 14, 46, 16],
823
+ [6, 147, 117, 4, 148, 118],
824
+ [6, 73, 45, 14, 74, 46],
825
+ [11, 54, 24, 16, 55, 25],
826
+ [30, 46, 16, 2, 47, 17],
827
+ [8, 132, 106, 4, 133, 107],
828
+ [8, 75, 47, 13, 76, 48],
829
+ [7, 54, 24, 22, 55, 25],
830
+ [22, 45, 15, 13, 46, 16],
831
+ [10, 142, 114, 2, 143, 115],
832
+ [19, 74, 46, 4, 75, 47],
833
+ [28, 50, 22, 6, 51, 23],
834
+ [33, 46, 16, 4, 47, 17],
835
+ [8, 152, 122, 4, 153, 123],
836
+ [22, 73, 45, 3, 74, 46],
837
+ [8, 53, 23, 26, 54, 24],
838
+ [12, 45, 15, 28, 46, 16],
839
+ [3, 147, 117, 10, 148, 118],
840
+ [3, 73, 45, 23, 74, 46],
841
+ [4, 54, 24, 31, 55, 25],
842
+ [11, 45, 15, 31, 46, 16],
843
+ [7, 146, 116, 7, 147, 117],
844
+ [21, 73, 45, 7, 74, 46],
845
+ [1, 53, 23, 37, 54, 24],
846
+ [19, 45, 15, 26, 46, 16],
847
+ [5, 145, 115, 10, 146, 116],
848
+ [19, 75, 47, 10, 76, 48],
849
+ [15, 54, 24, 25, 55, 25],
850
+ [23, 45, 15, 25, 46, 16],
851
+ [13, 145, 115, 3, 146, 116],
852
+ [2, 74, 46, 29, 75, 47],
853
+ [42, 54, 24, 1, 55, 25],
854
+ [23, 45, 15, 28, 46, 16],
855
+ [17, 145, 115],
856
+ [10, 74, 46, 23, 75, 47],
857
+ [10, 54, 24, 35, 55, 25],
858
+ [19, 45, 15, 35, 46, 16],
859
+ [17, 145, 115, 1, 146, 116],
860
+ [14, 74, 46, 21, 75, 47],
861
+ [29, 54, 24, 19, 55, 25],
862
+ [11, 45, 15, 46, 46, 16],
863
+ [13, 145, 115, 6, 146, 116],
864
+ [14, 74, 46, 23, 75, 47],
865
+ [44, 54, 24, 7, 55, 25],
866
+ [59, 46, 16, 1, 47, 17],
867
+ [12, 151, 121, 7, 152, 122],
868
+ [12, 75, 47, 26, 76, 48],
869
+ [39, 54, 24, 14, 55, 25],
870
+ [22, 45, 15, 41, 46, 16],
871
+ [6, 151, 121, 14, 152, 122],
872
+ [6, 75, 47, 34, 76, 48],
873
+ [46, 54, 24, 10, 55, 25],
874
+ [2, 45, 15, 64, 46, 16],
875
+ [17, 152, 122, 4, 153, 123],
876
+ [29, 74, 46, 14, 75, 47],
877
+ [49, 54, 24, 10, 55, 25],
878
+ [24, 45, 15, 46, 46, 16],
879
+ [4, 152, 122, 18, 153, 123],
880
+ [13, 74, 46, 32, 75, 47],
881
+ [48, 54, 24, 14, 55, 25],
882
+ [42, 45, 15, 32, 46, 16],
883
+ [20, 147, 117, 4, 148, 118],
884
+ [40, 75, 47, 7, 76, 48],
885
+ [43, 54, 24, 22, 55, 25],
886
+ [10, 45, 15, 67, 46, 16],
887
+ [19, 148, 118, 6, 149, 119],
888
+ [18, 75, 47, 31, 76, 48],
889
+ [34, 54, 24, 34, 55, 25],
890
+ [20, 45, 15, 61, 46, 16],
891
+ ];
892
+ QRRSBlock.getRSBlocks = function (typeNumber, errorCorrectLevel) {
893
+ var rsBlock = QRRSBlock.getRsBlockTable(typeNumber, errorCorrectLevel);
894
+ if (rsBlock == undefined) {
895
+ throw new Error(
896
+ "bad rs block @ typeNumber:" +
897
+ typeNumber +
898
+ "/errorCorrectLevel:" +
899
+ errorCorrectLevel
900
+ );
901
+ }
902
+ var length = rsBlock.length / 3;
903
+ var list = [];
904
+ for (var i = 0; i < length; i++) {
905
+ var count = rsBlock[i * 3 + 0];
906
+ var totalCount = rsBlock[i * 3 + 1];
907
+ var dataCount = rsBlock[i * 3 + 2];
908
+ for (var j = 0; j < count; j++) {
909
+ list.push(new QRRSBlock(totalCount, dataCount));
910
+ }
911
+ }
912
+ return list;
913
+ };
914
+ QRRSBlock.getRsBlockTable = function (typeNumber, errorCorrectLevel) {
915
+ switch (errorCorrectLevel) {
916
+ case QRErrorCorrectLevel.L:
917
+ return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];
918
+ case QRErrorCorrectLevel.M:
919
+ return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];
920
+ case QRErrorCorrectLevel.Q:
921
+ return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];
922
+ case QRErrorCorrectLevel.H:
923
+ return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];
924
+ default:
925
+ return undefined;
926
+ }
927
+ };
928
+ function QRBitBuffer() {
929
+ this.buffer = [];
930
+ this.length = 0;
931
+ }
932
+ QRBitBuffer.prototype = {
933
+ get: function (index) {
934
+ var bufIndex = Math.floor(index / 8);
935
+ return ((this.buffer[bufIndex] >>> (7 - (index % 8))) & 1) == 1;
936
+ },
937
+ put: function (num, length) {
938
+ for (var i = 0; i < length; i++) {
939
+ this.putBit(((num >>> (length - i - 1)) & 1) == 1);
940
+ }
941
+ },
942
+ getLengthInBits: function () {
943
+ return this.length;
944
+ },
945
+ putBit: function (bit) {
946
+ var bufIndex = Math.floor(this.length / 8);
947
+ if (this.buffer.length <= bufIndex) {
948
+ this.buffer.push(0);
949
+ }
950
+ if (bit) {
951
+ this.buffer[bufIndex] |= 0x80 >>> this.length % 8;
952
+ }
953
+ this.length++;
954
+ },
955
+ };
956
+ var QRCodeLimitLength = [
957
+ [17, 14, 11, 7],
958
+ [32, 26, 20, 14],
959
+ [53, 42, 32, 24],
960
+ [78, 62, 46, 34],
961
+ [106, 84, 60, 44],
962
+ [134, 106, 74, 58],
963
+ [154, 122, 86, 64],
964
+ [192, 152, 108, 84],
965
+ [230, 180, 130, 98],
966
+ [271, 213, 151, 119],
967
+ [321, 251, 177, 137],
968
+ [367, 287, 203, 155],
969
+ [425, 331, 241, 177],
970
+ [458, 362, 258, 194],
971
+ [520, 412, 292, 220],
972
+ [586, 450, 322, 250],
973
+ [644, 504, 364, 280],
974
+ [718, 560, 394, 310],
975
+ [792, 624, 442, 338],
976
+ [858, 666, 482, 382],
977
+ [929, 711, 509, 403],
978
+ [1003, 779, 565, 439],
979
+ [1091, 857, 611, 461],
980
+ [1171, 911, 661, 511],
981
+ [1273, 997, 715, 535],
982
+ [1367, 1059, 751, 593],
983
+ [1465, 1125, 805, 625],
984
+ [1528, 1190, 868, 658],
985
+ [1628, 1264, 908, 698],
986
+ [1732, 1370, 982, 742],
987
+ [1840, 1452, 1030, 790],
988
+ [1952, 1538, 1112, 842],
989
+ [2068, 1628, 1168, 898],
990
+ [2188, 1722, 1228, 958],
991
+ [2303, 1809, 1283, 983],
992
+ [2431, 1911, 1351, 1051],
993
+ [2563, 1989, 1423, 1093],
994
+ [2699, 2099, 1499, 1139],
995
+ [2809, 2213, 1579, 1219],
996
+ [2953, 2331, 1663, 1273],
997
+ ];
998
+
999
+ //---------------------------------------------------------------QR Code Object-----------------------------------------------------------------
1000
+
1001
+ /** Constructor */
1002
+ function QRCode(options) {
1003
+ var instance = this;
1004
+
1005
+ //Default options
1006
+ this.options = {
1007
+ padding: 0,
1008
+ width: 256,
1009
+ height: 256,
1010
+ typeNumber: 4,
1011
+ color: "#000000",
1012
+ background: "#ffffff",
1013
+ ecl: "H",
1014
+ };
1015
+
1016
+ //In case the options is string
1017
+ if (typeof options === "string") {
1018
+ options = {
1019
+ content: options,
1020
+ };
1021
+ }
1022
+
1023
+ //Merge options
1024
+ if (options) {
1025
+ for (var i in options) {
1026
+ this.options[i] = options[i];
1027
+ }
1028
+ }
1029
+
1030
+ if (typeof this.options.content !== "string") {
1031
+ throw new Error("Expected 'content' as string!");
1032
+ }
1033
+
1034
+ if (
1035
+ this.options.content.length ===
1036
+ 0 /* || this.options.content.length > 7089 */
1037
+ ) {
1038
+ throw new Error("Expected 'content' to be non-empty!");
1039
+ }
1040
+
1041
+ if (!(this.options.padding >= 0)) {
1042
+ throw new Error("Expected 'padding' value to be non-negative!");
1043
+ }
1044
+
1045
+ if (!(this.options.width > 0) || !(this.options.height > 0)) {
1046
+ throw new Error(
1047
+ "Expected 'width' or 'height' value to be higher than zero!"
1048
+ );
1049
+ }
1050
+
1051
+ //Gets the error correction level
1052
+ function _getErrorCorrectLevel(ecl) {
1053
+ switch (ecl) {
1054
+ case "L":
1055
+ return QRErrorCorrectLevel.L;
1056
+
1057
+ case "M":
1058
+ return QRErrorCorrectLevel.M;
1059
+
1060
+ case "Q":
1061
+ return QRErrorCorrectLevel.Q;
1062
+
1063
+ case "H":
1064
+ return QRErrorCorrectLevel.H;
1065
+
1066
+ default:
1067
+ throw new Error("Unknown error correction level: " + ecl);
1068
+ }
1069
+ }
1070
+
1071
+ //Get type number
1072
+ function _getTypeNumber(content, ecl) {
1073
+ var length = _getUTF8Length(content);
1074
+
1075
+ var type = 1;
1076
+ var limit = 0;
1077
+ for (var i = 0, len = QRCodeLimitLength.length; i <= len; i++) {
1078
+ var table = QRCodeLimitLength[i];
1079
+ if (!table) {
1080
+ throw new Error(
1081
+ "Content too long: expected " + limit + " but got " + length
1082
+ );
1083
+ }
1084
+
1085
+ switch (ecl) {
1086
+ case "L":
1087
+ limit = table[0];
1088
+ break;
1089
+
1090
+ case "M":
1091
+ limit = table[1];
1092
+ break;
1093
+
1094
+ case "Q":
1095
+ limit = table[2];
1096
+ break;
1097
+
1098
+ case "H":
1099
+ limit = table[3];
1100
+ break;
1101
+
1102
+ default:
1103
+ throw new Error("Unknwon error correction level: " + ecl);
1104
+ }
1105
+
1106
+ if (length <= limit) {
1107
+ break;
1108
+ }
1109
+
1110
+ type++;
1111
+ }
1112
+
1113
+ if (type > QRCodeLimitLength.length) {
1114
+ throw new Error("Content too long");
1115
+ }
1116
+
1117
+ return type;
1118
+ }
1119
+
1120
+ //Gets text length
1121
+ function _getUTF8Length(content) {
1122
+ var result = encodeURI(content)
1123
+ .toString()
1124
+ .replace(/\%[0-9a-fA-F]{2}/g, "a");
1125
+ return result.length + (result.length != content ? 3 : 0);
1126
+ }
1127
+
1128
+ //Generate QR Code matrix
1129
+ var content = this.options.content;
1130
+ var type = _getTypeNumber(content, this.options.ecl);
1131
+ var ecl = _getErrorCorrectLevel(this.options.ecl);
1132
+ this.qrcode = new QRCodeModel(type, ecl);
1133
+ this.qrcode.addData(content);
1134
+ this.qrcode.make();
1135
+ }
1136
+
1137
+ //----------------------------------------------------Drawing out the QR Code as an SVG image------------------------------------------------------------
1138
+
1139
+ /** Generates QR Code as SVG image */
1140
+ QRCode.prototype.svg = function (opt) {
1141
+ if (typeof opt == "undefined") {
1142
+ opt = { container: "svg" };
1143
+ }
1144
+
1145
+ var options = this.options;
1146
+ var modules = this.qrcode.modules;
1147
+
1148
+ var EOL = "\r\n";
1149
+ var width = options.width;
1150
+ var height = options.height;
1151
+ var length = modules.length;
1152
+ var style = options.style;
1153
+ var xsize = width / length;
1154
+ var ysize = height / length;
1155
+
1156
+ var rect =
1157
+ '<rect x="0" y="0" width="' +
1158
+ width +
1159
+ '" height="' +
1160
+ height +
1161
+ '" style="fill:' +
1162
+ options.background +
1163
+ ';shape-rendering:crispEdges;"/>' +
1164
+ EOL;
1165
+
1166
+ //Add the SVG element of each square in the body of the QR Code
1167
+ for (var y = 0; y < length; y++) {
1168
+ for (var x = 0; x < length; x++) {
1169
+ var module = modules[x][y];
1170
+ if (module) {
1171
+ //rect += '<path d="M'+px+' '+py+' L'+pointX+' '+pointY+' L'+px+' '+last+' Z" style="fill:' + options.color + ';shape-rendering:crispEdges;"/>' + EOL;
1172
+ //options.style = 'sharp-edge';
1173
+ rect += getShape(x, y, modules, options);
1174
+ //rect += '<rect rx="50" x="' + px + '" y="' + py + '" width="' + xsize + '" height="' + ysize + '" style="fill:' + options.color + ';shape-rendering:crispEdges;"/>' + EOL;
1175
+ }
1176
+ }
1177
+ }
1178
+
1179
+ //This works when creating a big black sharp-edge
1180
+ //rect = '<path d="M'+0+' '+0+' L'+width+' '+width+' L'+0+' '+width+' Z" style="fill:' + options.color + ';shape-rendering:crispEdges;"/>' + EOL;
1181
+
1182
+ var svg = "";
1183
+ switch (opt.container) {
1184
+ case "svg":
1185
+ // !!!! The following line of code may need access to the internet to run...
1186
+ svg +=
1187
+ '<?xml version="1.0" standalone="yes"?>' +
1188
+ EOL +
1189
+ '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="' +
1190
+ width +
1191
+ '" height="' +
1192
+ height +
1193
+ '">' +
1194
+ EOL;
1195
+ svg += rect;
1196
+ svg += "</svg>";
1197
+ break;
1198
+
1199
+ case "g":
1200
+ svg += '<g width="' + width + '" height="' + height + '">' + EOL;
1201
+ svg += rect;
1202
+ svg += "</g>";
1203
+ break;
1204
+
1205
+ default:
1206
+ svg += rect;
1207
+ break;
1208
+ }
1209
+
1210
+ return svg;
1211
+ };
1212
+
1213
+ /*Returns an svg element in the right shape determined by the surrounding modules and the qr code style*/
1214
+ function getShape(x, y, modules, options) {
1215
+ //Get the surrounding modules matrix
1216
+ var mod_matrix = {};
1217
+ mod_matrix.topLeft = x != 0 && y != 0 && modules[x - 1][y - 1];
1218
+ mod_matrix.top = y != 0 && modules[x][y - 1];
1219
+ mod_matrix.topRight =
1220
+ x != modules.length - 1 && y != 0 && modules[x + 1][y - 1];
1221
+ mod_matrix.left = x != 0 && modules[x - 1][y];
1222
+ mod_matrix.right = x != modules.length - 1 && modules[x + 1][y];
1223
+ mod_matrix.bottomLeft =
1224
+ x != 0 && y != modules.length - 1 && modules[x - 1][y + 1];
1225
+ mod_matrix.bottom = y != modules.length - 1 && modules[x][y + 1];
1226
+ mod_matrix.bottomRight =
1227
+ x != modules.length - 1 && y != modules.length - 1 && modules[x + 1][y + 1];
1228
+
1229
+ var surroundingCount = 0;
1230
+ if (mod_matrix.top) {
1231
+ surroundingCount++;
1232
+ }
1233
+ if (mod_matrix.left) {
1234
+ surroundingCount++;
1235
+ }
1236
+ if (mod_matrix.right) {
1237
+ surroundingCount++;
1238
+ }
1239
+ if (mod_matrix.bottom) {
1240
+ surroundingCount++;
1241
+ }
1242
+
1243
+ //Find out box shape from surroundingCount and the orientation of those surrounding modules
1244
+ switch (surroundingCount) {
1245
+ case 0:
1246
+ return getShapeZero(x, y, options, modules);
1247
+ case 1:
1248
+ return getShapeOne(x, y, options, modules, mod_matrix);
1249
+ case 2:
1250
+ return getShapeTwo(x, y, options, modules, mod_matrix);
1251
+ case 3:
1252
+ return getShapeThree(x, y, options, modules, mod_matrix);
1253
+ case 4:
1254
+ return getShapeFour(x, y, options, modules, mod_matrix);
1255
+ default:
1256
+ return getShapeZero(x, y, options, modules);
1257
+ }
1258
+ //This function checks that arrays a1 and a2 are the same:
1259
+ /* a1.length==a2.length && a1.every(function(v,i) { return v === a2[i]}) */
1260
+ }
1261
+
1262
+ //Returns an SVG element for a box with no surrounding boxes
1263
+ function getShapeZero(x, y, options, modules) {
1264
+ var EOL = "\r\n";
1265
+ var width = options.width;
1266
+ var height = options.height;
1267
+ var length = modules.length;
1268
+ var style = options.style;
1269
+ var xsize = width / length;
1270
+ var ysize = height / length;
1271
+ var px = x * xsize;
1272
+ var py = y * ysize;
1273
+
1274
+ switch (options.style) {
1275
+ case "square":
1276
+ return (
1277
+ '<rect x="' +
1278
+ px +
1279
+ '" y="' +
1280
+ py +
1281
+ '" width="' +
1282
+ xsize +
1283
+ '" height="' +
1284
+ ysize +
1285
+ '" style="fill:' +
1286
+ options.color +
1287
+ ';shape-rendering:crispEdges;"/>' +
1288
+ EOL
1289
+ );
1290
+ case "circle":
1291
+ return (
1292
+ '<rect rx="' +
1293
+ xsize +
1294
+ '" x="' +
1295
+ px +
1296
+ '" y="' +
1297
+ py +
1298
+ '" width="' +
1299
+ xsize +
1300
+ '" height="' +
1301
+ ysize +
1302
+ '" style="fill:' +
1303
+ options.color +
1304
+ ';shape-rendering:crispEdges;"/>' +
1305
+ EOL
1306
+ );
1307
+ case "sharp-edge":
1308
+ return (
1309
+ '<rect transform="rotate(45 ' +
1310
+ (px + xsize / 2) +
1311
+ " " +
1312
+ (py + ysize / 2) +
1313
+ ')" x="' +
1314
+ px +
1315
+ '" y="' +
1316
+ py +
1317
+ '" width="' +
1318
+ xsize +
1319
+ '" height="' +
1320
+ ysize +
1321
+ '" style="fill:' +
1322
+ options.color +
1323
+ ';shape-rendering:crispEdges;"/>' +
1324
+ EOL
1325
+ );
1326
+ case "ninja":
1327
+ return (
1328
+ '<g transform="translate(' +
1329
+ px +
1330
+ "," +
1331
+ py +
1332
+ ") scale(" +
1333
+ 1 +
1334
+ "," +
1335
+ 1 +
1336
+ ')"><g transform="" style="fill: rgb(255, 0, 0);"><path d="M0,14V0c0,0,9.15,4.38,14,0.55C14,0.55,14.24,14,0,14z"/></g></g>'
1337
+ );
1338
+ }
1339
+ }
1340
+
1341
+ //Returns an SVG element for a box with one surrounding box
1342
+ function getShapeOne(x, y, options, modules, mod_matrix) {
1343
+ var EOL = "\r\n";
1344
+ var width = options.width;
1345
+ var height = options.height;
1346
+ var length = modules.length;
1347
+ var style = options.style;
1348
+ var xsize = width / length;
1349
+ var ysize = height / length;
1350
+ var px = x * xsize;
1351
+ var py = y * ysize;
1352
+
1353
+ var orientation = 0;
1354
+ if (mod_matrix.right) {
1355
+ orientation = 90;
1356
+ } else if (mod_matrix.bottom) {
1357
+ orientation = 180;
1358
+ } else if (mod_matrix.left) {
1359
+ orientation = 270;
1360
+ }
1361
+
1362
+ //Returning a 1b
1363
+ switch (options.style) {
1364
+ case "square":
1365
+ return (
1366
+ '<rect transform="rotate(' +
1367
+ orientation +
1368
+ " " +
1369
+ (px + xsize / 2) +
1370
+ " " +
1371
+ (py + ysize / 2) +
1372
+ ')" x="' +
1373
+ px +
1374
+ '" y="' +
1375
+ py +
1376
+ '" width="' +
1377
+ xsize +
1378
+ '" height="' +
1379
+ ysize +
1380
+ '" style="fill:' +
1381
+ options.color +
1382
+ ';shape-rendering:crispEdges;"/>' +
1383
+ EOL
1384
+ );
1385
+ case "circle":
1386
+ return (
1387
+ '<rect transform="rotate(' +
1388
+ orientation +
1389
+ " " +
1390
+ (px + xsize / 2) +
1391
+ " " +
1392
+ (py + ysize / 2) +
1393
+ ')" rx="' +
1394
+ xsize +
1395
+ '" x="' +
1396
+ px +
1397
+ '" y="' +
1398
+ py +
1399
+ '" width="' +
1400
+ xsize +
1401
+ '" height="' +
1402
+ ysize +
1403
+ '" style="fill:' +
1404
+ options.color +
1405
+ ';shape-rendering:crispEdges;"/>' +
1406
+ EOL
1407
+ );
1408
+ case "sharp-edge":
1409
+ return (
1410
+ '<path transform="rotate(' +
1411
+ orientation +
1412
+ " " +
1413
+ (px + xsize / 2) +
1414
+ " " +
1415
+ (py + ysize / 2) +
1416
+ ')" d="M' +
1417
+ px +
1418
+ " " +
1419
+ py +
1420
+ " L" +
1421
+ (px + xsize) +
1422
+ " " +
1423
+ py +
1424
+ " L" +
1425
+ (px + xsize / 2) +
1426
+ " " +
1427
+ (py + ysize) +
1428
+ ' Z" style="fill:' +
1429
+ options.color +
1430
+ ';shape-rendering:crispEdges;"/>' +
1431
+ EOL
1432
+ );
1433
+ }
1434
+ }
1435
+
1436
+ //Returns an SVG element for a box with two surrounding boxes
1437
+ function getShapeTwo(x, y, options, modules, mod_matrix) {
1438
+ var EOL = "\r\n";
1439
+ var width = options.width;
1440
+ var height = options.height;
1441
+ var length = modules.length;
1442
+ var style = options.style;
1443
+ var xsize = width / length;
1444
+ var ysize = height / length;
1445
+ var px = x * xsize;
1446
+ var py = y * ysize;
1447
+
1448
+ //If in the middle of a straight line, return a 1b3b
1449
+ if (
1450
+ (mod_matrix.top && mod_matrix.bottom) ||
1451
+ (mod_matrix.left && mod_matrix.right)
1452
+ ) {
1453
+ var orientation = mod_matrix.top && mod_matrix.bottom ? 0 : 90;
1454
+ switch (options.style) {
1455
+ case "square":
1456
+ return (
1457
+ '<rect transform="rotate(' +
1458
+ orientation +
1459
+ " " +
1460
+ (px + xsize / 2) +
1461
+ " " +
1462
+ (py + ysize / 2) +
1463
+ ')" x="' +
1464
+ px +
1465
+ '" y="' +
1466
+ py +
1467
+ '" width="' +
1468
+ xsize +
1469
+ '" height="' +
1470
+ ysize +
1471
+ '" style="fill:' +
1472
+ options.color +
1473
+ ';shape-rendering:crispEdges;"/>' +
1474
+ EOL
1475
+ );
1476
+ case "circle":
1477
+ return (
1478
+ '<rect transform="rotate(' +
1479
+ orientation +
1480
+ " " +
1481
+ (px + xsize / 2) +
1482
+ " " +
1483
+ (py + ysize / 2) +
1484
+ ')" rx="' +
1485
+ xsize +
1486
+ '" x="' +
1487
+ px +
1488
+ '" y="' +
1489
+ py +
1490
+ '" width="' +
1491
+ xsize +
1492
+ '" height="' +
1493
+ ysize +
1494
+ '" style="fill:' +
1495
+ options.color +
1496
+ ';shape-rendering:crispEdges;"/>' +
1497
+ EOL
1498
+ );
1499
+ case "sharp-edge":
1500
+ return (
1501
+ '<rect transform="rotate(' +
1502
+ orientation +
1503
+ " " +
1504
+ (px + xsize / 2) +
1505
+ " " +
1506
+ (py + ysize / 2) +
1507
+ ')" x="' +
1508
+ px +
1509
+ '" y="' +
1510
+ py +
1511
+ '" width="' +
1512
+ xsize +
1513
+ '" height="' +
1514
+ ysize +
1515
+ '" style="fill:' +
1516
+ options.color +
1517
+ ';shape-rendering:crispEdges;"/>' +
1518
+ EOL
1519
+ );
1520
+ }
1521
+ }
1522
+
1523
+ //If a diagonal is in between the two surrounding (module is on a corner), return a 2a1b1a
1524
+ if (
1525
+ mod_matrix.topLeft ||
1526
+ mod_matrix.topRight ||
1527
+ mod_matrix.bottomLeft ||
1528
+ mod_matrix.bottomRight
1529
+ ) {
1530
+ var orientation = 0;
1531
+ if (mod_matrix.top && mod_matrix.topRight && mod_matrix.right) {
1532
+ orientation = 90;
1533
+ } else if (
1534
+ mod_matrix.right &&
1535
+ mod_matrix.bottomRight &&
1536
+ mod_matrix.bottom
1537
+ ) {
1538
+ orientation = 180;
1539
+ } else if (mod_matrix.left && mod_matrix.bottomLeft && mod_matrix.bottom) {
1540
+ orientation = 270;
1541
+ }
1542
+
1543
+ switch (options.style) {
1544
+ case "square":
1545
+ return (
1546
+ '<rect transform="rotate(' +
1547
+ orientation +
1548
+ " " +
1549
+ (px + xsize / 2) +
1550
+ " " +
1551
+ (py + ysize / 2) +
1552
+ ')" x="' +
1553
+ px +
1554
+ '" y="' +
1555
+ py +
1556
+ '" width="' +
1557
+ xsize +
1558
+ '" height="' +
1559
+ ysize +
1560
+ '" style="fill:' +
1561
+ options.color +
1562
+ ';shape-rendering:crispEdges;"/>' +
1563
+ EOL
1564
+ );
1565
+ case "circle":
1566
+ return (
1567
+ '<rect transform="rotate(' +
1568
+ orientation +
1569
+ " " +
1570
+ (px + xsize / 2) +
1571
+ " " +
1572
+ (py + ysize / 2) +
1573
+ ')" rx="' +
1574
+ xsize +
1575
+ '" x="' +
1576
+ px +
1577
+ '" y="' +
1578
+ py +
1579
+ '" width="' +
1580
+ xsize +
1581
+ '" height="' +
1582
+ ysize +
1583
+ '" style="fill:' +
1584
+ options.color +
1585
+ ';shape-rendering:crispEdges;"/>' +
1586
+ EOL
1587
+ );
1588
+ case "sharp-edge":
1589
+ return (
1590
+ '<rect transform="rotate(' +
1591
+ orientation +
1592
+ " " +
1593
+ (px + xsize / 2) +
1594
+ " " +
1595
+ (py + ysize / 2) +
1596
+ ')" x="' +
1597
+ px +
1598
+ '" y="' +
1599
+ py +
1600
+ '" width="' +
1601
+ xsize +
1602
+ '" height="' +
1603
+ ysize +
1604
+ '" style="fill:' +
1605
+ options.color +
1606
+ ';shape-rendering:crispEdges;"/>' +
1607
+ EOL
1608
+ );
1609
+ }
1610
+ }
1611
+
1612
+ //Else in the center of a right angle
1613
+ var orientation = 0;
1614
+ if (mod_matrix.top && mod_matrix.right) {
1615
+ orientation = 90;
1616
+ } else if (mod_matrix.right && mod_matrix.bottom) {
1617
+ orientation = 180;
1618
+ } else if (mod_matrix.bottom && mod_matrix.left) {
1619
+ orientation = 270;
1620
+ }
1621
+
1622
+ switch (options.style) {
1623
+ case "square":
1624
+ return (
1625
+ '<rect transform="rotate(' +
1626
+ orientation +
1627
+ " " +
1628
+ (px + xsize / 2) +
1629
+ " " +
1630
+ (py + ysize / 2) +
1631
+ ')" x="' +
1632
+ px +
1633
+ '" y="' +
1634
+ py +
1635
+ '" width="' +
1636
+ xsize +
1637
+ '" height="' +
1638
+ ysize +
1639
+ '" style="fill:' +
1640
+ options.color +
1641
+ ';shape-rendering:crispEdges;"/>' +
1642
+ EOL
1643
+ );
1644
+ case "circle":
1645
+ return (
1646
+ '<rect transform="rotate(' +
1647
+ orientation +
1648
+ " " +
1649
+ (px + xsize / 2) +
1650
+ " " +
1651
+ (py + ysize / 2) +
1652
+ ')" rx="' +
1653
+ xsize +
1654
+ '" x="' +
1655
+ px +
1656
+ '" y="' +
1657
+ py +
1658
+ '" width="' +
1659
+ xsize +
1660
+ '" height="' +
1661
+ ysize +
1662
+ '" style="fill:' +
1663
+ options.color +
1664
+ ';shape-rendering:crispEdges;"/>' +
1665
+ EOL
1666
+ );
1667
+ case "sharp-edge":
1668
+ return (
1669
+ '<rect transform="rotate(' +
1670
+ orientation +
1671
+ " " +
1672
+ (px + xsize / 2) +
1673
+ " " +
1674
+ (py + ysize / 2) +
1675
+ ')" x="' +
1676
+ px +
1677
+ '" y="' +
1678
+ py +
1679
+ '" width="' +
1680
+ xsize +
1681
+ '" height="' +
1682
+ ysize +
1683
+ '" style="fill:' +
1684
+ options.color +
1685
+ ';shape-rendering:crispEdges;"/>' +
1686
+ EOL
1687
+ );
1688
+ }
1689
+ }
1690
+
1691
+ //Returns an SVG element for a box with one surrounding box
1692
+ function getShapeThree(x, y, options, modules, mod_matrix) {
1693
+ var EOL = "\r\n";
1694
+ var width = options.width;
1695
+ var height = options.height;
1696
+ var length = modules.length;
1697
+ var style = options.style;
1698
+ var xsize = width / length;
1699
+ var ysize = height / length;
1700
+ var px = x * xsize;
1701
+ var py = y * ysize;
1702
+
1703
+ //in two supplementary right angle
1704
+ var orientation = 0;
1705
+ if (mod_matrix.top && mod_matrix.right && mod_matrix.bottom) {
1706
+ orientation = 90;
1707
+ } else if (mod_matrix.right && mod_matrix.bottom && mod_matrix.left) {
1708
+ orientation = 180;
1709
+ } else if (mod_matrix.bottom && mod_matrix.left && mod_matrix.top) {
1710
+ orientation = 270;
1711
+ }
1712
+
1713
+ switch (options.style) {
1714
+ case "square":
1715
+ return (
1716
+ '<rect transform="rotate(' +
1717
+ orientation +
1718
+ " " +
1719
+ (px + xsize / 2) +
1720
+ " " +
1721
+ (py + ysize / 2) +
1722
+ ')" x="' +
1723
+ px +
1724
+ '" y="' +
1725
+ py +
1726
+ '" width="' +
1727
+ xsize +
1728
+ '" height="' +
1729
+ ysize +
1730
+ '" style="fill:' +
1731
+ options.color +
1732
+ ';shape-rendering:crispEdges;"/>' +
1733
+ EOL
1734
+ );
1735
+ case "circle":
1736
+ return (
1737
+ '<rect transform="rotate(' +
1738
+ orientation +
1739
+ " " +
1740
+ (px + xsize / 2) +
1741
+ " " +
1742
+ (py + ysize / 2) +
1743
+ ')" rx="' +
1744
+ xsize +
1745
+ '" x="' +
1746
+ px +
1747
+ '" y="' +
1748
+ py +
1749
+ '" width="' +
1750
+ xsize +
1751
+ '" height="' +
1752
+ ysize +
1753
+ '" style="fill:' +
1754
+ options.color +
1755
+ ';shape-rendering:crispEdges;"/>' +
1756
+ EOL
1757
+ );
1758
+ case "sharp-edge":
1759
+ return (
1760
+ '<rect x="' +
1761
+ px +
1762
+ '" y="' +
1763
+ py +
1764
+ '" width="' +
1765
+ xsize +
1766
+ '" height="' +
1767
+ ysize +
1768
+ '" style="fill:' +
1769
+ options.color +
1770
+ ';shape-rendering:crispEdges;"/>' +
1771
+ EOL
1772
+ );
1773
+ }
1774
+ }
1775
+
1776
+ //Returns an SVG element for a box with one surrounding box
1777
+ function getShapeFour(x, y, options, modules, mod_matrix) {
1778
+ var EOL = "\r\n";
1779
+ var width = options.width;
1780
+ var height = options.height;
1781
+ var length = modules.length;
1782
+ var style = options.style;
1783
+ var xsize = width / length;
1784
+ var ysize = height / length;
1785
+ var px = x * xsize;
1786
+ var py = y * ysize;
1787
+
1788
+ //Else in the center of a horizontal-vertical cross
1789
+ var orientation = 0;
1790
+
1791
+ switch (options.style) {
1792
+ case "square":
1793
+ return (
1794
+ '<rect transform="rotate(' +
1795
+ orientation +
1796
+ " " +
1797
+ (px + xsize / 2) +
1798
+ " " +
1799
+ (py + ysize / 2) +
1800
+ ')" x="' +
1801
+ px +
1802
+ '" y="' +
1803
+ py +
1804
+ '" width="' +
1805
+ xsize +
1806
+ '" height="' +
1807
+ ysize +
1808
+ '" style="fill:' +
1809
+ options.color +
1810
+ ';shape-rendering:crispEdges;"/>' +
1811
+ EOL
1812
+ );
1813
+ case "circle":
1814
+ return (
1815
+ '<rect transform="rotate(' +
1816
+ orientation +
1817
+ " " +
1818
+ (px + xsize / 2) +
1819
+ " " +
1820
+ (py + ysize / 2) +
1821
+ ')" rx="' +
1822
+ xsize +
1823
+ '" x="' +
1824
+ px +
1825
+ '" y="' +
1826
+ py +
1827
+ '" width="' +
1828
+ xsize +
1829
+ '" height="' +
1830
+ ysize +
1831
+ '" style="fill:' +
1832
+ options.color +
1833
+ ';shape-rendering:crispEdges;"/>' +
1834
+ EOL
1835
+ );
1836
+ case "sharp-edge":
1837
+ return (
1838
+ '<rect transform="rotate(' +
1839
+ orientation +
1840
+ " " +
1841
+ (px + xsize / 2) +
1842
+ " " +
1843
+ (py + ysize / 2) +
1844
+ ')" x="' +
1845
+ px +
1846
+ '" y="' +
1847
+ py +
1848
+ '" width="' +
1849
+ xsize +
1850
+ '" height="' +
1851
+ ysize +
1852
+ '" style="fill:' +
1853
+ options.color +
1854
+ ';shape-rendering:crispEdges;"/>' +
1855
+ EOL
1856
+ );
1857
+ }
1858
+ }
1859
+
1860
+ if (typeof module != "undefined") {
1861
+ module.exports = { QRCode, generateQRCode };
1862
+ }