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.