PageSourceSearch

https://www.dituhui.com/template/default/js/easy.qrcode.js

js dituhui.com collected 2026-09-25 21:47:17 UTC 85,897 bytes, 2,219 lines download raw bytes

1/**
2 * EasyQRCodeJS
3 * 
4 * Cross-browser QRCode generator for pure javascript. Support Canvas, SVG and Table drawing methods. Support Dot style, Logo, Background image, Colorful, Title etc. settings. Support Angular, Vue.js, React, Next.js, Svelte framework. Support binary(hex) data mode.(Running with DOM on client side)
5 * 
6 * Version 4.4.13
7 * 
8 * @author [ [email protected] ]
9 * 
10 * @see https://github.com/ushelp/EasyQRCodeJS 
11 * @see http://www.easyproject.cn/easyqrcodejs/tryit.html
12 * @see https://github.com/ushelp/EasyQRCodeJS-NodeJS
13 * 
14 * Copyright 2017 Ray, EasyProject
15 * Released under the MIT license
16 * 
17 * [Support AMD, CMD, CommonJS/Node.js]
18 * 
19 */
20;
21(function() {
22
23    // 启用严格模式
24    "use strict";
25
26    // 自定义局部 undefined 变量
27    var undefined;
28
29    /** Node.js global 检测. */
30    var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;
31
32    /** `self` 变量检测. */
33    var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
34
35    /** 全局对象检测. */
36    var root = freeGlobal || freeSelf || Function('return this')();
37
38    /** `exports` 变量检测. */
39    var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;
40
41    /** `module` 变量检测. */
42    var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;
43
44    var _QRCode = root.QRCode;
45
46    var QRCode;
47
48    function QR8bitByte(data, binary, utf8WithoutBOM) {
49        this.mode = QRMode.MODE_8BIT_BYTE;
50        this.data = data;
51        this.parsedData = [];
52
53        // Added to support UTF-8 Characters
54        for (var i = 0, l = this.data.length; i < l; i++) {
55            var byteArray = [];
56            var code = this.data.charCodeAt(i);
57
58            if (binary) {
59                byteArray[0] = code;
60            } else {
61                if (code > 0x10000) {
62                    byteArray[0] = 0xF0 | ((code & 0x1C0000) >>> 18);
63                    byteArray[1] = 0x80 | ((code & 0x3F000) >>> 12);
64                    byteArray[2] = 0x80 | ((code & 0xFC0) >>> 6);
65                    byteArray[3] = 0x80 | (code & 0x3F);
66                } else if (code > 0x800) {
67                    byteArray[0] = 0xE0 | ((code & 0xF000) >>> 12);
68                    byteArray[1] = 0x80 | ((code & 0xFC0) >>> 6);
69                    byteArray[2] = 0x80 | (code & 0x3F);
70                } else if (code > 0x80) {
71                    byteArray[0] = 0xC0 | ((code & 0x7C0) >>> 6);
72                    byteArray[1] = 0x80 | (code & 0x3F);
73                } else {
74                    byteArray[0] = code;
75                }
76            }
77
78
79            this.parsedData.push(byteArray);
80        }
81
82        this.parsedData = Array.prototype.concat.apply([], this.parsedData);
83        if (!utf8WithoutBOM && this.parsedData.length != this.data.length) {
84            this.parsedData.unshift(191);
85            this.parsedData.unshift(187);
86            this.parsedData.unshift(239);
87        }
88    }
89
90    QR8bitByte.prototype = {
91        getLength: function(buffer) {
92            return this.parsedData.length;
93        },
94        write: function(buffer) {
95            for (var i = 0, l = this.parsedData.length; i < l; i++) {
96                buffer.put(this.parsedData[i], 8);
97            }
98        }
99    };
100
101    function QRCodeModel(typeNumber, errorCorrectLevel) {
102        this.typeNumber = typeNumber;
103        this.errorCorrectLevel = errorCorrectLevel;
104        this.modules = null;
105        this.moduleCount = 0;
106        this.dataCache = null;
107        this.dataList = [];
108    }
109
110    QRCodeModel.prototype = {
111        addData: function(data, binary, utf8WithoutBOM) {
112            var newData = new QR8bitByte(data, binary, utf8WithoutBOM);
113            this.dataList.push(newData);
114            this.dataCache = null;
115        },
116        isDark: function(row, col) {
117            if (row < 0 || this.moduleCount <= row || col < 0 || this.moduleCount <= col) {
118                throw new Error(row + "," + col);
119            }
120            return this.modules[row][col][0];
121        },
122        getEye: function(row, col) {
123            if (row < 0 || this.moduleCount <= row || col < 0 || this.moduleCount <= col) {
124                throw new Error(row + "," + col);
125            }
126
127            var block = this.modules[row][
128                col
129            ]; // [isDark(ture/false), EyeOuterOrInner(O/I), Position(TL/TR/BL/A) ]
130
131            if (block[1]) {
132                var type = 'P' + block[1] + '_' + block[2]; //PO_TL, PI_TL, PO_TR, PI_TR, PO_BL, PI_BL
133                if (block[2] == 'A') {
134                    type = 'A' + block[1]; // AI, AO
135                }
136
137                return {
138                    isDark: block[0],
139                    type: type
140                };
141            } else {
142                return null;
143            }
144        },
145        getModuleCount: function() {
146            return this.moduleCount;
147        },
148        make: function() {
149            this.makeImpl(false, this.getBestMaskPattern());
150        },
151        makeImpl: function(test, maskPattern) {
152            this.moduleCount = this.typeNumber * 4 + 17;
153            this.modules = new Array(this.moduleCount);
154            for (var row = 0; row < this.moduleCount; row++) {
155                this.modules[row] = new Array(this.moduleCount);
156                for (var col = 0; col < this.moduleCount; col++) {
157                    this.modules[row][
158                        col
159                    ] = []; // [isDark(ture/false), EyeOuterOrInner(O/I), Position(TL/TR/BL) ]
160                }
161            }
162            this.setupPositionProbePattern(0, 0, 'TL'); // TopLeft, TL
163            this.setupPositionProbePattern(this.moduleCount - 7, 0, 'BL'); // BotoomLeft, BL
164            this.setupPositionProbePattern(0, this.moduleCount - 7, 'TR'); // TopRight, TR
165            this.setupPositionAdjustPattern('A'); // Alignment, A 
166            this.setupTimingPattern();
167            this.setupTypeInfo(test, maskPattern);
168            if (this.typeNumber >= 7) {
169                this.setupTypeNumber(test);
170            }
171            if (this.dataCache == null) {
172                this.dataCache = QRCodeModel.createData(this.typeNumber, this.errorCorrectLevel, this
173                    .dataList);
174            }
175            this.mapData(this.dataCache, maskPattern);
176        },
177        setupPositionProbePattern: function(row, col, posName) {
178            for (var r = -1; r <= 7; r++) {
179                if (row + r <= -1 || this.moduleCount <= row + r) continue;
180                for (var c = -1; c <= 7; c++) {
181                    if (col + c <= -1 || this.moduleCount <= col + c) continue;
182                    if ((0 <= r && r <= 6 && (c == 0 || c == 6)) || (0 <= c && c <= 6 && (r == 0 || r ==
183                            6)) ||
184                        (2 <= r && r <= 4 &&
185                            2 <= c && c <= 4)) {
186                        this.modules[row + r][col + c][0] = true;
187
188                        this.modules[row + r][col + c][2] = posName; // Position
189                        if (r == -0 || c == -0 || r == 6 || c == 6) {
190                            this.modules[row + r][col + c][1] = 'O'; // Position Outer
191                        } else {
192                            this.modules[row + r][col + c][1] = 'I'; // Position Inner
193                        }
194                    } else {
195                        this.modules[row + r][col + c][0] = false;
196                    }
197                }
198            }
199        },
200        getBestMaskPattern: function() {
201            var minLostPoint = 0;
202            var pattern = 0;
203            for (var i = 0; i < 8; i++) {
204                this.makeImpl(true, i);
205                var lostPoint = QRUtil.getLostPoint(this);
206                if (i == 0 || minLostPoint > lostPoint) {
207                    minLostPoint = lostPoint;
208                    pattern = i;
209                }
210            }
211            return pattern;
212        },
213        createMovieClip: function(target_mc, instance_name, depth) {
214            var qr_mc = target_mc.createEmptyMovieClip(instance_name, depth);
215            var cs = 1;
216            this.make();
217            for (var row = 0; row < this.modules.length; row++) {
218                var y = row * cs;
219                for (var col = 0; col < this.modules[row].length; col++) {
220                    var x = col * cs;
221                    var dark = this.modules[row][col][0];
222                    if (dark) {
223                        qr_mc.beginFill(0, 100);
224                        qr_mc.moveTo(x, y);
225                        qr_mc.lineTo(x + cs, y);
226                        qr_mc.lineTo(x + cs, y + cs);
227                        qr_mc.lineTo(x, y + cs);
228                        qr_mc.endFill();
229                    }
230                }
231            }
232            return qr_mc;
233        },
234        setupTimingPattern: function() {
235            for (var r = 8; r < this.moduleCount - 8; r++) {
236                if (this.modules[r][6][0] != null) {
237                    continue;
238                }
239                this.modules[r][6][0] = (r % 2 == 0);
240            }
241            for (var c = 8; c < this.moduleCount - 8; c++) {
242                if (this.modules[6][c][0] != null) {
243                    continue;
244                }
245                this.modules[6][c][0] = (c % 2 == 0);
246            }
247        },
248        setupPositionAdjustPattern: function(posName) {
249            var pos = QRUtil.getPatternPosition(this.typeNumber);
250            for (var i = 0; i < pos.length; i++) {
251                for (var j = 0; j < pos.length; j++) {
252                    var row = pos[i];
253                    var col = pos[j];
254                    if (this.modules[row][col][0] != null) {
255                        continue;
256                    }
257                    for (var r = -2; r <= 2; r++) {
258                        for (var c = -2; c <= 2; c++) {
259                            if (r == -2 || r == 2 || c == -2 || c == 2 || (r == 0 && c == 0)
259) {
260                                this.modules[row + r][col + c][0] = true;
261                                this.modules[row + r][col + c][2] = posName; // Position
262                                if (r == -2 || c == -2 || r == 2 || c == 2) {
263                                    this.modules[row + r][col + c][1] = 'O'; // Position Outer
264                                } else {
265                                    this.modules[row + r][col + c][1] = 'I'; // Position Inner
266                                }
267                            } else {
268                                this.modules[row + r][col + c][0] = false;
269                            }
270                        }
271                    }
272                }
273            }
274        },
275        setupTypeNumber: function(test) {
276            var bits = QRUtil.getBCHTypeNumber(this.typeNumber);
277            for (var i = 0; i < 18; i++) {
278                var mod = (!test && ((bits >> i) & 1) == 1);
279                this.modules[Math.floor(i / 3)][i % 3 + this.moduleCount - 8 - 3][0] = mod;
280            }
281            for (var i = 0; i < 18; i++) {
282                var mod = (!test && ((bits >> i) & 1) == 1);
283                this.modules[i % 3 + this.moduleCount - 8 - 3][Math.floor(i / 3)][0] = mod;
284            }
285        },
286        setupTypeInfo: function(test, maskPattern) {
287            var data = (this.errorCorrectLevel << 3) | maskPattern;
288            var bits = QRUtil.getBCHTypeInfo(data);
289            for (var i = 0; i < 15; i++) {
290                var mod = (!test && ((bits >> i) & 1) == 1);
291                if (i < 6) {
292                    this.modules[i][8][0] = mod;
293                } else if (i < 8) {
294                    this.modules[i + 1][8][0] = mod;
295                } else {
296                    this.modules[this.moduleCount - 15 + i][8][0] = mod;
297                }
298            }
299            for (var i = 0; i < 15; i++) {
300                var mod = (!test && ((bits >> i) & 1) == 1);
301                if (i < 8) {
302                    this.modules[8][this.moduleCount - i - 1][0] = mod;
303                } else if (i < 9) {
304                    this.modules[8][15 - i - 1 + 1][0] = mod;
305                } else {
306                    this.modules[8][15 - i - 1][0] = mod;
307                }
308            }
309            this.modules[this.moduleCount - 8][8][0] = (!test);
310        },
311        mapData: function(data, maskPattern) {
312            var inc = -1;
313            var row = this.moduleCount - 1;
314            var bitIndex = 7;
315            var byteIndex = 0;
316            for (var col = this.moduleCount - 1; col > 0; col -= 2) {
317                if (col == 6) col--;
318                while (true) {
319                    for (var c = 0; c < 2; c++) {
320                        if (this.modules[row][col - c][0] == null) {
321                            var dark = false;
322                            if (byteIndex < data.length) {
323                                dark = (((data[byteIndex] >>> bitIndex) & 1) == 1);
324                            }
325                            var mask = QRUtil.getMask(maskPattern, row, col - c);
326                            if (mask) {
327                                dark = !dark;
328                            }
329                            this.modules[row][col - c][0] = dark;
330                            bitIndex--;
331                            if (bitIndex == -1) {
332                                byteIndex++;
333                                bitIndex = 7;
334                            }
335                        }
336                    }
337                    row += inc;
338                    if (row < 0 || this.moduleCount <= row) {
339                        row -= inc;
340                        inc = -inc;
341                        break;
342                    }
343                }
344            }
345        }
346    };
347    QRCodeModel.PAD0 = 0xEC;
348    QRCodeModel.PAD1 = 0x11;
349    QRCodeModel.createData = function(typeNumber, errorCorrectLevel, dataList) {
350        var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel);
351        var buffer = new QRBitBuffer();
352        for (var i = 0; i < dataList.length; i++) {
353            var data = dataList[i];
354            buffer.put(data.mode, 4);
355            buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber));
356            data.write(buffer);
357        }
358        var totalDataCount = 0;
359        for (var i = 0; i < rsBlocks.length; i++) {
360            totalDataCount += rsBlocks[i].dataCount;
361        }
362        if (buffer.getLengthInBits() > totalDataCount * 8) {
363            throw new Error("code length overflow. (" +
364                buffer.getLengthInBits() +
365                ">" +
366                totalDataCount * 8 +
367                ")");
368        }
vendor: 22,140 bytes, lines 369-991
369        if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {
370            buffer.put(0, 4);
371        }
372        while (buffer.getLengthInBits() % 8 != 0) {
373            buffer.putBit(false);
374        }
375        while (true) {
376            if (buffer.getLengthInBits() >= totalDataCount * 8) {
377                break;
378            }
379            buffer.put(QRCodeModel.PAD0, 8);
380            if (buffer.getLengthInBits() >= totalDataCount * 8) {
381                break;
382            }
383            buffer.put(QRCodeModel.PAD1, 8);
384        }
385        return QRCodeModel.createBytes(buffer, rsBlocks);
386    };
387    QRCodeModel.createBytes = function(buffer, rsBlocks) {
388        var offset = 0;
389        var maxDcCount = 0;
390        var maxEcCount = 0;
391        var dcdata = new Array(rsBlocks.length);
392        var ecdata = new Array(rsBlocks.length);
393        for (var r = 0; r < rsBlocks.length; r++) {
394            var dcCount = rsBlocks[r].dataCount;
395            var ecCount = rsBlocks[r].totalCount - dcCount;
396            maxDcCount = Math.max(maxDcCount, dcCount);
397            maxEcCount = Math.max(maxEcCount, ecCount);
398            dcdata[r] = new Array(dcCount);
399            for (var i = 0; i < dcdata[r].length; i++) {
400                dcdata[r][i] = 0xff & buffer.buffer[i + offset];
401            }
402            offset += dcCount;
403            var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
404            var rawPoly = new QRPolynomial(dcdata[r], rsPoly.getLength() - 1);
405            var modPoly = rawPoly.mod(rsPoly);
406            ecdata[r] = new Array(rsPoly.getLength() - 1);
407            for (var i = 0; i < ecdata[r].length; i++) {
408                var modIndex = i + modPoly.getLength() - ecdata[r].length;
409                ecdata[r][i] = (modIndex >= 0) ? modPoly.get(modIndex) : 0;
410            }
411        }
412        var totalCodeCount = 0;
413        for (var i = 0; i < rsBlocks.length; i++) {
414            totalCodeCount += rsBlocks[i].totalCount;
415        }
416        var data = new Array(totalCodeCount);
417        var index = 0;
418        for (var i = 0; i < maxDcCount; i++) {
419            for (var r = 0; r < rsBlocks.length; r++) {
420                if (i < dcdata[r].length) {
421                    data[index++] = dcdata[r][i];
422                }
423            }
424        }
425        for (var i = 0; i < maxEcCount; i++) {
426            for (var r = 0; r < rsBlocks.length; r++) {
427                if (i < ecdata[r].length) {
428                    data[index++] = ecdata[r][i];
429                }
430            }
431        }
432        return data;
433    };
434    var QRMode = {
435        MODE_NUMBER: 1 << 0,
436        MODE_ALPHA_NUM: 1 << 1,
437        MODE_8BIT_BYTE: 1 << 2,
438        MODE_KANJI: 1 << 3
439    };
440    var QRErrorCorrectLevel = {
441        L: 1,
442        M: 0,
443        Q: 3,
444        H: 2
445    };
446    var QRMaskPattern = {
447        PATTERN000: 0,
448        PATTERN001: 1,
449        PATTERN010: 2,
450        PATTERN011: 3,
451        PATTERN100: 4,
452        PATTERN101: 5,
453        PATTERN110: 6,
454        PATTERN111: 7
455    };
456    var QRUtil = {
457        PATTERN_POSITION_TABLE: [
458            [],
459            [6, 18],
460            [6, 22],
461            [6, 26],
462            [6, 30],
463            [6, 34],
464            [6, 22, 38],
465            [6, 24, 42],
466            [6, 26, 46],
467            [6, 28, 50],
468            [6, 30, 54],
469            [6, 32, 58],
470            [6, 34, 62],
471            [6, 26, 46, 66],
472            [6, 26, 48, 70],
473            [6, 26, 50, 74],
474            [6, 30, 54, 78],
475            [6, 30, 56, 82],
476            [6, 30, 58, 86],
477            [6, 34, 62, 90],
478            [6, 28, 50, 72, 94],
479            [6, 26, 50, 74, 98],
480            [6, 30, 54, 78, 102],
481            [6, 28, 54, 80, 106],
482            [6, 32, 58, 84, 110],
483            [6, 30, 58, 86, 114],
484            [6, 34, 62, 90, 118],
485            [6, 26, 50, 74, 98, 122],
486            [6, 30, 54, 78, 102, 126],
487            [6, 26, 52, 78, 104, 130],
488            [6, 30, 56, 82, 108, 134],
489            [6, 34, 60, 86, 112, 138],
490            [6, 30, 58, 86, 114, 142],
491            [6, 34, 62, 90, 118, 146],
492            [6, 30, 54, 78, 102, 126, 150],
493            [6, 24, 50, 76, 102, 128, 154],
494            [6, 28, 54, 80, 106, 132, 158],
495            [6, 32, 58, 84, 110, 136, 162],
496            [6, 26, 54, 82, 110, 138, 166],
497            [6, 30, 58, 86, 114, 142, 170]
498        ],
499        G15: (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0),
500        G18: (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0),
501        G15_MASK: (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1),
502        getBCHTypeInfo: function(data) {
503            var d = data << 10;
504            while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0) {
505                d ^= (QRUtil.G15 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15)));
506            }
507            return ((data << 10) | d) ^ QRUtil.G15_MASK;
508        },
509        getBCHTypeNumber: function(data) {
510            var d = data << 12;
511            while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0) {
512                d ^= (QRUtil.G18 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18)));
513            }
514            return (data << 12) | d;
515        },
516        getBCHDigit: function(data) {
517            var digit = 0;
518            while (data != 0) {
519                digit++;
520                data >>>= 1;
521            }
522            return digit;
523        },
524        getPatternPosition: function(typeNumber) {
525            return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1];
526        },
527        getMask: function(maskPattern, i, j) {
528            switch (maskPattern) {
529                case QRMaskPattern.PATTERN000:
530                    return (i + j) % 2 == 0;
531                case QRMaskPattern.PATTERN001:
532                    return i % 2 == 0;
533                case QRMaskPattern.PATTERN010:
534                    return j % 3 == 0;
535                case QRMaskPattern.PATTERN011:
536                    return (i + j) % 3 == 0;
537                case QRMaskPattern.PATTERN100:
538                    return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 == 0;
539                case QRMaskPattern.PATTERN101:
540                    return (i * j) % 2 + (i * j) % 3 == 0;
541                case QRMaskPattern.PATTERN110:
542                    return ((i * j) % 2 + (i * j) % 3) % 2 == 0;
543                case QRMaskPattern.PATTERN111:
544                    return ((i * j) % 3 + (i + j) % 2) % 2 == 0;
545                default:
546                    throw new Error("bad maskPattern:" + maskPattern);
547            }
548        },
549        getErrorCorrectPolynomial: function(errorCorrectLength) {
550            var a = new QRPolynomial([1], 0);
551            for (var i = 0; i < errorCorrectLength; i++) {
552                a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0));
553            }
554            return a;
555        },
556        getLengthInBits: function(mode, type) {
557            if (1 <= type && type < 10) {
558                switch (mode) {
559                    case QRMode.MODE_NUMBER:
560                        return 10;
561                    case QRMode.MODE_ALPHA_NUM:
562                        return 9;
563                    case QRMode.MODE_8BIT_BYTE:
564                        return 8;
565                    case QRMode.MODE_KANJI:
566                        return 8;
567                    default:
568                        throw new Error("mode:" + mode);
569                }
570            } else if (type < 27) {
571                switch (mode) {
572                    case QRMode.MODE_NUMBER:
573                        return 12;
574                    case QRMode.MODE_ALPHA_NUM:
575                        return 11;
576                    case QRMode.MODE_8BIT_BYTE:
577                        return 16;
578                    case QRMode.MODE_KANJI:
579                        return 10;
580                    default:
581                        throw new Error("mode:" + mode);
582                }
583            } else if (type < 41) {
584                switch (mode) {
585                    case QRMode.MODE_NUMBER:
586                        return 14;
587                    case QRMode.MODE_ALPHA_NUM:
588                        return 13;
589                    case QRMode.MODE_8BIT_BYTE:
590                        return 16;
591                    case QRMode.MODE_KANJI:
592                        return 12;
593                    default:
594                        throw new Error("mode:" + mode);
595                }
596            } else {
597                throw new Error("type:" + type);
598            }
599        },
600        getLostPoint: function(qrCode) {
601            var moduleCount = qrCode.getModuleCount();
602            var lostPoint = 0;
603            for (var row = 0; row < moduleCount; row++) {
604                for (var col = 0; col < moduleCount; col++) {
605                    var sameCount = 0;
606                    var dark = qrCode.isDark(row, col);
607                    for (var r = -1; r <= 1; r++) {
608                        if (row + r < 0 || moduleCount <= row + r) {
609                            continue;
610                        }
611                        for (var c = -1; c <= 1; c++) {
612                            if (col + c < 0 || moduleCount <= col + c) {
613                                continue;
614                            }
615                            if (r == 0 && c == 0) {
616                                continue;
617                            }
618                            if (dark == qrCode.isDark(row + r, col + c)) {
619                                sameCount++;
620                            }
621                        }
622                    }
623                    if (sameCount > 5) {
624                        lostPoint += (3 + sameCount - 5);
625                    }
626                }
627            }
628            for (var row = 0; row < moduleCount - 1; row++) {
629                for (var col = 0; col < moduleCount - 1; col++) {
630                    var count = 0;
631                    if (qrCode.isDark(row, col)) count++;
632                    if (qrCode.isDark(row + 1, col)) count++;
633                    if (qrCode.isDark(row, col + 1)) count++;
634                    if (qrCode.isDark(row + 1, col + 1)) count++;
635                    if (count == 0 || count == 4) {
636                        lostPoint += 3;
637                    }
638                }
639            }
640            for (var row = 0; row < moduleCount; row++) {
641                for (var col = 0; col < moduleCount - 6; col++) {
642                    if (qrCode.isDark(row, col) && !qrCode.isDark(row, col + 1) && qrCode.isDark(row, col +
643                            2) && qrCode.isDark(
644                            row,
645                            col + 3) && qrCode.isDark(row, col + 4) && !qrCode.isDark(row, col + 5) &&
646                        qrCode.isDark(row, col + 6)) {
647                        lostPoint += 40;
648                    }
649                }
650            }
651            for (var col = 0; col < moduleCount; col++) {
652                for (var row = 0; row < moduleCount - 6; row++) {
653                    if (qrCode.isDark(row, col) && !qrCode.isDark(row + 1, col) && qrCode.isDark(row + 2,
654                            col) && qrCode.isDark(
655                            row +
656                            3, col) && qrCode.isDark(row + 4, col) && !qrCode.isDark(row + 5, col) &&
657                        qrCode.isDark(row + 6, col)) {
658                        lostPoint += 40;
659                    }
660                }
661            }
662            var darkCount = 0;
663            for (var col = 0; col < moduleCount; col++) {
664                for (var row = 0; row < moduleCount; row++) {
665                    if (qrCode.isDark(row, col)) {
666                        darkCount++;
667                    }
668                }
669            }
670            var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5;
671            lostPoint += ratio * 10;
672            return lostPoint;
673        }
674    };
675    var QRMath = {
676        glog: function(n) {
677            if (n < 1) {
678                throw new Error("glog(" + n + ")");
679            }
680            return QRMath.LOG_TABLE[n];
681        },
682        gexp: function(n) {
683            while (n < 0) {
684                n += 255;
685            }
686            while (n >= 256) {
687                n -= 255;
688            }
689            return QRMath.EXP_TABLE[n];
690        },
691        EXP_TABLE: new Array(256),
692        LOG_TABLE: new Array(256)
693    };
694    for (var i = 0; i < 8; i++) {
695        QRMath.EXP_TABLE[i] = 1 << i;
696    }
697    for (var i = 8; i < 256; i++) {
698        QRMath.EXP_TABLE[i] = QRMath.EXP_TABLE[i - 4] ^ QRMath.EXP_TABLE[i - 5] ^ QRMath.EXP_TABLE[i - 6] ^ QRMath
699            .EXP_TABLE[
700                i - 8];
701    }
702    for (var i = 0; i < 255; i++) {
703        QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]] = i;
704    }
705
706    function QRPolynomial(num, shift) {
707        if (num.length == undefined) {
708            throw new Error(num.length + "/" + shift);
709        }
710        var offset = 0;
711        while (offset < num.length && num[offset] == 0) {
712            offset++;
713        }
714        this.num = new Array(num.length - offset + shift);
715        for (var i = 0; i < num.length - offset; i++) {
716            this.num[i] = num[i + offset];
717        }
718    }
719    QRPolynomial.prototype = {
720        get: function(index) {
721            return this.num[index];
722        },
723        getLength: function() {
724            return this.num.length;
725        },
726        multiply: function(e) {
727            var num = new Array(this.getLength() + e.getLength() - 1);
728            for (var i = 0; i < this.getLength(); i++) {
729                for (var j = 0; j < e.getLength(); j++) {
730                    num[i + j] ^= QRMath.gexp(QRMath.glog(this.get(i)) + QRMath.glog(e.get(j)));
731                }
732            }
733            return new QRPolynomial(num, 0);
734        },
735        mod: function(e) {
736            if (this.getLength() - e.getLength() < 0) {
737                return this;
738            }
739            var ratio = QRMath.glog(this.get(0)) - QRMath.glog(e.get(0));
740            var num = new Array(this.getLength());
741            for (var i = 0; i < this.getLength(); i++) {
742                num[i] = this.get(i);
743            }
744            for (var i = 0; i < e.getLength(); i++) {
745                num[i] ^= QRMath.gexp(QRMath.glog(e.get(i)) + ratio);
746            }
747            return new QRPolynomial(num, 0).mod(e);
748        }
749    };
750
751    function QRRSBlock(totalCount, dataCount) {
752        this.totalCount = totalCount;
753        this.dataCount = dataCount;
754    }
755    QRRSBlock.RS_BLOCK_TABLE = [
756        [1, 26, 19],
757        [1, 26, 16],
758        [1, 26, 13],
759        [1, 26, 9],
760        [1, 44, 34],
761        [1, 44, 28],
762        [1, 44, 22],
763        [1, 44, 16],
764        [1, 70, 55],
765        [1, 70, 44],
766        [2, 35, 17],
767        [2, 35, 13],
768        [1, 100, 80],
769        [2, 50, 32],
770        [2, 50, 24],
771        [4, 25, 9],
772        [1, 134, 108],
773        [2, 67, 43],
774        [2, 33, 15, 2, 34, 16],
775        [2, 33, 11, 2, 34, 12],
776        [2, 86, 68],
777        [4, 43, 27],
778        [4, 43, 19],
779        [4, 43, 15],
780        [2, 98, 78],
781        [4, 49, 31],
782        [2, 32, 14, 4, 33, 15],
783        [4, 39, 13, 1, 40, 14],
784        [2, 121, 97],
785        [2, 60, 38, 2, 61, 39],
786        [4, 40, 18, 2, 41, 19],
787        [4, 40, 14, 2, 41, 15],
788        [2, 146, 116],
789        [3, 58, 36, 2, 59, 37],
790        [4, 36, 16, 4, 37, 17],
791        [4, 36, 12, 4, 37, 13],
792        [2, 86, 68, 2, 87, 69],
793        [4, 69, 43, 1, 70, 44],
794        [6, 43, 19, 2, 44, 20],
795        [6, 43, 15, 2, 44, 16],
796        [4, 101, 81],
797        [1, 80, 50, 4, 81, 51],
798        [4, 50, 22, 4, 51, 23],
799        [3, 36, 12, 8, 37, 13],
800        [2, 116, 92, 2, 117, 93],
801        [6, 58, 36, 2, 59, 37],
802        [4, 46, 20, 6, 47, 21],
803        [7, 42, 14, 4, 43, 15],
804        [4, 133, 107],
805        [8, 59, 37, 1, 60, 38],
806        [8, 44, 20, 4, 45, 21],
807        [12, 33, 11, 4, 34, 12],
808        [3, 145, 115, 1, 146, 116],
809        [4, 64, 40, 5, 65, 41],
810        [11, 36, 16, 5, 37, 17],
811        [11, 36, 12, 5, 37, 13],
812        [5, 109, 87, 1, 110, 88],
813        [5, 65, 41, 5, 66, 42],
814        [5, 54, 24, 7, 55, 25],
815        [11, 36, 12, 7, 37, 13],
816        [5, 122, 98, 1, 123, 99],
817        [7, 73, 45, 3, 74, 46],
818        [15, 43, 19, 2, 44, 20],
819        [3, 45, 15, 13, 46, 16],
820        [1, 135, 107, 5, 136, 108],
821        [10, 74, 46, 1, 75, 47],
822        [1, 50, 22, 15, 51, 23],
823        [2, 42, 14, 17, 43, 15],
824        [5, 150, 120, 1, 151, 121],
825        [9, 69, 43, 4, 70, 44],
826        [17, 50, 22, 1, 51, 23],
827        [2, 42, 14, 19, 43, 15],
828        [3, 141, 113, 4, 142, 114],
829        [3, 70, 44, 11, 71, 45],
830        [17, 47, 21, 4, 48, 22],
831        [9, 39, 13, 16, 40, 14],
832        [3, 135, 107, 5, 136, 108],
833        [3, 67, 41, 13, 68, 42],
834        [15, 54, 24, 5, 55, 25],
835        [15, 43, 15, 10, 44, 16],
836        [4, 144, 116, 4, 145, 117],
837        [17, 68, 42],
838        [17, 50, 22, 6, 51, 23],
839        [19, 46, 16, 6, 47, 17],
840        [2, 139, 111, 7, 140, 112],
841        [17, 74, 46],
842        [7, 54, 24, 16, 55, 25],
843        [34, 37, 13],
844        [4, 151, 121, 5, 152, 122],
845        [4, 75, 47, 14, 76, 48],
846        [11, 54, 24, 14, 55, 25],
847        [16, 45, 15, 14, 46, 16],
848        [6, 147, 117, 4, 148, 118],
849        [6, 73, 45, 14, 74, 46],
850        [11, 54, 24, 16, 55, 25],
851        [30, 46, 16, 2, 47, 17],
852        [8, 132, 106, 4, 133, 107],
853        [8, 75, 47, 13, 76, 48],
854        [7, 54, 24, 22, 55, 25],
855        [22, 45, 15, 13, 46, 16],
856        [10, 142, 114, 2, 143, 115],
857        [19, 74, 46, 4, 75, 47],
858        [28, 50, 22, 6, 51, 23],
859        [33, 46, 16, 4, 47, 17],
860        [8, 152, 122, 4, 153, 123],
861        [22, 73, 45, 3, 74, 46],
862        [8, 53, 23, 26, 54, 24],
863        [12, 45, 15, 28, 46, 16],
864        [3, 147, 117, 10, 148, 118],
865        [3, 73, 45, 23, 74, 46],
866        [4, 54, 24, 31, 55, 25],
867        [11, 45, 15, 31, 46, 16],
868        [7, 146, 116, 7, 147, 117],
869        [21, 73, 45, 7, 74, 46],
870        [1, 53, 23, 37, 54, 24],
871        [19, 45, 15, 26, 46, 16],
872        [5, 145, 115, 10, 146, 116],
873        [19, 75, 47, 10, 76, 48],
874        [15, 54, 24, 25, 55, 25],
875        [23, 45, 15, 25, 46, 16],
876        [13, 145, 115, 3, 146, 116],
877        [2, 74, 46, 29, 75, 47],
878        [42, 54, 24, 1, 55, 25],
879        [23, 45, 15, 28, 46, 16],
880        [17, 145, 115],
881        [10, 74, 46, 23, 75, 47],
882        [10, 54, 24, 35, 55, 25],
883        [19, 45, 15, 35, 46, 16],
884        [17, 145, 115, 1, 146, 116],
885        [14, 74, 46, 21, 75, 47],
886        [29, 54, 24, 19, 55, 25],
887        [11, 45, 15, 46, 46, 16],
888        [13, 145, 115, 6, 146, 116],
889        [14, 74, 46, 23, 75, 47],
890        [44, 54, 24, 7, 55, 25],
891        [59, 46, 16, 1, 47, 17],
892        [12, 151, 121, 7, 152, 122],
893        [12, 75, 47, 26, 76, 48],
894        [39, 54, 24, 14, 55, 25],
895        [22, 45, 15, 41, 46, 16],
896        [6, 151, 121, 14, 152, 122],
897        [6, 75, 47, 34, 76, 48],
898        [46, 54, 24, 10, 55, 25],
899        [2, 45, 15, 64, 46, 16],
900        [17, 152, 122, 4, 153, 123],
901        [29, 74, 46, 14, 75, 47],
902        [49, 54, 24, 10, 55, 25],
903        [24, 45, 15, 46, 46, 16],
904        [4, 152, 122, 18, 153, 123],
905        [13, 74, 46, 32, 75, 47],
906        [48, 54, 24, 14, 55, 25],
907        [42, 45, 15, 32, 46, 16],
908        [20, 147, 117, 4, 148, 118],
909        [40, 75, 47, 7, 76, 48],
910        [43, 54, 24, 22, 55, 25],
911        [10, 45, 15, 67, 46, 16],
912        [19, 148, 118, 6, 149, 119],
913        [18, 75, 47, 31, 76, 48],
914        [34, 54, 24, 34, 55, 25],
915        [20, 45, 15, 61, 46, 16]
916    ];
917    QRRSBlock.getRSBlocks = function(typeNumber, errorCorrectLevel) {
918        var rsBlock = QRRSBlock.getRsBlockTable(typeNumber, errorCorrectLevel);
919        if (rsBlock == undefined) {
920            throw new Error("bad rs block @ typeNumber:" + typeNumber + "/errorCorrectLevel:" +
921                errorCorrectLevel);
922        }
923        var length = rsBlock.length / 3;
924        var list = [];
925        for (var i = 0; i < length; i++) {
926            var count = rsBlock[i * 3 + 0];
927            var totalCount = rsBlock[i * 3 + 1];
928            var dataCount = rsBlock[i * 3 + 2];
929            for (var j = 0; j < count; j++) {
930                list.push(new QRRSBlock(totalCount, dataCount));
931            }
932        }
933        return list;
934    };
935    QRRSBlock.getRsBlockTable = function(typeNumber, errorCorrectLevel) {
936        switch (errorCorrectLevel) {
937            case QRErrorCorrectLevel.L:
938                return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];
939            case QRErrorCorrectLevel.M:
940                return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];
941            case QRErrorCorrectLevel.Q:
942                return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];
943            case QRErrorCorrectLevel.H:
944                return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];
945            default:
946                return undefined;
947        }
948    };
949
950    function QRBitBuffer() {
951        this.buffer = [];
952        this.length = 0;
953    }
954    QRBitBuffer.prototype = {
955        get: function(index) {
956            var bufIndex = Math.floor(index / 8);
957            return ((this.buffer[bufIndex] >>> (7 - index % 8)) & 1) == 1;
958        },
959        put: function(num, length) {
960            for (var i = 0; i < length; i++) {
961                this.putBit(((num >>> (length - i - 1)) & 1) == 1);
962            }
963        },
964        getLengthInBits: function() {
965            return this.length;
966        },
967        putBit: function(bit) {
968            var bufIndex = Math.floor(this.length / 8);
969            if (this.buffer.length <= bufIndex) {
970                this.buffer.push(0);
971            }
972            if (bit) {
973                this.buffer[bufIndex] |= (0x80 >>> (this.length % 8));
974            }
975            this.length++;
976        }
977    };
978    var QRCodeLimitLength = [
979        [17, 14, 11, 7],
980        [32, 26, 20, 14],
981        [53, 42, 32, 24],
982        [78, 62, 46, 34],
983        [106, 84, 60, 44],
984        [134, 106, 74, 58],
985        [154, 122, 86, 64],
986        [192, 152, 108, 84],
987        [230, 180, 130, 98],
988        [271, 213, 151, 119],
989        [321, 251, 177, 137],
990        [367, 287, 203, 155],
991        [425, 331, 241, 177],
992        [458, 362, 258, 194],
993        [520, 412, 292, 220],
994        [586, 450, 322, 250],
995        [644, 504, 364, 280],
996        [718, 560, 394, 310],
997        [792, 624, 442, 338],
998        [858, 666, 482, 382],
999        [929, 711, 509, 403],
1000        [1003, 779, 565, 439],
1001        [1091, 857, 611, 461],
1002        [1171, 911, 661, 511],
1003        [1273, 997, 715, 535],
1004        [1367, 1059, 751, 593],
1005        [1465, 1125, 805, 625],
1006        [1528, 1190, 868, 658],
1007        [1628, 1264, 908, 698],
1008        [1732, 1370, 982, 742],
1009        [1840, 1452, 1030, 790],
1010        [1952, 1538, 1112, 842],
1011        [2068, 1628, 1168, 898],
1012        [2188, 1722, 1228, 958],
1013        [2303, 1809, 1283, 983],
1014        [2431, 1911, 1351, 1051],
1015        [2563, 1989, 1423, 1093],
1016        [2699, 2099, 1499, 1139],
1017        [2809, 2213, 1579, 1219],
1018        [2953, 2331, 1663, 1273]
1019    ];
1020
1021    function _isSupportCanvas() {
1022        return typeof CanvasRenderingContext2D != "undefined";
1023    }
1024
1025    // android 2.x doesn't support Data-URI spec
1026    function _getAndroid() {
1027        var android = false;
1028        var sAgent = navigator.userAgent;
1029
1030        if (/android/i.test(sAgent)) { // android
1031            android = true;
1032            var aMat = sAgent.toString().match(/android ([0-9]\.[0-9])/i);
1033
1034            if (aMat && aMat[1]) {
1035                android = parseFloat(aMat[1]);
1036            }
1037        }
1038
1039        return android;
1040    }
1041
1042    // Drawing in DOM by using Table tag
1043    var Drawing = !_isSupportCanvas() ? (function() {
1044        var Drawing = function(el, htOption) {
1045            this._el = el;
1046            this._htOption = htOption;
1047        };
1048
1049        /**
1050         * Draw the QRCode
1051         * 
1052         * @param {QRCode} oQRCode
1053         */
1054        Drawing.prototype.draw = function(oQRCode) {
1055            var _htOption = this._htOption;
1056            var _el = this._el;
1057            var nCount = oQRCode.getModuleCount();
1058            var nWidth = Math.round(_htOption.width / nCount);
1059            var nHeight = Math.round((_htOption.height - _htOption.titleHeight) / nCount);
1060            if (nWidth <= 1) {
1061                nWidth = 1;
1062            }
1063            if (nHeight <= 1) {
1064                nHeight = 1;
1065            }
1066
1067            this._htOption.width = nWidth * nCount;
1068            this._htOption.height = nHeight * nCount + _htOption.titleHeight;
1069
1070            this._htOption.quietZone = Math.round(this._htOption.quietZone);
1071
1072
1073            var aHTML = [];
1074
1075            var divStyle = '';
1076
1077            var drawWidth = Math.round(nWidth * _htOption.dotScale);
1078            var drawHeight = Math.round(nHeight * _htOption.dotScale);
1079            if (drawWidth < 4) {
1080                drawWidth = 4;
1081                drawHeight = 4;
1082            }
1083
1084            var nonRequiredColorDark = _htOption.colorDark;
1085            var nonRequiredcolorLight = _htOption.colorLight;
1086            if (_htOption.backgroundImage) {
1087                if (_htOption.autoColor) {
1088                    _htOption.colorDark =
1089                        "rgba(0, 0, 0, .6);filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0, StartColorStr='#99000000', EndColorStr='#99000000');";
1090                    _htOption.colorLight =
1091                        "rgba(255, 255, 255, .7);filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0, StartColorStr='#B2FFFFFF', EndColorStr='#B2FFFFFF');";
1092
1093                    // _htOption.colorDark="rgba(0, 0, 0, .6)";
1094                    // _htOption.colorLight='rgba(255, 255, 255, .7)';
1095                } else {
1096                    _htOption.colorLight = "rgba(0,0,0,0)";
1097                }
1098
1099
1100                var backgroundImageEle =
1101                    '<div style="display:inline-block; z-index:-10;position:absolute;"><img src="' +
1102                    _htOption.backgroundImage + '" widht="' + (_htOption.width + _htOption.quietZone *
1103                        2) + '" height="' + (
1104                        _htOption.height + _htOption.quietZone * 2) + '" style="opacity:' + _htOption
1105                    .backgroundImageAlpha +
1106                    ';filter:alpha(opacity=' + (_htOption.backgroundImageAlpha * 100) + '); "/></div>';
1107                aHTML.push(backgroundImageEle);
1108            }
1109
1110            if (_htOption.quietZone) {
1111                divStyle = 'display:inline-block; width:' + (
1112                        _htOption.width +
1113                        _htOption.quietZone * 2) + 'px; height:' + (_htOption.width +
1114                        _htOption.quietZone * 2) + 'px;background:' + _htOption.quietZoneColor +
1115                    '; text-align:center;';
1116            }
1117            aHTML.push('<div style="font-size:0;' + divStyle + '">');
1118
1119            aHTML.push(
1120                '<table  style="font-size:0;border:0;border-collapse:collapse; margin-top:' +
1121                _htOption.quietZone +
1122                'px;" border="0" cellspacing="0" cellspadding="0" align="center" valign="middle">'
1123            );
1124            aHTML.push('<tr height="' + _htOption.titleHeight +
1125                '" align="center"><td style="border:0;border-collapse:collapse;margin:0;padding:0" colspan="' +
1126                nCount +
1127                '">')
1128            if (_htOption.title) {
1129                var c = _htOption.titleColor;
1130                var f = _htOption.titleFont;
1131                aHTML.push('<div style="width:100%;margin-top:' + _htOption.titleTop + 'px;color:' + c +
1132                    ';font:' + f +
1133                    ';
1133background:' + _htOption.titleBackgroundColor + '">' +
1134                    _htOption.title + '</div>');
1135            }
1136            if (_htOption.subTitle) {
1137                aHTML.push('<div style="width:100%;margin-top:' + (_htOption.subTitleTop - _htOption
1138                        .titleTop) +
1139                    'px;color:' +
1140                    _htOption.subTitleColor + '; font:' + _htOption.subTitleFont +
1141                    '">' + _htOption.subTitle + '</div>');
1142            }
1143            aHTML.push('</td></tr>')
1144            for (var row = 0; row < nCount; row++) {
1145                aHTML.push('<tr style="border:0; padding:0; margin:0;" height="7">');
1146
1147                for (var col = 0; col < nCount; col++) {
1148
1149                    var bIsDark = oQRCode.isDark(row, col);
1150
1151                    var eye = oQRCode.getEye(row,
1152                        col); // { isDark: true/false, type: PO_TL, PI_TL, PO_TR, PI_TR, PO_BL, PI_BL };
1153
1154                    if (eye) {
1155                        // Is eye
1156                        bIsDark = eye.isDark;
1157                        var type = eye.type;
1158
1159                        // PX_XX, PX, colorDark, colorLight
1160                        var eyeColorDark = _htOption[type] || _htOption[type.substring(0, 2)] ||
1161                            nonRequiredColorDark;
1162                        aHTML.push(
1163                            '<td style="border:0;border-collapse:collapse;padding:0;margin:0;width:' +
1164                            nWidth + 'px;height:' +
1165                            nHeight + 'px;">' +
1166                            '<span style="width:' + nWidth + 'px;height:' + nHeight +
1167                            'px;background-color:' + (bIsDark ?
1168                                eyeColorDark : nonRequiredcolorLight) +
1169                            ';display:inline-block"></span></td>');
1170
1171                    } else {
1172
1173                        // Timing Pattern 
1174                        var nowDarkColor = _htOption.colorDark;
1175                        if (row == 6) {
1176                            nowDarkColor = _htOption.timing_H || _htOption.timing ||
1177                                nonRequiredColorDark;
1178                            aHTML.push(
1179                                '<td style="border:0;border-collapse:collapse;padding:0;margin:0;width:' +
1180                                nWidth +
1181                                'px;height:' +
1182                                nHeight + 'px;background-color:' + (bIsDark ? nowDarkColor :
1183                                    nonRequiredcolorLight) +
1184                                ';"></td>');
1185                        } else if (col == 6) {
1186                            nowDarkColor = _htOption.timing_V || _htOption.timing ||
1187                                nonRequiredColorDark;
1188
1189                            aHTML.push(
1190                                '<td style="border:0;border-collapse:collapse;padding:0;margin:0;width:' +
1191                                nWidth +
1192                                'px;height:' +
1193                                nHeight + 'px;background-color:' + (bIsDark ? nowDarkColor :
1194                                    nonRequiredcolorLight) +
1195                                ';"></td>');
1196
1197                        } else {
1198                            aHTML.push(
1199                                '<td style="border:0;border-collapse:collapse;padding:0;margin:0;width:' +
1200                                nWidth +
1201                                'px;height:' +
1202                                nHeight + 'px;">' +
1203                                '<div style="display:inline-block;width:' + drawWidth +
1204                                'px;height:' + drawHeight +
1205                                'px;background-color:' + (bIsDark ? nowDarkColor : _htOption
1206                                    .colorLight) +
1207                                ';"></div></td>');
1208                        }
1209
1210
1211
1212
1213                    }
1214
1215
1216                }
1217
1218                aHTML.push('</tr>');
1219            }
1220
1221
1222            aHTML.push('</table>');
1223            aHTML.push('</div>');
1224
1225            if (_htOption.logo) {
1226                // Logo Image
1227                var img = new Image();
1228
1229                if (_htOption.crossOrigin != null) {
1230                    img.crossOrigin = _htOption.crossOrigin;
1231                }
1232
1233                // img.crossOrigin="Anonymous";
1234                img.src = _htOption.logo;
1235
1236                var imgW = _htOption.width / 3.5;
1237                var imgH = _htOption.height / 3.5;
1238                if (imgW != imgH) {
1239                    imgW = imgH;
1240                }
1241
1242                if (_htOption.logoWidth) {
1243                    imgW = _htOption.logoWidth;
1244                }
1245                if (_htOption.logoHeight) {
1246                    imgH = _htOption.logoHeight;
1247                }
1248
1249                var imgDivStyle = 'position:relative; z-index:1;display:table-cell;top:-' + ((
1250                            _htOption.height - _htOption.titleHeight) /
1251                        2 + imgH / 2 + _htOption.quietZone) + 'px;text-align:center; width:' + imgW +
1252                    'px; height:' + imgH + 'px;line-height:' + imgW + 'px; vertical-align: middle;';
1253                if (!_htOption.logoBackgroundTransparent) {
1254                    imgDivStyle += 'background:' + _htOption.logoBackgroundColor;
1255                }
1256
1257                aHTML.push('<div style="' + imgDivStyle + '"><img  src="' + _htOption.logo +
1258                    '"  style="max-width: ' + imgW + 'px; max-height: ' + imgH +
1259                    'px;" /> <div style=" display: none; width:1px;margin-left: -1px;"></div></div>'
1260                );
1261
1262
1263            }
1264
1265
1266
1267            if (_htOption.onRenderingStart) {
1268                _htOption.onRenderingStart(_htOption)
1269            }
1270
1271            _el.innerHTML = aHTML.join('');
1272            // Fix the margin values as real size.
1273            var elTable = _el.childNodes[0];
1274            var nLeftMarginTable = (_htOption.width - elTable.offsetWidth) / 2;
1275            var nTopMarginTable = (_htOption.height - elTable.offsetHeight) / 2;
1276            if (nLeftMarginTable > 0 && nTopMarginTable > 0) {
1277                elTable.style.margin = nTopMarginTable + "px " + nLeftMarginTable + "px";
1278            }
1279            if (this._htOption.onRenderingEnd) {
1280                this._htOption.onRenderingEnd(this._htOption, null);
1281            }
1282        };
1283
1284        /**
1285         * Clear the QRCode
1286         */
1287        Drawing.prototype.clear = function() {
1288            this._el.innerHTML = '';
1289        };
1290
1291        return Drawing;
1292    })() : (function() { // Drawing in Canvas
1293        function _onMakeImage() {
1294
1295
1296            if (this._htOption.drawer == 'svg') {
1297                var svgData = this._oContext.getSerializedSvg(true);
1298                this.dataURL = svgData;
1299                this._el.innerHTML = svgData;
1300            } else {
1301                // canvas
1302                // this._elImage.crossOrigin='Anonymous';
1303                try {
1304                    // if (this._htOption.crossOrigin != null) {
1305                    //     this._elImage.crossOrigin = this._htOption.crossOrigin;
1306                    // }
1307                    var dataURL = this._elCanvas.toDataURL("image/png");
1308                    // this._elImage.src = dataURL;
1309                    this.dataURL = dataURL;
1310                    // this._elImage.style.display = "inline";
1311                    // this._elCanvas.style.display = "none";
1312                } catch (e) {
1313                    console.error(e)
1314                }
1315
1316            }
1317            if (this._htOption.onRenderingEnd) {
1318                if (!this.dataURL) {
1319                    console.error(
1320                        "Can not get base64 data, please check: 1. Published the page and image to the server 2. The image request support CORS 3. Configured `crossOrigin:'anonymous'` option"
1321                    )
1322                }
1323                this._htOption.onRenderingEnd(this._htOption, this.dataURL);
1324            }
1325
1326
1327        }
1328
1329        // Android 2.1 bug workaround
1330        // http://code.google.com/p/android/issues/detail?id=5141
1331        if (root._android && root._android <= 2.1) {
1332            var factor = 1 / window.devicePixelRatio;
1333            var drawImage = CanvasRenderingContext2D.prototype.drawImage;
1334            CanvasRenderingContext2D.prototype.drawImage = function(image, sx, sy, sw, sh, dx, dy, dw, dh) {
1335                if (("nodeName" in image) && /img/i.test(image.nodeName)) {
1336                    for (var i = arguments.length - 1; i >= 1; i--) {
1337                        arguments[i] = arguments[i] * factor;
1338                    }
1339                } else if (typeof dw == "undefined") {
1340                    arguments[1] *= factor;
1341                    arguments[2] *= factor;
1342                    arguments[3] *= factor;
1343                    arguments[4] *= factor;
1344                }
1345
1346                drawImage.apply(this, arguments);
1347            };
1348        }
1349
1350        /**
1351         * Check whether the user's browser supports Data URI or not
1352         * 
1353         * @private
1354         * @param {Function} fSuccess Occurs if it supports Data URI
1355         * @param {Function} fFail Occurs if it doesn't support Data URI
1356         */
1357        function _safeSetDataURI(fSuccess, fFail) {
1358            var self = this;
1359            self._fFail = fFail;
1360            self._fSuccess = fSuccess;
1361
1362            // Check it just once
1363            if (self._bSupportDataURI === null) {
1364                var el = document.createElement("img");
1365                var fOnError = function() {
1366                    self._bSupportDataURI = false;
1367
1368                    if (self._fFail) {
1369                        self._fFail.call(self);
1370                    }
1371                };
1372                var fOnSuccess = function() {
1373                    self._bSupportDataURI = true;
1374
1375                    if (self._fSuccess) {
1376                        self._fSuccess.call(self);
1377                    }
1378                };
1379
1380                el.onabort = fOnError;
1381                el.onerror = fOnError;
1382                el.onload = fOnSuccess;
1383                el.src =
1384                    "data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="; // the Image contains 1px data.
1385                return;
1386            } else if (self._bSupportDataURI === true && self._fSuccess) {
1387                self._fSuccess.call(self);
1388            } else if (self._bSupportDataURI === false && self._fFail) {
1389                self._fFail.call(self);
1390            }
1391        };
1392
1393        /**
1394         * Drawing QRCode by using canvas
1395         * 
1396         * @constructor
1397         * @param {HTMLElement} el
1398         * @param {Object} htOption QRCode Options 
1399         */
1400        var Drawing = function(el, htOption) {
1401            this._bIsPainted = false;
1402            this._android = _getAndroid();
1403            this._el = el;
1404            this._htOption = htOption;
1405
1406            if (this._htOption.drawer == 'svg') {
1407                this._oContext = {};
1408                this._elCanvas = {};
1409            } else {
1410                // canvas
1411                this._elCanvas = document.createElement("canvas");
1412                this._el.appendChild(this._elCanvas);
1413                this._oContext = this._elCanvas.getContext("2d");
1414                // this._elImage = document.createElement("img");
1415                // this._elImage.alt = "Scan me!";
1416                // this._elImage.style.display = "none";
1417                // this._el.appendChild(this._elImage);
1418            }
1419
1420            this._bSupportDataURI = null;
1421            this.dataURL = null;
1422        };
1423
1424        /**
1425         * Draw the QRCode
1426         * 
1427         * @param {QRCode} oQRCode 
1428         */
1429        Drawing.prototype.draw = function(oQRCode) {
1430            // var _elImage = this._elImage;
1431            var _htOption = this._htOption;
1432
1433            var nCount = oQRCode.getModuleCount();
1434            var nWidth = Math.round(_htOption.width / nCount);
1435            var nHeight = Math.round((_htOption.height - _htOption.titleHeight) / nCount);
1436            if (nWidth <= 1) {
1437                nWidth = 1;
1438            }
1439            if (nHeight <= 1) {
1440                nHeight = 1;
1441            }
1442
1443            _htOption.width = nWidth * nCount;
1444            _htOption.height = nHeight * nCount + _htOption.titleHeight;
1445
1446            _htOption.quietZone = Math.round(_htOption.quietZone);
1447
1448            this._elCanvas.width = _htOption.width + _htOption.quietZone * 2;
1449            this._elCanvas.height = _htOption.height + _htOption.quietZone * 2;
1450
1451            if (this._htOption.drawer != 'canvas') {
1452                // _elImage.style.display = "none";
1453                // } else {
1454                this._oContext = new C2S(this._elCanvas.width, this._elCanvas.height);
1455            }
1456            this.clear();
1457
1458            var _oContext = this._oContext;
1459            _oContext.lineWidth = 0;
1460            _oContext.fillStyle = _htOption.colorLight;
1461            _oContext.fillRect(0, 0, this._elCanvas.width, this._elCanvas.height);
1462            _oContext.clearRect(_htOption.quietZone, _htOption.quietZone, _htOption.width, _htOption.titleHeight);
1463
1464            var t = this;
1465
1466            function drawQuietZoneColor() {
1467
1468                if (_htOption.quietZone > 0 && _htOption.quietZoneColor) {
1469                    // top
1470                    _oContext.lineWidth = 0;
1471                    _oContext.fillStyle = _htOption.quietZoneColor;
1472
1473                    _oContext.fillRect(0, 0, t._elCanvas.width, _htOption.quietZone);
1474                    // left
1475                    _oContext.fillRect(0, _htOption.quietZone, _htOption.quietZone, t._elCanvas.height -
1476                        _htOption.quietZone * 2);
1477                    // right
1478                    _oContext.fillRect(t._elCanvas.width - _htOption.quietZone, _htOption.quietZone,
1479                        _htOption.quietZone, t._elCanvas.height - _htOption.quietZone * 2);
1480                    // bottom
1481                    _oContext.fillRect(0, t._elCanvas.height - _htOption.quietZone, t._elCanvas.width,
1482                        _htOption.quietZone);
1483                }
1484            }
1485
1486            if (_htOption.backgroundImage) {
1487
1488                // Background Image
1489                var bgImg = new Image();
1490
1491                bgImg.onload = function() {
1492                    _oContext.globalAlpha = 1;
1493
1494                    _oContext.globalAlpha = _htOption.backgroundImageAlpha;
1495                    var imageSmoothingQuality = _oContext.imageSmoothingQuality;
1496                    var imageSmoothingEnabled = _oContext.imageSmoothingEnabled;
1497                    _oContext.imageSmoothingEnabled = true;
1498                    _oContext.imageSmoothingQuality = "high";
1499                    _oContext.drawImage(bgImg, 0, _htOption.titleHeight, _htOption.width + _htOption.quietZone * 2, _htOption.height + _htOption.quietZone * 2 - _htOption.titleHeight);
1500                    _oContext.imageSmoothingEnabled = imageSmoothingEnabled;
1501                    _oContext.imageSmoothingQuality = imageSmoothingQuality;
1502                    _oContext.globalAlpha = 1;
1503
1504
1505                    drawQrcode.call(t, oQRCode);
1506                }
1507                // bgImg.crossOrigin='Anonymous';
1508                if (_htOption.crossOrigin != null) {
1509                    bgImg.crossOrigin = _htOption.crossOrigin;
1510                }
1511                bgImg.originalSrc = _htOption.backgroundImage;
1512                bgImg.src = _htOption.backgroundImage;
1513                // DoSomething
1514            } else {
1515                drawQrcode.call(t, oQRCode);
1516            }
1517
1518            function drawQrcode(oQRCode) {
1519                if (_htOption.onRenderingStart) {
1520                    _htOption.onRenderingStart(_htOption)
1521                }
1522
1523                for (var row = 0; row < nCount; row++) {
1524                    for (var col = 0; col < nCount; col++) {
1525                        var nLeft = col * nWidth + _htOption.quietZone;
1526                        var nTop = row * nHeight + _htOption.quietZone;
1527
1528                        var bIsDark = oQRCode.isDark(row, col);
1529
1530                        var eye = oQRCode.getEye(row,
1531                            col
1532                        ); // { isDark: true/false, type: PO_TL, PI_TL, PO_TR, PI_TR, PO_BL, PI_BL };
1533
1534                        var nowDotScale = _htOption.dotScale;
1535
1536                        _oContext.lineWidth = 0;
1537                        // Color handler
1538                        var dColor;
1539                        var lColor;
1540                        if (eye) {
1541                            dColor = _htOption[eye.type] || _htOption[eye.type.substring(
1542                                    0, 2)] ||
1543                                _htOption.colorDark;
1544                            lColor = _htOption.colorLight;
1545                        } else {
1546                            if (_htOption.backgroundImage) {
1547
1548                                lColor = "rgba(0,0,0,0)";
1549                                if (row == 6) {
1550                                    // dColor = _htOption.timing_H || _htOption.timing || _htOption.colorDark;
1551                                    if (_htOption.autoColor) {
1552                                        dColor = _htOption.timing_H || _htOption.timing || _htOption
1553                                            .autoColorDark;
1554                                        lColor = _htOption.autoColorLight;
1555                                    } else {
1556                                        dColor = _htOption.timing_H || _htOption.timing || _htOption
1557                                            .colorDark;
1558                                    }
1559                                } else if (col == 6) {
1560                                    // dColor = _htOption.timing_V || _htOption.timing || _htOption.colorDark;
1561                                    if (_htOption.autoColor) {
1562                                        dColor = _htOption.timing_V || _htOption.timing || _htOption
1563                                            .autoColorDark;
1564                                        lColor = _htOption.autoColorLight;
1565                                    } else {
1566                                        dColor = _htOption.timing_V || _htOption.timing || _htOption.colorDark;
1567                                    }
1568                                } else {
1569                                    if (_htOption.autoColor) {
1570                                        dColor = _htOption.autoColorDark;
1571                                        lColor = _htOption.autoColorLight;
1572                                    } else {
1573                                        dColor = _htOption.colorDark;
1574                                    }
1575                                }
1576
1577                            } else {
1578                                if (row == 6) {
1579                                    dColor = _htOption.timing_H || _htOption.timing || _htOption
1580                                        .colorDark;
1581                                } else if (col == 6) {
1582                                    dColor = _htOption.timing_V || _htOption.timing ||
1583                                        _htOption.colorDark;
1584                                } else {
1585                                    dColor = _htOption.colorDark;
1586                                }
1587                                lColor = _htOption.colorLight;
1588                            }
1589                        }
1590                        _oContext.strokeStyle = bIsDark ? dColor :
1591                            lColor;
1592                        _oContext.fillStyle = bIsDark ? dColor :
1593                            lColor;
1594
1595                        if (eye) {
1596                            if (eye.type == 'AO') {
1597                                nowDotScale = _htOption.dotScaleAO;
1598                            } else if (eye.type == 'AI') {
1599                                nowDotScale = _htOption.dotScaleAI;
1600                            } else {
1601                                nowDotScale = 1;
1602                            }
1603
1604                            if (_htOption.backgroundImage && _htOption.autoColor) {
1605                                dColor = ((eye.type == 'AO') ? _htOption.AI : _htOption.AO) ||
1606                                    _htOption.autoColorDark;
1607                                lColor = _htOption.autoColorLight;
1608                            } else {
1609                                dColor = ((eye.type == 'AO') ? _htOption.AI : _htOption.AO) ||
1610                                    dColor;
1611                            }
1612
1613                            // Is eye
1614                            bIsDark = eye.isDark;
1615
1616
1617                            _oContext.fillRect(nLeft + nWidth * (1 - nowDotScale) / 2, _htOption
1618                                .titleHeight +
1619                                nTop + nHeight * (1 -
1620                                    nowDotScale) / 2, nWidth * nowDotScale, nHeight *
1621                                nowDotScale);
1622
1623                        } else {
1624
1625                            if (row == 6) {
1626                                // Timing Pattern 
1627
1628                                nowDotScale = _htOption.dotScaleTiming_H;
1629
1630                                _oContext.fillRect(nLeft + nWidth * (1 - nowDotScale) / 2, _htOption
1631                                    .titleHeight +
1632                                    nTop + nHeight * (1 -
1633                                        nowDotScale) / 2, nWidth * nowDotScale, nHeight *
1634                                    nowDotScale);
1635                            } else if (col == 6) {
1636                                // Timing Pattern 
1637                                nowDotScale = _htOption.dotScaleTiming_V;
1638
1639                                _oContext.fillRect(nLeft + nWidth * (1 - nowDotScale) / 2, _htOption
1640                                    .titleHeight +
1641                                    nTop + nHeight * (1 -
1642                                        nowDotScale) / 2, nWidth * nowDotScale, nHeight *
1643                                    nowDotScale);
1644                            } else {
1645
1646                                if (_htOption.backgroundImage) {
1647
1648                                    _oContext.fillRect(nLeft + nWidth * (1 - nowDotScale) / 2,
1649                                        _htOption.titleHeight + nTop + nHeight * (1 -
1650                                            nowDotScale) / 2, nWidth * nowDotScale, nHeight *
1651                                        nowDotScale);
1652                                } else {
1653
1654                                    _oContext.fillRect(nLeft + nWidth * (1 - nowDotScale) / 2,
1655                                        _htOption.titleHeight + nTop + nHeight * (1 -
1656                                            nowDotScale) / 2, nWidth * nowDotScale, nHeight *
1657                                        nowDotScale);
1658
1659                                }
1660                            }
1661                        }
1662
1663                        if (_htOption.dotScale != 1 && !eye) {
1664                            _oContext.strokeStyle = _htOption.colorLight;
1665                        }
1666
1667                    }
1668                }
1669
1670                if (_htOption.title) {
1671
1672                    _oContext.fillStyle = _htOption.titleBackgroun
1672dColor;
1673                    _oContext.fillRect(_htOption.quietZone, _htOption.quietZone, _htOption.width, _htOption.titleHeight);
1674
1675                    _oContext.font = _htOption.titleFont;
1676                    _oContext.fillStyle = _htOption.titleColor;
1677                    _oContext.textAlign = 'center';
1678                    _oContext.fillText(_htOption.title, this._elCanvas.width / 2, +_htOption.quietZone +
1679                        _htOption.titleTop);
1680                }
1681
1682                if (_htOption.subTitle) {
1683                    _oContext.font = _htOption.subTitleFont;
1684                    _oContext.fillStyle = _htOption.subTitleColor;
1685                    _oContext.fillText(_htOption.subTitle, this._elCanvas.width / 2, +_htOption
1686                        .quietZone +
1687                        _htOption.subTitleTop);
1688                }
1689
1690                function generateLogoImg(img) {
1691                    var imgContainerW = Math.round(_htOption.width / 3.5);
1692                    var imgContainerH = Math.round(_htOption.height / 3.5);
1693                    if (imgContainerW !== imgContainerH) {
1694                        imgContainerW = imgContainerH;
1695                    }
1696
1697                    if (_htOption.logoMaxWidth) {
1698                        imgContainerW = Math.round(_htOption.logoMaxWidth);
1699                    } else if (_htOption.logoWidth) {
1700                        imgContainerW = Math.round(_htOption.logoWidth);
1701                    }
1702
1703                    if (_htOption.logoMaxHeight) {
1704                        imgContainerH = Math.round(_htOption.logoMaxHeight);
1705                    } else if (_htOption.logoHeight) {
1706                        imgContainerH = Math.round(_htOption.logoHeight);
1707                    }
1708
1709                    var nw;
1710                    var nh;
1711                    if (typeof img.naturalWidth == "undefined") {
1712                        // IE 6/7/8
1713                        nw = img.width;
1714                        nh = img.height;
1715                    } else {
1716                        // HTML5 browsers
1717                        nw = img.naturalWidth;
1718                        nh = img.naturalHeight;
1719                    }
1720
1721                    if (_htOption.logoMaxWidth || _htOption.logoMaxHeight) {
1722                        if (_htOption.logoMaxWidth && nw <= imgContainerW) {
1723                            imgContainerW = nw;
1724                        }
1725
1726                        if (_htOption.logoMaxHeight && nh <= imgContainerH) {
1727                            imgContainerH = nh;
1728                        }
1729                        if (nw <= imgContainerW && nh <= imgContainerH) {
1730                            imgContainerW = nw;
1731                            imgContainerH = nh;
1732                        }
1733                    }
1734
1735                    var imgContainerX = (_htOption.width + _htOption.quietZone * 2 - imgContainerW) / 2;
1736                    var imgContainerY = (_htOption.height + _htOption.titleHeight + _htOption
1737                        .quietZone *
1738                        2 - imgContainerH) / 2;
1739
1740                    var imgScale = Math.min(imgContainerW / nw, imgContainerH / nh);
1741                    var imgW = nw * imgScale;
1742                    var imgH = nh * imgScale;
1743
1744                    if (_htOption.logoMaxWidth || _htOption.logoMaxHeight) {
1745                        imgContainerW = imgW;
1746                        imgContainerH = imgH;
1747                        imgContainerX = (_htOption.width + _htOption.quietZone * 2 - imgContainerW) / 2;
1748                        imgContainerY = (_htOption.height + _htOption.titleHeight + _htOption
1749                            .quietZone *
1750                            2 - imgContainerH) / 2;
1751
1752                    }
1753
1754                    // Did Not Use Transparent Logo Image
1755                    if (!_htOption.logoBackgroundTransparent) {
1756                        //if (!_htOption.logoBackgroundColor) {
1757                        //_htOption.logoBackgroundColor = '#ffffff';
1758                        //}
1759                        _oContext.fillStyle = _htOption.logoBackgroundColor;
1760
1761                        _oContext.fillRect(imgContainerX, imgContainerY, imgContainerW, imgContainerH);
1762                    }
1763                    var imageSmoothingQuality = _oContext.imageSmoothingQuality;
1764                    var imageSmoothingEnabled = _oContext.imageSmoothingEnabled;
1765                    _oContext.imageSmoothingEnabled = true;
1766                    _oContext.imageSmoothingQuality = "high";
1767                    _oContext.drawImage(img, imgContainerX + (imgContainerW - imgW) / 2, imgContainerY 
1767+ (imgContainerH - imgH) / 2, imgW, imgH);
1768                    _oContext.imageSmoothingEnabled = imageSmoothingEnabled;
1769                    _oContext.imageSmoothingQuality = imageSmoothingQuality;
1770                    drawQuietZoneColor();
1771                    _this._bIsPainted = true;
1772
1773                    _this.makeImage();
1774                }
1775
1776
1777                if (_htOption.logo) {
1778                    // Logo Image
1779                    var img = new Image();
1780
1781                    var _this = this;
1782
1783
1784                    img.onload = function() {
1785                        generateLogoImg(img);
1786                    }
1787
1788                    img.onerror = function(e) {
1789                        console.error(e)
1790                    }
1791
1792                    // img.crossOrigin="Anonymous";
1793                    if (_htOption.crossOrigin != null) {
1794                        img.crossOrigin = _htOption.crossOrigin;
1795                    }
1796                    img.originalSrc = _htOption.logo;
1797                    img.src = _htOption.logo;
1798
1799                } else {
1800                    drawQuietZoneColor();
1801                    this._bIsPainted = true;
1802                    this.makeImage();
1803
1804                }
1805
1806            }
1807
1808        };
1809
1810        /**
1811         * Make the image from Canvas if the browser supports Data URI.
1812         */
1813        Drawing.prototype.makeImage = function() {
1814            if (this._bIsPainted) {
1815                _safeSetDataURI.call(this, _onMakeImage);
1816            }
1817        };
1818
1819        /**
1820         * Return whether the QRCode is painted or not
1821         * 
1822         * @return {Boolean}
1823         */
1824        Drawing.prototype.isPainted = function() {
1825            return this._bIsPainted;
1826        };
1827
1828        /**
1829         * Clear the QRCode
1830         */
1831        Drawing.prototype.clear = function() {
1832            this._oContext.clearRect(0, 0, this._elCanvas.width, this._elCanvas.height);
1833            this._bIsPainted = false;
1834        };
1835
1836        Drawing.prototype.remove = function() {
1837            this._oContext.clearRect(0, 0, this._elCanvas.width, this._elCanvas.height);
1838            this._bIsPainted = false;
1839            this._el.innerHTML = '';
1840        };
1841
1842        /**
1843         * @private
1844         * @param {Number} nNumber
1845         */
1846        Drawing.prototype.round = function(nNumber) {
1847            if (!nNumber) {
1848                return nNumber;
1849            }
1850
1851            return Math.floor(nNumber * 1000) / 1000;
1852        };
1853
1854        return Drawing;
1855    })();
1856
1857    /**
1858     * Get the type by string length
1859     * 
1860     * @private
1861     * @param {String} sText
1862     * @param {Number} nCorrectLevel
1863     * @return {Number} type
1864     */
1865    function _getTypeNumber(sText, _htOption) {
1866
1867        var nCorrectLevel = _htOption.correctLevel;
1868
1869        var nType = 1;
1870        var length = _getUTF8Length(sText);
1871
1872        for (var i = 0, len = QRCodeLimitLength.length; i < len; i++) {
1873            var nLimit = 0;
1874            switch (nCorrectLevel) {
1875                case QRErrorCorrectLevel.L:
1876                    nLimit = QRCodeLimitLength[i][0];
1877                    break;
1878                case QRErrorCorrectLevel.M:
1879                    nLimit = QRCodeLimitLength[i][1];
1880                    break;
1881                case QRErrorCorrectLevel.Q:
1882                    nLimit = QRCodeLimitLength[i][2];
1883                    break;
1884                case QRErrorCorrectLevel.H:
1885                    nLimit = QRCodeLimitLength[i][3];
1886                    break;
1887            }
1888
1889            if (length <= nLimit) {
1890                break;
1891            } else {
1892                nType++;
1893            }
1894        }
1895        if (nType > QRCodeLimitLength.length) {
1896            throw new Error("Too long data. the CorrectLevel." + ['M', 'L', 'H', 'Q'][nCorrectLevel] +
1897                " limit length is " + nLimit);
1898        }
1899
1900        if (_htOption.version != 0) {
1901            if (nType <= _htOption.version) {
1902                nType = _htOption.version;
1903                _htOption.runVersion = nType;
1904            } else {
1905                console.warn("QR Code version " + _htOption.version + " too small, run version use " + nType);
1906                _htOption.runVersion = nType;
1907            }
1908        }
1909        return nType;
1910    }
1911
1912    function _getUTF8Length(sText) {
1913        var replacedText = encodeURI(sText).toString().replace(/\%[0-9a-fA-F]{2}/g, 'a');
1914        return replacedText.length + (replacedText.length != sText.length ? 3 : 0);
1915    }
1916
1917
1918    QRCode = function(el, vOption) {
1919        this._htOption = {
1920            width: 256,
1921            height: 256,
1922            typeNumber: 4,
1923            colorDark: "#000000",
1924            colorLight: "#ffffff",
1925            correctLevel: QRErrorCorrectLevel.H,
1926
1927            dotScale: 1, // For body block, must be greater than 0, less than or equal to 1. default is 1
1928
1929            dotScaleTiming: 1, // Dafault for timing block , must be greater than 0, less than or equal to 1. default is 1
1930            dotScaleTiming_H: undefined, // For horizontal timing block, must be greater than 0, less than or equal to 1. default is 1
1931            dotScaleTiming_V: undefined, // For vertical timing block, must be greater than 0, less than or equal to 1. default is 1
1932
1933            dotScaleA: 1, // Dafault for alignment block, must be greater than 0, less than or equal to 1. default is 1
1934            dotScaleAO: undefined, // For alignment outer block, must be greater than 0, less than or equal to 1. default is 1
1935            dotScaleAI: undefined, // For alignment inner block, must be greater than 0, less than or equal to 1. default is 1
1936
1937            quietZone: 0,
1938            quietZoneColor: "rgba(0,0,0,0)",
1939
1940            title: "",
1941            titleFont: "normal normal bold 16px Arial",
1942            titleColor: "#000000",
1943            titleBackgroundColor: "#ffffff",
1944            titleHeight: 0, // Title Height, Include subTitle
1945            titleTop: 30, // draws y coordinates. default is 30
1946
1947            subTitle: "",
1948            subTitleFont: "normal normal normal 14px Arial",
1949            subTitleColor: "#4F4F4F",
1950            subTitleTop: 60, // draws y coordinates. default is 0
1951
1952            logo: undefined,
1953            logoWidth: undefined,
1954            logoHeight: undefined,
1955            logoMaxWidth: undefined,
1956            logoMaxHeight: undefined,
1957            logoBackgroundColor: '#ffffff',
1958            logoBackgroundTransparent: false,
1959
1960            // === Posotion Pattern(Eye) Color
1961            PO: undefined, // Global Posotion Outer color. if not set, the defaut is `colorDark`
1962            PI: undefined, // Global Posotion Inner color. if not set, the defaut is `colorDark`
1963            PO_TL: undefined, // Posotion Outer - Top Left 
1964            PI_TL: undefined, // Posotion Inner - Top Left 
1965            PO_TR: undefined, // Posotion Outer - Top Right 
1966            PI_TR: undefined, // Posotion Inner - Top Right 
1967            PO_BL: undefined, // Posotion Outer - Bottom Left 
1968            PI_BL: undefined, // Posotion Inner - Bottom Left 
1969
1970            // === Alignment Color
1971            AO: undefined, // Alignment Outer. if not set, the defaut is `colorDark`
1972            AI: undefined, // Alignment Inner. if not set, the defaut is `colorDark`
1973
1974            // === Timing Pattern Color
1975            timing: undefined, // Global Timing color. if not set, the defaut is `colorDark`
1976            timing_H: undefined, // Horizontal timing color
1977            timing_V: undefined, // Vertical timing color
1978
1979            // ==== Backgroud Image
1980            backgroundImage: undefined, // Background Image
1981            backgroundImageAlpha: 1, // Background image transparency, value between 0 and 1. default is 1. 
1982            autoColor: false, // Automatic color adjustment(for data block)
1983            autoColorDark: "rgba(0, 0, 0, .6)", // Automatic color: dark CSS color
1984            autoColorLight: "rgba(255, 255, 255, .7)", // Automatic color: light CSS color
1985
1986            // ==== Event Handler
1987            onRenderingStart: undefined,
1988            onRenderingEnd: undefined,
1989
1990            // ==== Versions
1991            version: 0, // The symbol versions of QR Code range from Version 1 to Version 40. default 0 means automatically choose the closest version based on the text length.
1992
1993            // ==== Tooltip
1994            tooltip: false, // Whether set the QRCode Text as the title attribute value of the image
1995
1996            // ==== Binary(hex) data mode
1997            binary: false, // Whether it is binary mode, default is text mode. 
1998
1999            // ==== Drawing method
2000            drawer: 'canvas', // Drawing method: canvas, svg(Chrome, FF, IE9+)
2001
2002            // ==== CORS
2003            crossOrigin: null, // String which specifies the CORS setting to use when retrieving the image. null means that the crossOrigin attribute is not set.
2004
2005            // UTF-8 without BOM
2006            utf8WithoutBOM: true
2007        };
2008
2009        if (typeof vOption === 'string') {
2010            vOption = {
2011                text: vOption
2012            };
2013        }
2014
2015        // Overwrites options
2016        if (vOption) {
2017            for (var i in vOption) {
2018                this._htOption[i] = vOption[i];
2019            }
2020        }
2021
2022        if (!this._htOption.title && !this._htOption.subTitle) {
2023            this._htOption.titleHeight = 0;
2024        }
2025
2026        if (this._htOption.version < 0 || this._htOption.version > 40) {
2027            console.warn("QR Code version '" + this._htOption.version + "' is invalidate, reset to 0")
2028            this._htOption.version = 0;
2029        }
2030
2031        if (this._htOption.dotScale < 0 || this._htOption.dotScale > 1) {
2032            console.warn(this._htOption.dotScale +
2033                " , is invalidate, dotScale must greater than 0, less than or equal to 1, now reset to 1. "
2034            )
2035            this._htOption.dotScale = 1;
2036        }
2037
2038        if (this._htOption.dotScaleTiming < 0 || this._htOption.dotScaleTiming > 1) {
2039            console.warn(this._htOption.dotScaleTiming +
2040                " , is invalidate, dotScaleTiming must greater than 0, less than or equal to 1, now reset to 1. "
2041            )
2042            this._htOption.dotScaleTiming = 1;
2043        }
2044        if (this._htOption.dotScaleTiming_H) {
2045            if (this._htOption.dotScaleTiming_H < 0 || this._htOption.dotScaleTiming_H > 1) {
2046                console.warn(this._htOption.dotScaleTiming_H +
2047                    " , is invalidate, dotScaleTiming_H must greater than 0, less than or equal to 1, now reset to 1. "
2048                )
2049                this._htOption.dotScaleTiming_H = 1;
2050            }
2051        } else {
2052            this._htOption.dotScaleTiming_H = this._htOption.dotScaleTiming;
2053        }
2054
2055        if (this._htOption.dotScaleTiming_V) {
2056            if (this._htOption.dotScaleTiming_V < 0 || this._htOption.dotScaleTiming_V > 1) {
2057                console.warn(this._htOption.dotScaleTiming_V +
2058                    " , is invalidate, dotScaleTiming_V must greater than 0, less than or equal to 1, now reset to 1. "
2059                )
2060                this._htOption.dotScaleTiming_V = 1;
2061            }
2062        } else {
2063            this._htOption.dotScaleTiming_V = this._htOption.dotScaleTiming;
2064        }
2065
2066
2067
2068        if (this._htOption.dotScaleA < 0 || this._htOption.dotScaleA > 1) {
2069            console.warn(this._htOption.dotScaleA +
2070                " , is invalidate, dotScaleA must greater than 0, less than or equal to 1, now reset to 1. "
2071            )
2072            this._htOption.dotScaleA = 1;
2073        }
2074        if (this._htOption.dotScaleAO) {
2075            if (this._htOption.dotScaleAO < 0 || this._htOption.dotScaleAO > 1) {
2076                console.warn(this._htOption.dotScaleAO +
2077                    " , is invalidate, dotScaleAO must greater than 0, less than or equal to 1, now reset to 1. "
2078                )
2079                this._htOption.dotScaleAO = 1;
2080            }
2081        } else {
2082            this._htOption.dotScaleAO = this._htOption.dotScaleA;
2083        }
2084        if (this._htOption.dotScaleAI) {
2085            if (this._htOption.dotScaleAI < 0 || this._htOption.dotScaleAI > 1) {
2086                console.warn(this._htOption.dotScaleAI +
2087                    " , is invalidate, dotScaleAI must greater than 0, less than or equal to 1, now reset to 1. "
2088                )
2089                this._htOption.dotScaleAI = 1;
2090            }
2091        } else {
2092            this._htOption.dotScaleAI = this._htOption.dotScaleA;
2093        }
2094
2095
2096
2097        if (this._htOption.backgroundImageAlpha < 0 || this._htOption.backgroundImageAlpha > 1) {
2098            console.warn(this._htOption.backgroundImageAlpha +
2099                " , is invalidate, backgroundImageAlpha must between 0 and 1, now reset to 1. ")
2100            this._htOption.backgroundImageAlpha = 1;
2101        }
2102
2103        this._htOption.height = this._htOption.height + this._htOption.titleHeight;
2104        if (typeof el == "string") {
2105            el = document.getElementById(el);
2106        }
2107
2108        if (!this._htOption.drawer || (this._htOption.drawer != 'svg' && this._htOption.drawer != 'canvas')) {
2109            this._htOption.drawer = 'canvas';
2110        }
2111
2112        this._android = _getAndroid();
2113        this._el = el;
2114        this._oQRCode = null;
2115
2116        this._htOption._element = el;
2117
2118        var _htOptionClone = {};
2119        for (var i in this._htOption) {
2120            _htOptionClone[i] = this._htOption[i];
2121        }
2122        this._oDrawing = new Drawing(this._el, _htOptionClone);
2123
2124        if (this._htOption.text) {
2125            this.makeCode(this._htOption.text);
2126        }
2127    };
2128
2129    /**
2130     * Make the QRCode
2131     * 
2132     * @param {String} sText link data
2133     */
2134    QRCode.prototype.makeCode = function(sText) {
2135
2136        this._oQRCode = new QRCodeModel(_getTypeNumber(sText, this._htOption), this._htOption.correctLevel);
2137        this._oQRCode.addData(sText, this._htOption.binary, this._htOption.utf8WithoutBOM);
2138        this._oQRCode.make();
2139        if (this._htOption.tooltip) {
2140            this._el.title = sText;
2141        }
2142        this._oDrawing.draw(this._oQRCode);
2143        //		this.makeImage();
2144    };
2145
2146    /**
2147     * Make the Image from Canvas element
2148     * - It occurs automatically
2149     * - Android below 3 doesn't support Data-URI spec.
2150     * 
2151     * @private
2152     */
2153    QRCode.prototype.makeImage = function() {
2154        if (typeof this._oDrawing.makeImage == "function" && (!this._android || this._android >= 3)) {
2155            this._oDrawing.makeImage();
2156        }
2157    };
2158
2159    /**
2160     * Clear the QRCode
2161     */
2162    QRCode.prototype.clear = function() {
2163        this._oDrawing.remove();
2164    };
2165
2166    /**
2167     * Resize the QRCode
2168     */
2169    QRCode.prototype.resize = function(width, height) {
2170        this._oDrawing._htOption.width = width;
2171        this._oDrawing._htOption.height = height;
2172        this._oDrawing.draw(this._oQRCode);
2173    };
2174
2175
2176
2177    /**
2178     * No Conflict
2179     * @return QRCode object
2180     */
2181    QRCode.prototype.noConflict = function() {
2182        if (root.QRCode === this) {
2183            root.QRCode = _QRCode;
2184        }
2185        return QRCode;
2186    }
2187
2188    /**
2189     * @name QRCode.CorrectLevel
2190     */
2191    QRCode.CorrectLevel = QRErrorCorrectLevel;
2192
2193
2194    /*--------------------------------------------------------------------------*/
2195    // Export QRCode
2196
2197    // AMD & CMD Compatibility
2198    if (typeof define == 'function' && (define.amd || define.cmd)) {
2199
2200        // 1. Define an anonymous module
2201        define([], function() {
2202            return QRCode;
2203        });
2204
2205    }
2206    // CommonJS Compatibility(include NodeJS)
2207    else if (freeModule) {
2208        // Node.js
2209        (freeModule.exports = QRCode).QRCode = QRCode;
2210        // Other CommonJS
2211        freeExports.QRCode = QRCode;
2212    } else {
2213        // Export Global
2214        root.QRCode = QRCode;
2215    }
2216
2217
2218
2219}.call(this));

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.