blob: 638cb0c4768b9096919c12cfdb3b5788ca62ac76 [file] [log] [blame]
binquan.qiu7f2665f2020-03-27 17:19:57 +08001//---------------------------------------------------------------------
2//
3// QR Code Generator for JavaScript
4//
5// Copyright (c) 2009 Kazuhiko Arase
6//
7// URL: http://www.d-project.com/
8//
9// Licensed under the MIT license:
10// http://www.opensource.org/licenses/mit-license.php
11//
12// The word 'QR Code' is registered trademark of
13// DENSO WAVE INCORPORATED
14// http://www.denso-wave.com/qrcode/faqpatent-e.html
15//
16//---------------------------------------------------------------------
17
18//---------------微信小程序基于base64生成二维码插件修改-------------------
19/*
20 * @Modified: Pudon
21 * @demoURL: https://github.com/Pudon/weapp-qrcode
22 * @Date: 2018-09-11 14:00:05
23 * @Last Modified by: Pudon
24 * @Last Modified time: 2018-09-12 16:33:19
25 */
26//---------------------------------------------------------------------
27
28/**
29 * qrcode
30 * @param typeNumber 1 to 40
31 * @param errorCorrectLevel 'L','M','Q','H'
32 */
33var qrcode = function(typeNumber, errorCorrectLevel) {
34
35 var PAD0 = 0xEC;
36 var PAD1 = 0x11;
37
38 var _typeNumber = typeNumber;
39 var _errorCorrectLevel = QRErrorCorrectLevel[errorCorrectLevel];
40 var _modules = null;
41 var _moduleCount = 0;
42 var _dataCache = null;
43 var _dataList = new Array();
44
45 var _this = {};
46
47 var makeImpl = function(test, maskPattern) {
48
49 _moduleCount = _typeNumber * 4 + 17;
50 _modules = function(moduleCount) {
51 var modules = new Array(moduleCount);
52 for (var row = 0; row < moduleCount; row += 1) {
53 modules[row] = new Array(moduleCount);
54 for (var col = 0; col < moduleCount; col += 1) {
55 modules[row][col] = null;
56 }
57 }
58 return modules;
59 }(_moduleCount);
60
61 setupPositionProbePattern(0, 0);
62 setupPositionProbePattern(_moduleCount - 7, 0);
63 setupPositionProbePattern(0, _moduleCount - 7);
64 setupPositionAdjustPattern();
65 setupTimingPattern();
66 setupTypeInfo(test, maskPattern);
67
68 if (_typeNumber >= 7) {
69 setupTypeNumber(test);
70 }
71
72 if (_dataCache == null) {
73 _dataCache = createData(_typeNumber, _errorCorrectLevel, _dataList);
74 }
75
76 mapData(_dataCache, maskPattern);
77 };
78
79 var setupPositionProbePattern = function(row, col) {
80
81 for (var r = -1; r <= 7; r += 1) {
82
83 if (row + r <= -1 || _moduleCount <= row + r) continue;
84
85 for (var c = -1; c <= 7; c += 1) {
86
87 if (col + c <= -1 || _moduleCount <= col + c) continue;
88
89 if ( (0 <= r && r <= 6 && (c == 0 || c == 6) )
90 || (0 <= c && c <= 6 && (r == 0 || r == 6) )
91 || (2 <= r && r <= 4 && 2 <= c && c <= 4) ) {
92 _modules[row + r][col + c] = true;
93 } else {
94 _modules[row + r][col + c] = false;
95 }
96 }
97 }
98 };
99
100 var getBestMaskPattern = function() {
101
102 var minLostPoint = 0;
103 var pattern = 0;
104
105 for (var i = 0; i < 8; i += 1) {
106
107 makeImpl(true, i);
108
109 var lostPoint = QRUtil.getLostPoint(_this);
110
111 if (i == 0 || minLostPoint > lostPoint) {
112 minLostPoint = lostPoint;
113 pattern = i;
114 }
115 }
116
117 return pattern;
118 };
119
120 var setupTimingPattern = function() {
121
122 for (var r = 8; r < _moduleCount - 8; r += 1) {
123 if (_modules[r][6] != null) {
124 continue;
125 }
126 _modules[r][6] = (r % 2 == 0);
127 }
128
129 for (var c = 8; c < _moduleCount - 8; c += 1) {
130 if (_modules[6][c] != null) {
131 continue;
132 }
133 _modules[6][c] = (c % 2 == 0);
134 }
135 };
136
137 var setupPositionAdjustPattern = function() {
138
139 var pos = QRUtil.getPatternPosition(_typeNumber);
140
141 for (var i = 0; i < pos.length; i += 1) {
142
143 for (var j = 0; j < pos.length; j += 1) {
144
145 var row = pos[i];
146 var col = pos[j];
147
148 if (_modules[row][col] != null) {
149 continue;
150 }
151
152 for (var r = -2; r <= 2; r += 1) {
153
154 for (var c = -2; c <= 2; c += 1) {
155
156 if (r == -2 || r == 2 || c == -2 || c == 2
157 || (r == 0 && c == 0) ) {
158 _modules[row + r][col + c] = true;
159 } else {
160 _modules[row + r][col + c] = false;
161 }
162 }
163 }
164 }
165 }
166 };
167
168 var setupTypeNumber = function(test) {
169
170 var bits = QRUtil.getBCHTypeNumber(_typeNumber);
171
172 for (var i = 0; i < 18; i += 1) {
173 var mod = (!test && ( (bits >> i) & 1) == 1);
174 _modules[Math.floor(i / 3)][i % 3 + _moduleCount - 8 - 3] = mod;
175 }
176
177 for (var i = 0; i < 18; i += 1) {
178 var mod = (!test && ( (bits >> i) & 1) == 1);
179 _modules[i % 3 + _moduleCount - 8 - 3][Math.floor(i / 3)] = mod;
180 }
181 };
182
183 var setupTypeInfo = function(test, maskPattern) {
184
185 var data = (_errorCorrectLevel << 3) | maskPattern;
186 var bits = QRUtil.getBCHTypeInfo(data);
187
188 // vertical
189 for (var i = 0; i < 15; i += 1) {
190
191 var mod = (!test && ( (bits >> i) & 1) == 1);
192
193 if (i < 6) {
194 _modules[i][8] = mod;
195 } else if (i < 8) {
196 _modules[i + 1][8] = mod;
197 } else {
198 _modules[_moduleCount - 15 + i][8] = mod;
199 }
200 }
201
202 // horizontal
203 for (var i = 0; i < 15; i += 1) {
204
205 var mod = (!test && ( (bits >> i) & 1) == 1);
206
207 if (i < 8) {
208 _modules[8][_moduleCount - i - 1] = mod;
209 } else if (i < 9) {
210 _modules[8][15 - i - 1 + 1] = mod;
211 } else {
212 _modules[8][15 - i - 1] = mod;
213 }
214 }
215
216 // fixed module
217 _modules[_moduleCount - 8][8] = (!test);
218 };
219
220 var mapData = function(data, maskPattern) {
221
222 var inc = -1;
223 var row = _moduleCount - 1;
224 var bitIndex = 7;
225 var byteIndex = 0;
226 var maskFunc = QRUtil.getMaskFunction(maskPattern);
227
228 for (var col = _moduleCount - 1; col > 0; col -= 2) {
229
230 if (col == 6) col -= 1;
231
232 while (true) {
233
234 for (var c = 0; c < 2; c += 1) {
235
236 if (_modules[row][col - c] == null) {
237
238 var dark = false;
239
240 if (byteIndex < data.length) {
241 dark = ( ( (data[byteIndex] >>> bitIndex) & 1) == 1);
242 }
243
244 var mask = maskFunc(row, col - c);
245
246 if (mask) {
247 dark = !dark;
248 }
249
250 _modules[row][col - c] = dark;
251 bitIndex -= 1;
252
253 if (bitIndex == -1) {
254 byteIndex += 1;
255 bitIndex = 7;
256 }
257 }
258 }
259
260 row += inc;
261
262 if (row < 0 || _moduleCount <= row) {
263 row -= inc;
264 inc = -inc;
265 break;
266 }
267 }
268 }
269 };
270
271 var createBytes = function(buffer, rsBlocks) {
272
273 var offset = 0;
274
275 var maxDcCount = 0;
276 var maxEcCount = 0;
277
278 var dcdata = new Array(rsBlocks.length);
279 var ecdata = new Array(rsBlocks.length);
280
281 for (var r = 0; r < rsBlocks.length; r += 1) {
282
283 var dcCount = rsBlocks[r].dataCount;
284 var ecCount = rsBlocks[r].totalCount - dcCount;
285
286 maxDcCount = Math.max(maxDcCount, dcCount);
287 maxEcCount = Math.max(maxEcCount, ecCount);
288
289 dcdata[r] = new Array(dcCount);
290
291 for (var i = 0; i < dcdata[r].length; i += 1) {
292 dcdata[r][i] = 0xff & buffer.getBuffer()[i + offset];
293 }
294 offset += dcCount;
295
296 var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
297 var rawPoly = qrPolynomial(dcdata[r], rsPoly.getLength() - 1);
298
299 var modPoly = rawPoly.mod(rsPoly);
300 ecdata[r] = new Array(rsPoly.getLength() - 1);
301 for (var i = 0; i < ecdata[r].length; i += 1) {
302 var modIndex = i + modPoly.getLength() - ecdata[r].length;
303 ecdata[r][i] = (modIndex >= 0)? modPoly.getAt(modIndex) : 0;
304 }
305 }
306
307 var totalCodeCount = 0;
308 for (var i = 0; i < rsBlocks.length; i += 1) {
309 totalCodeCount += rsBlocks[i].totalCount;
310 }
311
312 var data = new Array(totalCodeCount);
313 var index = 0;
314
315 for (var i = 0; i < maxDcCount; i += 1) {
316 for (var r = 0; r < rsBlocks.length; r += 1) {
317 if (i < dcdata[r].length) {
318 data[index] = dcdata[r][i];
319 index += 1;
320 }
321 }
322 }
323
324 for (var i = 0; i < maxEcCount; i += 1) {
325 for (var r = 0; r < rsBlocks.length; r += 1) {
326 if (i < ecdata[r].length) {
327 data[index] = ecdata[r][i];
328 index += 1;
329 }
330 }
331 }
332
333 return data;
334 };
335
336 var createData = function(typeNumber, errorCorrectLevel, dataList) {
337
338 var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel);
339
340 var buffer = qrBitBuffer();
341
342 for (var i = 0; i < dataList.length; i += 1) {
343 var data = dataList[i];
344 buffer.put(data.getMode(), 4);
345 buffer.put(data.getLength(), QRUtil.getLengthInBits(data.getMode(), typeNumber) );
346 data.write(buffer);
347 }
348
349 // calc num max data.
350 var totalDataCount = 0;
351 for (var i = 0; i < rsBlocks.length; i += 1) {
352 totalDataCount += rsBlocks[i].dataCount;
353 }
354
355 if (buffer.getLengthInBits() > totalDataCount * 8) {
356 throw new Error('code length overflow. ('
357 + buffer.getLengthInBits()
358 + '>'
359 + totalDataCount * 8
360 + ')');
361 }
362
363 // end code
364 if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {
365 buffer.put(0, 4);
366 }
367
368 // padding
369 while (buffer.getLengthInBits() % 8 != 0) {
370 buffer.putBit(false);
371 }
372
373 // padding
374 while (true) {
375
376 if (buffer.getLengthInBits() >= totalDataCount * 8) {
377 break;
378 }
379 buffer.put(PAD0, 8);
380
381 if (buffer.getLengthInBits() >= totalDataCount * 8) {
382 break;
383 }
384 buffer.put(PAD1, 8);
385 }
386
387 return createBytes(buffer, rsBlocks);
388 };
389
390 _this.addData = function(data) {
391 var newData = qr8BitByte(data);
392 _dataList.push(newData);
393 _dataCache = null;
394 };
395
396 _this.isDark = function(row, col) {
397 if (row < 0 || _moduleCount <= row || col < 0 || _moduleCount <= col) {
398 throw new Error(row + ',' + col);
399 }
400 return _modules[row][col];
401 };
402
403 _this.getModuleCount = function() {
404 return _moduleCount;
405 };
406
407 _this.make = function() {
408 makeImpl(false, getBestMaskPattern() );
409 };
410
411 _this.createTableTag = function(cellSize, margin) {
412
413 cellSize = cellSize || 2;
414 margin = (typeof margin == 'undefined')? cellSize * 4 : margin;
415
416 var qrHtml = '';
417
418 qrHtml += '<table style="';
419 qrHtml += ' border-width: 0px; border-style: none;';
420 qrHtml += ' border-collapse: collapse;';
421 qrHtml += ' padding: 0px; margin: ' + margin + 'px;';
422 qrHtml += '">';
423 qrHtml += '<tbody>';
424
425 for (var r = 0; r < _this.getModuleCount(); r += 1) {
426
427 qrHtml += '<tr>';
428
429 for (var c = 0; c < _this.getModuleCount(); c += 1) {
430 qrHtml += '<td style="';
431 qrHtml += ' border-width: 0px; border-style: none;';
432 qrHtml += ' border-collapse: collapse;';
433 qrHtml += ' padding: 0px; margin: 0px;';
434 qrHtml += ' width: ' + cellSize + 'px;';
435 qrHtml += ' height: ' + cellSize + 'px;';
436 qrHtml += ' background-color: ';
437 qrHtml += _this.isDark(r, c)? '#000000' : '#ffffff';
438 qrHtml += ';';
439 qrHtml += '"/>';
440 }
441
442 qrHtml += '</tr>';
443 }
444
445 qrHtml += '</tbody>';
446 qrHtml += '</table>';
447
448 return qrHtml;
449 };
450
451 _this.createImgTag = function(cellSize, margin, size) {
452
453 cellSize = cellSize || 2;
454 margin = (typeof margin == 'undefined')? cellSize * 4 : margin;
455
456 var min = margin;
457 var max = _this.getModuleCount() * cellSize + margin;
458
459 return createImgTag(size, size, function(x, y) {
460 if (min <= x && x < max && min <= y && y < max) {
461 var c = Math.floor( (x - min) / cellSize);
462 var r = Math.floor( (y - min) / cellSize);
463 return _this.isDark(r, c)? 0 : 1;
464 } else {
465 return 1;
466 }
467 } );
468 };
469
470 return _this;
471};
472
473//---------------------------------------------------------------------
474// qrcode.stringToBytes
475//---------------------------------------------------------------------
476
477qrcode.stringToBytes = function(s) {
478 var bytes = new Array();
479 for (var i = 0; i < s.length; i += 1) {
480 var c = s.charCodeAt(i);
481 bytes.push(c & 0xff);
482 }
483 return bytes;
484};
485
486//---------------------------------------------------------------------
487// qrcode.createStringToBytes
488//---------------------------------------------------------------------
489
490/**
491 * @param unicodeData base64 string of byte array.
492 * [16bit Unicode],[16bit Bytes], ...
493 * @param numChars
494 */
495qrcode.createStringToBytes = function(unicodeData, numChars) {
496
497 // create conversion map.
498
499 var unicodeMap = function() {
500
501 var bin = base64DecodeInputStream(unicodeData);
502 var read = function() {
503 var b = bin.read();
504 if (b == -1) throw new Error();
505 return b;
506 };
507
508 var count = 0;
509 var unicodeMap = {};
510 while (true) {
511 var b0 = bin.read();
512 if (b0 == -1) break;
513 var b1 = read();
514 var b2 = read();
515 var b3 = read();
516 var k = String.fromCharCode( (b0 << 8) | b1);
517 var v = (b2 << 8) | b3;
518 unicodeMap[k] = v;
519 count += 1;
520 }
521 if (count != numChars) {
522 throw new Error(count + ' != ' + numChars);
523 }
524
525 return unicodeMap;
526 }();
527
528 var unknownChar = '?'.charCodeAt(0);
529
530 return function(s) {
531 var bytes = new Array();
532 for (var i = 0; i < s.length; i += 1) {
533 var c = s.charCodeAt(i);
534 if (c < 128) {
535 bytes.push(c);
536 } else {
537 var b = unicodeMap[s.charAt(i)];
538 if (typeof b == 'number') {
539 if ( (b & 0xff) == b) {
540 // 1byte
541 bytes.push(b);
542 } else {
543 // 2bytes
544 bytes.push(b >>> 8);
545 bytes.push(b & 0xff);
546 }
547 } else {
548 bytes.push(unknownChar);
549 }
550 }
551 }
552 return bytes;
553 };
554};
555
556//---------------------------------------------------------------------
557// QRMode
558//---------------------------------------------------------------------
559
560var QRMode = {
561 MODE_NUMBER : 1 << 0,
562 MODE_ALPHA_NUM : 1 << 1,
563 MODE_8BIT_BYTE : 1 << 2,
564 MODE_KANJI : 1 << 3
565};
566
567//---------------------------------------------------------------------
568// QRErrorCorrectLevel
569//---------------------------------------------------------------------
570
571var QRErrorCorrectLevel = {
572 L : 1,
573 M : 0,
574 Q : 3,
575 H : 2
576};
577
578//---------------------------------------------------------------------
579// QRMaskPattern
580//---------------------------------------------------------------------
581
582var QRMaskPattern = {
583 PATTERN000 : 0,
584 PATTERN001 : 1,
585 PATTERN010 : 2,
586 PATTERN011 : 3,
587 PATTERN100 : 4,
588 PATTERN101 : 5,
589 PATTERN110 : 6,
590 PATTERN111 : 7
591};
592
593//---------------------------------------------------------------------
594// QRUtil
595//---------------------------------------------------------------------
596
597var QRUtil = function() {
598
599 var PATTERN_POSITION_TABLE = [
600 [],
601 [6, 18],
602 [6, 22],
603 [6, 26],
604 [6, 30],
605 [6, 34],
606 [6, 22, 38],
607 [6, 24, 42],
608 [6, 26, 46],
609 [6, 28, 50],
610 [6, 30, 54],
611 [6, 32, 58],
612 [6, 34, 62],
613 [6, 26, 46, 66],
614 [6, 26, 48, 70],
615 [6, 26, 50, 74],
616 [6, 30, 54, 78],
617 [6, 30, 56, 82],
618 [6, 30, 58, 86],
619 [6, 34, 62, 90],
620 [6, 28, 50, 72, 94],
621 [6, 26, 50, 74, 98],
622 [6, 30, 54, 78, 102],
623 [6, 28, 54, 80, 106],
624 [6, 32, 58, 84, 110],
625 [6, 30, 58, 86, 114],
626 [6, 34, 62, 90, 118],
627 [6, 26, 50, 74, 98, 122],
628 [6, 30, 54, 78, 102, 126],
629 [6, 26, 52, 78, 104, 130],
630 [6, 30, 56, 82, 108, 134],
631 [6, 34, 60, 86, 112, 138],
632 [6, 30, 58, 86, 114, 142],
633 [6, 34, 62, 90, 118, 146],
634 [6, 30, 54, 78, 102, 126, 150],
635 [6, 24, 50, 76, 102, 128, 154],
636 [6, 28, 54, 80, 106, 132, 158],
637 [6, 32, 58, 84, 110, 136, 162],
638 [6, 26, 54, 82, 110, 138, 166],
639 [6, 30, 58, 86, 114, 142, 170]
640 ];
641 var G15 = (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0);
642 var G18 = (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0);
643 var G15_MASK = (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1);
644
645 var _this = {};
646
647 var getBCHDigit = function(data) {
648 var digit = 0;
649 while (data != 0) {
650 digit += 1;
651 data >>>= 1;
652 }
653 return digit;
654 };
655
656 _this.getBCHTypeInfo = function(data) {
657 var d = data << 10;
658 while (getBCHDigit(d) - getBCHDigit(G15) >= 0) {
659 d ^= (G15 << (getBCHDigit(d) - getBCHDigit(G15) ) );
660 }
661 return ( (data << 10) | d) ^ G15_MASK;
662 };
663
664 _this.getBCHTypeNumber = function(data) {
665 var d = data << 12;
666 while (getBCHDigit(d) - getBCHDigit(G18) >= 0) {
667 d ^= (G18 << (getBCHDigit(d) - getBCHDigit(G18) ) );
668 }
669 return (data << 12) | d;
670 };
671
672 _this.getPatternPosition = function(typeNumber) {
673 return PATTERN_POSITION_TABLE[typeNumber - 1];
674 };
675
676 _this.getMaskFunction = function(maskPattern) {
677
678 switch (maskPattern) {
679
680 case QRMaskPattern.PATTERN000 :
681 return function(i, j) { return (i + j) % 2 == 0; };
682 case QRMaskPattern.PATTERN001 :
683 return function(i, j) { return i % 2 == 0; };
684 case QRMaskPattern.PATTERN010 :
685 return function(i, j) { return j % 3 == 0; };
686 case QRMaskPattern.PATTERN011 :
687 return function(i, j) { return (i + j) % 3 == 0; };
688 case QRMaskPattern.PATTERN100 :
689 return function(i, j) { return (Math.floor(i / 2) + Math.floor(j / 3) ) % 2 == 0; };
690 case QRMaskPattern.PATTERN101 :
691 return function(i, j) { return (i * j) % 2 + (i * j) % 3 == 0; };
692 case QRMaskPattern.PATTERN110 :
693 return function(i, j) { return ( (i * j) % 2 + (i * j) % 3) % 2 == 0; };
694 case QRMaskPattern.PATTERN111 :
695 return function(i, j) { return ( (i * j) % 3 + (i + j) % 2) % 2 == 0; };
696
697 default :
698 throw new Error('bad maskPattern:' + maskPattern);
699 }
700 };
701
702 _this.getErrorCorrectPolynomial = function(errorCorrectLength) {
703 var a = qrPolynomial([1], 0);
704 for (var i = 0; i < errorCorrectLength; i += 1) {
705 a = a.multiply(qrPolynomial([1, QRMath.gexp(i)], 0) );
706 }
707 return a;
708 };
709
710 _this.getLengthInBits = function(mode, type) {
711
712 if (1 <= type && type < 10) {
713
714 // 1 - 9
715
716 switch(mode) {
717 case QRMode.MODE_NUMBER : return 10;
718 case QRMode.MODE_ALPHA_NUM : return 9;
719 case QRMode.MODE_8BIT_BYTE : return 8;
720 case QRMode.MODE_KANJI : return 8;
721 default :
722 throw new Error('mode:' + mode);
723 }
724
725 } else if (type < 27) {
726
727 // 10 - 26
728
729 switch(mode) {
730 case QRMode.MODE_NUMBER : return 12;
731 case QRMode.MODE_ALPHA_NUM : return 11;
732 case QRMode.MODE_8BIT_BYTE : return 16;
733 case QRMode.MODE_KANJI : return 10;
734 default :
735 throw new Error('mode:' + mode);
736 }
737
738 } else if (type < 41) {
739
740 // 27 - 40
741
742 switch(mode) {
743 case QRMode.MODE_NUMBER : return 14;
744 case QRMode.MODE_ALPHA_NUM : return 13;
745 case QRMode.MODE_8BIT_BYTE : return 16;
746 case QRMode.MODE_KANJI : return 12;
747 default :
748 throw new Error('mode:' + mode);
749 }
750
751 } else {
752 throw new Error('type:' + type);
753 }
754 };
755
756 _this.getLostPoint = function(qrcode) {
757
758 var moduleCount = qrcode.getModuleCount();
759
760 var lostPoint = 0;
761
762 // LEVEL1
763
764 for (var row = 0; row < moduleCount; row += 1) {
765 for (var col = 0; col < moduleCount; col += 1) {
766
767 var sameCount = 0;
768 var dark = qrcode.isDark(row, col);
769
770 for (var r = -1; r <= 1; r += 1) {
771
772 if (row + r < 0 || moduleCount <= row + r) {
773 continue;
774 }
775
776 for (var c = -1; c <= 1; c += 1) {
777
778 if (col + c < 0 || moduleCount <= col + c) {
779 continue;
780 }
781
782 if (r == 0 && c == 0) {
783 continue;
784 }
785
786 if (dark == qrcode.isDark(row + r, col + c) ) {
787 sameCount += 1;
788 }
789 }
790 }
791
792 if (sameCount > 5) {
793 lostPoint += (3 + sameCount - 5);
794 }
795 }
796 };
797
798 // LEVEL2
799
800 for (var row = 0; row < moduleCount - 1; row += 1) {
801 for (var col = 0; col < moduleCount - 1; col += 1) {
802 var count = 0;
803 if (qrcode.isDark(row, col) ) count += 1;
804 if (qrcode.isDark(row + 1, col) ) count += 1;
805 if (qrcode.isDark(row, col + 1) ) count += 1;
806 if (qrcode.isDark(row + 1, col + 1) ) count += 1;
807 if (count == 0 || count == 4) {
808 lostPoint += 3;
809 }
810 }
811 }
812
813 // LEVEL3
814
815 for (var row = 0; row < moduleCount; row += 1) {
816 for (var col = 0; col < moduleCount - 6; col += 1) {
817 if (qrcode.isDark(row, col)
818 && !qrcode.isDark(row, col + 1)
819 && qrcode.isDark(row, col + 2)
820 && qrcode.isDark(row, col + 3)
821 && qrcode.isDark(row, col + 4)
822 && !qrcode.isDark(row, col + 5)
823 && qrcode.isDark(row, col + 6) ) {
824 lostPoint += 40;
825 }
826 }
827 }
828
829 for (var col = 0; col < moduleCount; col += 1) {
830 for (var row = 0; row < moduleCount - 6; row += 1) {
831 if (qrcode.isDark(row, col)
832 && !qrcode.isDark(row + 1, col)
833 && qrcode.isDark(row + 2, col)
834 && qrcode.isDark(row + 3, col)
835 && qrcode.isDark(row + 4, col)
836 && !qrcode.isDark(row + 5, col)
837 && qrcode.isDark(row + 6, col) ) {
838 lostPoint += 40;
839 }
840 }
841 }
842
843 // LEVEL4
844
845 var darkCount = 0;
846
847 for (var col = 0; col < moduleCount; col += 1) {
848 for (var row = 0; row < moduleCount; row += 1) {
849 if (qrcode.isDark(row, col) ) {
850 darkCount += 1;
851 }
852 }
853 }
854
855 var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5;
856 lostPoint += ratio * 10;
857
858 return lostPoint;
859 };
860
861 return _this;
862}();
863
864//---------------------------------------------------------------------
865// QRMath
866//---------------------------------------------------------------------
867
868var QRMath = function() {
869
870 var EXP_TABLE = new Array(256);
871 var LOG_TABLE = new Array(256);
872
873 // initialize tables
874 for (var i = 0; i < 8; i += 1) {
875 EXP_TABLE[i] = 1 << i;
876 }
877 for (var i = 8; i < 256; i += 1) {
878 EXP_TABLE[i] = EXP_TABLE[i - 4]
879 ^ EXP_TABLE[i - 5]
880 ^ EXP_TABLE[i - 6]
881 ^ EXP_TABLE[i - 8];
882 }
883 for (var i = 0; i < 255; i += 1) {
884 LOG_TABLE[EXP_TABLE[i] ] = i;
885 }
886
887 var _this = {};
888
889 _this.glog = function(n) {
890
891 if (n < 1) {
892 throw new Error('glog(' + n + ')');
893 }
894
895 return LOG_TABLE[n];
896 };
897
898 _this.gexp = function(n) {
899
900 while (n < 0) {
901 n += 255;
902 }
903
904 while (n >= 256) {
905 n -= 255;
906 }
907
908 return EXP_TABLE[n];
909 };
910
911 return _this;
912}();
913
914//---------------------------------------------------------------------
915// qrPolynomial
916//---------------------------------------------------------------------
917
918function qrPolynomial(num, shift) {
919
920 if (typeof num.length == 'undefined') {
921 throw new Error(num.length + '/' + shift);
922 }
923
924 var _num = function() {
925 var offset = 0;
926 while (offset < num.length && num[offset] == 0) {
927 offset += 1;
928 }
929 var _num = new Array(num.length - offset + shift);
930 for (var i = 0; i < num.length - offset; i += 1) {
931 _num[i] = num[i + offset];
932 }
933 return _num;
934 }();
935
936 var _this = {};
937
938 _this.getAt = function(index) {
939 return _num[index];
940 };
941
942 _this.getLength = function() {
943 return _num.length;
944 };
945
946 _this.multiply = function(e) {
947
948 var num = new Array(_this.getLength() + e.getLength() - 1);
949
950 for (var i = 0; i < _this.getLength(); i += 1) {
951 for (var j = 0; j < e.getLength(); j += 1) {
952 num[i + j] ^= QRMath.gexp(QRMath.glog(_this.getAt(i) ) + QRMath.glog(e.getAt(j) ) );
953 }
954 }
955
956 return qrPolynomial(num, 0);
957 };
958
959 _this.mod = function(e) {
960
961 if (_this.getLength() - e.getLength() < 0) {
962 return _this;
963 }
964
965 var ratio = QRMath.glog(_this.getAt(0) ) - QRMath.glog(e.getAt(0) );
966
967 var num = new Array(_this.getLength() );
968 for (var i = 0; i < _this.getLength(); i += 1) {
969 num[i] = _this.getAt(i);
970 }
971
972 for (var i = 0; i < e.getLength(); i += 1) {
973 num[i] ^= QRMath.gexp(QRMath.glog(e.getAt(i) ) + ratio);
974 }
975
976 // recursive call
977 return qrPolynomial(num, 0).mod(e);
978 };
979
980 return _this;
981};
982
983//---------------------------------------------------------------------
984// QRRSBlock
985//---------------------------------------------------------------------
986
987var QRRSBlock = function() {
988
989
990 // [1: [L, M, Q, H], ..]
991 var RS_BLOCK_TABLE=[[1,26,19],[1,26,16],[1,26,13],[1,26,9],[1,44,34],[1,44,28],[1,44,22],[1,44,16],[1,70,55],[1,70,44],[2,35,17],[2,35,13],[1,100,80],[2,50,32],[2,50,24],[4,25,9],[1,134,108],[2,67,43],[2,33,15,2,34,16],[2,33,11,2,34,12],[2,86,68],[4,43,27],[4,43,19],[4,43,15],[2,98,78],[4,49,31],[2,32,14,4,33,15],[4,39,13,1,40,14],[2,121,97],[2,60,38,2,61,39],[4,40,18,2,41,19],[4,40,14,2,41,15],[2,146,116],[3,58,36,2,59,37],[4,36,16,4,37,17],[4,36,12,4,37,13],[2,86,68,2,87,69],[4,69,43,1,70,44],[6,43,19,2,44,20],[6,43,15,2,44,16],[4,101,81],[1,80,50,4,81,51],[4,50,22,4,51,23],[3,36,12,8,37,13],[2,116,92,2,117,93],[6,58,36,2,59,37],[4,46,20,6,47,21],[7,42,14,4,43,15],[4,133,107],[8,59,37,1,60,38],[8,44,20,4,45,21],[12,33,11,4,34,12],[3,145,115,1,146,116],[4,64,40,5,65,41],[11,36,16,5,37,17],[11,36,12,5,37,13],[5,109,87,1,110,88],[5,65,41,5,66,42],[5,54,24,7,55,25],[11,36,12],[5,122,98,1,123,99],[7,73,45,3,74,46],[15,43,19,2,44,20],[3,45,15,13,46,16],[1,135,107,5,136,108],[10,74,46,1,75,47],[1,50,22,15,51,23],[2,42,14,17,43,15],[5,150,120,1,151,121],[9,69,43,4,70,44],[17,50,22,1,51,23],[2,42,14,19,43,15],[3,141,113,4,142,114],[3,70,44,11,71,45],[17,47,21,4,48,22],[9,39,13,16,40,14],[3,135,107,5,136,108],[3,67,41,13,68,42],[15,54,24,5,55,25],[15,43,15,10,44,16],[4,144,116,4,145,117],[17,68,42],[17,50,22,6,51,23],[19,46,16,6,47,17],[2,139,111,7,140,112],[17,74,46],[7,54,24,16,55,25],[34,37,13],[4,151,121,5,152,122],[4,75,47,14,76,48],[11,54,24,14,55,25],[16,45,15,14,46,16],[6,147,117,4,148,118],[6,73,45,14,74,46],[11,54,24,16,55,25],[30,46,16,2,47,17],[8,132,106,4,133,107],[8,75,47,13,76,48],[7,54,24,22,55,25],[22,45,15,13,46,16],[10,142,114,2,143,115],[19,74,46,4,75,47],[28,50,22,6,51,23],[33,46,16,4,47,17],[8,152,122,4,153,123],[22,73,45,3,74,46],[8,53,23,26,54,24],[12,45,15,28,46,16],[3,147,117,10,148,118],[3,73,45,23,74,46],[4,54,24,31,55,25],[11,45,15,31,46,16],[7,146,116,7,147,117],[21,73,45,7,74,46],[1,53,23,37,54,24],[19,45,15,26,46,16],[5,145,115,10,146,116],[19,75,47,10,76,48],[15,54,24,25,55,25],[23,45,15,25,46,16],[13,145,115,3,146,116],[2,74,46,29,75,47],[42,54,24,1,55,25],[23,45,15,28,46,16],[17,145,115],[10,74,46,23,75,47],[10,54,24,35,55,25],[19,45,15,35,46,16],[17,145,115,1,146,116],[14,74,46,21,75,47],[29,54,24,19,55,25],[11,45,15,46,46,16],[13,145,115,6,146,116],[14,74,46,23,75,47],[44,54,24,7,55,25],[59,46,16,1,47,17],[12,151,121,7,152,122],[12,75,47,26,76,48],[39,54,24,14,55,25],[22,45,15,41,46,16],[6,151,121,14,152,122],[6,75,47,34,76,48],[46,54,24,10,55,25],[2,45,15,64,46,16],[17,152,122,4,153,123],[29,74,46,14,75,47],[49,54,24,10,55,25],[24,45,15,46,46,16],[4,152,122,18,153,123],[13,74,46,32,75,47],[48,54,24,14,55,25],[42,45,15,32,46,16],[20,147,117,4,148,118],[40,75,47,7,76,48],[43,54,24,22,55,25],[10,45,15,67,46,16],[19,148,118,6,149,119],[18,75,47,31,76,48],[34,54,24,34,55,25],[20,45,15,61,46,16]];
992
993 var qrRSBlock = function(totalCount, dataCount) {
994 var _this = {};
995 _this.totalCount = totalCount;
996 _this.dataCount = dataCount;
997 return _this;
998 };
999
1000 var _this = {};
1001
1002 var getRsBlockTable = function(typeNumber, errorCorrectLevel) {
1003
1004 switch(errorCorrectLevel) {
1005 case QRErrorCorrectLevel.L :
1006 return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];
1007 case QRErrorCorrectLevel.M :
1008 return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];
1009 case QRErrorCorrectLevel.Q :
1010 return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];
1011 case QRErrorCorrectLevel.H :
1012 return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];
1013 default :
1014 return undefined;
1015 }
1016 };
1017
1018 _this.getRSBlocks = function(typeNumber, errorCorrectLevel) {
1019
1020 var rsBlock = getRsBlockTable(typeNumber, errorCorrectLevel);
1021
1022 if (typeof rsBlock == 'undefined') {
1023 throw new Error('bad rs block @ typeNumber:' + typeNumber +
1024 '/errorCorrectLevel:' + errorCorrectLevel);
1025 }
1026
1027 var length = rsBlock.length / 3;
1028
1029 var list = new Array();
1030
1031 for (var i = 0; i < length; i += 1) {
1032
1033 var count = rsBlock[i * 3 + 0];
1034 var totalCount = rsBlock[i * 3 + 1];
1035 var dataCount = rsBlock[i * 3 + 2];
1036
1037 for (var j = 0; j < count; j += 1) {
1038 list.push(qrRSBlock(totalCount, dataCount) );
1039 }
1040 }
1041
1042 return list;
1043 };
1044
1045 return _this;
1046}();
1047
1048//---------------------------------------------------------------------
1049// qrBitBuffer
1050//---------------------------------------------------------------------
1051
1052var qrBitBuffer = function() {
1053
1054 var _buffer = new Array();
1055 var _length = 0;
1056
1057 var _this = {};
1058
1059 _this.getBuffer = function() {
1060 return _buffer;
1061 };
1062
1063 _this.getAt = function(index) {
1064 var bufIndex = Math.floor(index / 8);
1065 return ( (_buffer[bufIndex] >>> (7 - index % 8) ) & 1) == 1;
1066 };
1067
1068 _this.put = function(num, length) {
1069 for (var i = 0; i < length; i += 1) {
1070 _this.putBit( ( (num >>> (length - i - 1) ) & 1) == 1);
1071 }
1072 };
1073
1074 _this.getLengthInBits = function() {
1075 return _length;
1076 };
1077
1078 _this.putBit = function(bit) {
1079
1080 var bufIndex = Math.floor(_length / 8);
1081 if (_buffer.length <= bufIndex) {
1082 _buffer.push(0);
1083 }
1084
1085 if (bit) {
1086 _buffer[bufIndex] |= (0x80 >>> (_length % 8) );
1087 }
1088
1089 _length += 1;
1090 };
1091
1092 return _this;
1093};
1094
1095//---------------------------------------------------------------------
1096// qr8BitByte
1097//---------------------------------------------------------------------
1098
1099var qr8BitByte = function(data) {
1100
1101 var _mode = QRMode.MODE_8BIT_BYTE;
1102 var _data = data;
1103 var _parsedData = [];
1104
1105 var _this = {};
1106
1107
1108 // Added to support UTF-8 Characters
1109 for (var i = 0, l = _data.length; i < l; i++) {
1110 var byteArray = [];
1111 var code = _data.charCodeAt(i);
1112
1113 if (code > 0x10000) {
1114 byteArray[0] = 0xF0 | ((code & 0x1C0000) >>> 18);
1115 byteArray[1] = 0x80 | ((code & 0x3F000) >>> 12);
1116 byteArray[2] = 0x80 | ((code & 0xFC0) >>> 6);
1117 byteArray[3] = 0x80 | (code & 0x3F);
1118 } else if (code > 0x800) {
1119 byteArray[0] = 0xE0 | ((code & 0xF000) >>> 12);
1120 byteArray[1] = 0x80 | ((code & 0xFC0) >>> 6);
1121 byteArray[2] = 0x80 | (code & 0x3F);
1122 } else if (code > 0x80) {
1123 byteArray[0] = 0xC0 | ((code & 0x7C0) >>> 6);
1124 byteArray[1] = 0x80 | (code & 0x3F);
1125 } else {
1126 byteArray[0] = code;
1127 }
1128
1129 // Fix Unicode corruption bug
1130 _parsedData.push(byteArray);
1131 }
1132
1133 _parsedData = Array.prototype.concat.apply([], _parsedData);
1134
1135 if (_parsedData.length != _data.length) {
1136 _parsedData.unshift(191);
1137 _parsedData.unshift(187);
1138 _parsedData.unshift(239);
1139 }
1140
1141 var _bytes = _parsedData;
1142
1143 _this.getMode = function() {
1144 return _mode;
1145 };
1146
1147 _this.getLength = function(buffer) {
1148 return _bytes.length;
1149 };
1150
1151 _this.write = function(buffer) {
1152 for (var i = 0; i < _bytes.length; i += 1) {
1153 buffer.put(_bytes[i], 8);
1154 }
1155 };
1156
1157 return _this;
1158};
1159
1160//=====================================================================
1161// GIF Support etc.
1162//
1163
1164//---------------------------------------------------------------------
1165// byteArrayOutputStream
1166//---------------------------------------------------------------------
1167
1168var byteArrayOutputStream = function() {
1169
1170 var _bytes = new Array();
1171
1172 var _this = {};
1173
1174 _this.writeByte = function(b) {
1175 _bytes.push(b & 0xff);
1176 };
1177
1178 _this.writeShort = function(i) {
1179 _this.writeByte(i);
1180 _this.writeByte(i >>> 8);
1181 };
1182
1183 _this.writeBytes = function(b, off, len) {
1184 off = off || 0;
1185 len = len || b.length;
1186 for (var i = 0; i < len; i += 1) {
1187 _this.writeByte(b[i + off]);
1188 }
1189 };
1190
1191 _this.writeString = function(s) {
1192 for (var i = 0; i < s.length; i += 1) {
1193 _this.writeByte(s.charCodeAt(i) );
1194 }
1195 };
1196
1197 _this.toByteArray = function() {
1198 return _bytes;
1199 };
1200
1201 _this.toString = function() {
1202 var s = '';
1203 s += '[';
1204 for (var i = 0; i < _bytes.length; i += 1) {
1205 if (i > 0) {
1206 s += ',';
1207 }
1208 s += _bytes[i];
1209 }
1210 s += ']';
1211 return s;
1212 };
1213
1214 return _this;
1215};
1216
1217//---------------------------------------------------------------------
1218// base64EncodeOutputStream
1219//---------------------------------------------------------------------
1220
1221var base64EncodeOutputStream = function() {
1222
1223 var _buffer = 0;
1224 var _buflen = 0;
1225 var _length = 0;
1226 var _base64 = '';
1227
1228 var _this = {};
1229
1230 var writeEncoded = function(b) {
1231 _base64 += String.fromCharCode(encode(b & 0x3f) );
1232 };
1233
1234 var encode = function(n) {
1235 if (n < 0) {
1236 // error.
1237 } else if (n < 26) {
1238 return 0x41 + n;
1239 } else if (n < 52) {
1240 return 0x61 + (n - 26);
1241 } else if (n < 62) {
1242 return 0x30 + (n - 52);
1243 } else if (n == 62) {
1244 return 0x2b;
1245 } else if (n == 63) {
1246 return 0x2f;
1247 }
1248 throw new Error('n:' + n);
1249 };
1250
1251 _this.writeByte = function(n) {
1252
1253 _buffer = (_buffer << 8) | (n & 0xff);
1254 _buflen += 8;
1255 _length += 1;
1256
1257 while (_buflen >= 6) {
1258 writeEncoded(_buffer >>> (_buflen - 6) );
1259 _buflen -= 6;
1260 }
1261 };
1262
1263 _this.flush = function() {
1264
1265 if (_buflen > 0) {
1266 writeEncoded(_buffer << (6 - _buflen) );
1267 _buffer = 0;
1268 _buflen = 0;
1269 }
1270
1271 if (_length % 3 != 0) {
1272 // padding
1273 var padlen = 3 - _length % 3;
1274 for (var i = 0; i < padlen; i += 1) {
1275 _base64 += '=';
1276 }
1277 }
1278 };
1279
1280 _this.toString = function() {
1281 return _base64;
1282 };
1283
1284 return _this;
1285};
1286
1287//---------------------------------------------------------------------
1288// base64DecodeInputStream
1289//---------------------------------------------------------------------
1290
1291var base64DecodeInputStream = function(str) {
1292
1293 var _str = str;
1294 var _pos = 0;
1295 var _buffer = 0;
1296 var _buflen = 0;
1297
1298 var _this = {};
1299
1300 _this.read = function() {
1301
1302 while (_buflen < 8) {
1303
1304 if (_pos >= _str.length) {
1305 if (_buflen == 0) {
1306 return -1;
1307 }
1308 throw new Error('unexpected end of file./' + _buflen);
1309 }
1310
1311 var c = _str.charAt(_pos);
1312 _pos += 1;
1313
1314 if (c == '=') {
1315 _buflen = 0;
1316 return -1;
1317 } else if (c.match(/^\s$/) ) {
1318 // ignore if whitespace.
1319 continue;
1320 }
1321
1322 _buffer = (_buffer << 6) | decode(c.charCodeAt(0) );
1323 _buflen += 6;
1324 }
1325
1326 var n = (_buffer >>> (_buflen - 8) ) & 0xff;
1327 _buflen -= 8;
1328 return n;
1329 };
1330
1331 var decode = function(c) {
1332 if (0x41 <= c && c <= 0x5a) {
1333 return c - 0x41;
1334 } else if (0x61 <= c && c <= 0x7a) {
1335 return c - 0x61 + 26;
1336 } else if (0x30 <= c && c <= 0x39) {
1337 return c - 0x30 + 52;
1338 } else if (c == 0x2b) {
1339 return 62;
1340 } else if (c == 0x2f) {
1341 return 63;
1342 } else {
1343 throw new Error('c:' + c);
1344 }
1345 };
1346
1347 return _this;
1348};
1349
1350//---------------------------------------------------------------------
1351// gifImage (B/W)
1352//---------------------------------------------------------------------
1353
1354var gifImage = function(width, height) {
1355
1356 var _width = width;
1357 var _height = height;
1358 var _data = new Array(width * height);
1359
1360 var _this = {};
1361
1362 _this.setPixel = function(x, y, pixel) {
1363 _data[y * _width + x] = pixel;
1364 };
1365
1366 _this.write = function(out) {
1367
1368 //---------------------------------
1369 // GIF Signature
1370
1371 out.writeString('GIF87a');
1372
1373 //---------------------------------
1374 // Screen Descriptor
1375
1376 out.writeShort(_width);
1377 out.writeShort(_height);
1378
1379 out.writeByte(0x80); // 2bit
1380 out.writeByte(0);
1381 out.writeByte(0);
1382
1383 //---------------------------------
1384 // Global Color Map
1385
1386 // black
1387 out.writeByte(0x00);
1388 out.writeByte(0x00);
1389 out.writeByte(0x00);
1390
1391 // white
1392 out.writeByte(0xff);
1393 out.writeByte(0xff);
1394 out.writeByte(0xff);
1395
1396 //---------------------------------
1397 // Image Descriptor
1398
1399 out.writeString(',');
1400 out.writeShort(0);
1401 out.writeShort(0);
1402 out.writeShort(_width);
1403 out.writeShort(_height);
1404 out.writeByte(0);
1405
1406 //---------------------------------
1407 // Local Color Map
1408
1409 //---------------------------------
1410 // Raster Data
1411
1412 var lzwMinCodeSize = 2;
1413 var raster = getLZWRaster(lzwMinCodeSize);
1414
1415 out.writeByte(lzwMinCodeSize);
1416
1417 var offset = 0;
1418
1419 while (raster.length - offset > 255) {
1420 out.writeByte(255);
1421 out.writeBytes(raster, offset, 255);
1422 offset += 255;
1423 }
1424
1425 out.writeByte(raster.length - offset);
1426 out.writeBytes(raster, offset, raster.length - offset);
1427 out.writeByte(0x00);
1428
1429 //---------------------------------
1430 // GIF Terminator
1431 out.writeString(';');
1432 };
1433
1434 var bitOutputStream = function(out) {
1435
1436 var _out = out;
1437 var _bitLength = 0;
1438 var _bitBuffer = 0;
1439
1440 var _this = {};
1441
1442 _this.write = function(data, length) {
1443
1444 if ( (data >>> length) != 0) {
1445 throw new Error('length over');
1446 }
1447
1448 while (_bitLength + length >= 8) {
1449 _out.writeByte(0xff & ( (data << _bitLength) | _bitBuffer) );
1450 length -= (8 - _bitLength);
1451 data >>>= (8 - _bitLength);
1452 _bitBuffer = 0;
1453 _bitLength = 0;
1454 }
1455
1456 _bitBuffer = (data << _bitLength) | _bitBuffer;
1457 _bitLength = _bitLength + length;
1458 };
1459
1460 _this.flush = function() {
1461 if (_bitLength > 0) {
1462 _out.writeByte(_bitBuffer);
1463 }
1464 };
1465
1466 return _this;
1467 };
1468
1469 var getLZWRaster = function(lzwMinCodeSize) {
1470
1471 var clearCode = 1 << lzwMinCodeSize;
1472 var endCode = (1 << lzwMinCodeSize) + 1;
1473 var bitLength = lzwMinCodeSize + 1;
1474
1475 // Setup LZWTable
1476 var table = lzwTable();
1477
1478 for (var i = 0; i < clearCode; i += 1) {
1479 table.add(String.fromCharCode(i) );
1480 }
1481 table.add(String.fromCharCode(clearCode) );
1482 table.add(String.fromCharCode(endCode) );
1483
1484 var byteOut = byteArrayOutputStream();
1485 var bitOut = bitOutputStream(byteOut);
1486
1487 // clear code
1488 bitOut.write(clearCode, bitLength);
1489
1490 var dataIndex = 0;
1491
1492 var s = String.fromCharCode(_data[dataIndex]);
1493 dataIndex += 1;
1494
1495 while (dataIndex < _data.length) {
1496
1497 var c = String.fromCharCode(_data[dataIndex]);
1498 dataIndex += 1;
1499
1500 if (table.contains(s + c) ) {
1501
1502 s = s + c;
1503
1504 } else {
1505
1506 bitOut.write(table.indexOf(s), bitLength);
1507
1508 if (table.size() < 0xfff) {
1509
1510 if (table.size() == (1 << bitLength) ) {
1511 bitLength += 1;
1512 }
1513
1514 table.add(s + c);
1515 }
1516
1517 s = c;
1518 }
1519 }
1520
1521 bitOut.write(table.indexOf(s), bitLength);
1522
1523 // end code
1524 bitOut.write(endCode, bitLength);
1525
1526 bitOut.flush();
1527
1528 return byteOut.toByteArray();
1529 };
1530
1531 var lzwTable = function() {
1532
1533 var _map = {};
1534 var _size = 0;
1535
1536 var _this = {};
1537
1538 _this.add = function(key) {
1539 if (_this.contains(key) ) {
1540 throw new Error('dup key:' + key);
1541 }
1542 _map[key] = _size;
1543 _size += 1;
1544 };
1545
1546 _this.size = function() {
1547 return _size;
1548 };
1549
1550 _this.indexOf = function(key) {
1551 return _map[key];
1552 };
1553
1554 _this.contains = function(key) {
1555 return typeof _map[key] != 'undefined';
1556 };
1557
1558 return _this;
1559 };
1560
1561 return _this;
1562};
1563
1564var createImgTag = function(width, height, getPixel, alt) {
1565
1566 var gif = gifImage(width, height);
1567 for (var y = 0; y < height; y += 1) {
1568 for (var x = 0; x < width; x += 1) {
1569 gif.setPixel(x, y, getPixel(x, y) );
1570 }
1571 }
1572
1573 var b = byteArrayOutputStream();
1574 gif.write(b);
1575
1576 var base64 = base64EncodeOutputStream();
1577 var bytes = b.toByteArray();
1578 for (var i = 0; i < bytes.length; i += 1) {
1579 base64.writeByte(bytes[i]);
1580 }
1581 base64.flush();
1582
1583 var img = '';
1584 img += 'data:image/gif;base64,';
1585 img += base64;
1586
1587 return img;
1588};
1589
1590//---------------------------------------------------------------------
1591// returns qrcode function.
1592
1593var drawImg = function(text, options) {
1594 options = options || {};
1595 var typeNumber = options.typeNumber || 4;
1596 var errorCorrectLevel = options.errorCorrectLevel || 'M';
1597 var size = options.size || 500;
1598
1599 var qr;
1600
1601 try {
1602 qr = qrcode(typeNumber, errorCorrectLevel || 'M');
1603 qr.addData(text);
1604 qr.make();
1605 } catch (e) {
1606 if(typeNumber >= 40) {
1607 throw new Error('Text too long to encode');
1608 } else {
1609 return drawImg(text, {
1610 size: size,
1611 errorCorrectLevel: errorCorrectLevel,
1612 typeNumber: typeNumber + 1
1613 });
1614 }
1615 }
1616
1617 // calc cellsize and margin
1618 var cellsize = parseInt(size / qr.getModuleCount());
1619 var margin = parseInt((size - qr.getModuleCount() * cellsize) / 2);
1620
1621 return qr.createImgTag(cellsize, margin, size);
1622};
1623module.exports = {
1624 drawImg: drawImg
1625};