qrcode.js (44411B)
1 /** 2 * @fileoverview 3 * - Using the 'QRCode for Javascript library' 4 * - Fixed dataset of 'QRCode for Javascript library' for support full-spec. 5 * - this library has no dependencies. 6 * 7 * @author davidshimjs 8 * @see <a href="http://www.d-project.com/" target="_blank">http://www.d-project.com/</a> 9 * @see <a href="http://jeromeetienne.github.com/jquery-qrcode/" target="_blank">http://jeromeetienne.github.com/jquery-qrcode/</a> 10 */ 11 var QRCode 12 ;(function () { 13 // --------------------------------------------------------------------- 14 // QRCode for JavaScript 15 // 16 // Copyright (c) 2009 Kazuhiko Arase 17 // 18 // URL: http://www.d-project.com/ 19 // 20 // Licensed under the MIT license: 21 // http://www.opensource.org/licenses/mit-license.php 22 // 23 // The word "QR Code" is registered trademark of 24 // DENSO WAVE INCORPORATED 25 // http://www.denso-wave.com/qrcode/faqpatent-e.html 26 // 27 // --------------------------------------------------------------------- 28 function QR8bitByte (data) { 29 this.mode = QRMode.MODE_8BIT_BYTE 30 this.data = data 31 this.parsedData = [] 32 33 // Added to support UTF-8 Characters 34 for (var i = 0, l = this.data.length; i < l; i++) { 35 var byteArray = [] 36 var code = this.data.charCodeAt(i) 37 38 if (code > 0x10000) { 39 byteArray[0] = 0xf0 | ((code & 0x1c0000) >>> 18) 40 byteArray[1] = 0x80 | ((code & 0x3f000) >>> 12) 41 byteArray[2] = 0x80 | ((code & 0xfc0) >>> 6) 42 byteArray[3] = 0x80 | (code & 0x3f) 43 } else if (code > 0x800) { 44 byteArray[0] = 0xe0 | ((code & 0xf000) >>> 12) 45 byteArray[1] = 0x80 | ((code & 0xfc0) >>> 6) 46 byteArray[2] = 0x80 | (code & 0x3f) 47 } else if (code > 0x80) { 48 byteArray[0] = 0xc0 | ((code & 0x7c0) >>> 6) 49 byteArray[1] = 0x80 | (code & 0x3f) 50 } else { 51 byteArray[0] = code 52 } 53 54 this.parsedData.push(byteArray) 55 } 56 57 this.parsedData = Array.prototype.concat.apply([], this.parsedData) 58 59 if (this.parsedData.length != this.data.length) { 60 this.parsedData.unshift(191) 61 this.parsedData.unshift(187) 62 this.parsedData.unshift(239) 63 } 64 } 65 66 QR8bitByte.prototype = { 67 getLength: function (buffer) { 68 return this.parsedData.length 69 }, 70 write: function (buffer) { 71 for (var i = 0, l = this.parsedData.length; i < l; i++) { 72 buffer.put(this.parsedData[i], 8) 73 } 74 } 75 } 76 77 function QRCodeModel (typeNumber, errorCorrectLevel) { 78 this.typeNumber = typeNumber 79 this.errorCorrectLevel = errorCorrectLevel 80 this.modules = null 81 this.moduleCount = 0 82 this.dataCache = null 83 this.dataList = [] 84 } 85 86 QRCodeModel.prototype = { 87 addData: function (data) { 88 var newData = new QR8bitByte(data) 89 this.dataList.push(newData) 90 this.dataCache = null 91 }, 92 isDark: function (row, col) { 93 if ( 94 row < 0 || 95 this.moduleCount <= row || 96 col < 0 || 97 this.moduleCount <= col 98 ) { 99 throw new Error(row + ',' + col) 100 } 101 return this.modules[row][col] 102 }, 103 getModuleCount: function () { 104 return this.moduleCount 105 }, 106 make: function () { 107 this.makeImpl(false, this.getBestMaskPattern()) 108 }, 109 makeImpl: function (test, maskPattern) { 110 this.moduleCount = this.typeNumber * 4 + 17 111 this.modules = new Array(this.moduleCount) 112 for (var row = 0; row < this.moduleCount; row++) { 113 this.modules[row] = new Array(this.moduleCount) 114 for (var col = 0; col < this.moduleCount; col++) { 115 this.modules[row][col] = null 116 } 117 } 118 this.setupPositionProbePattern(0, 0) 119 this.setupPositionProbePattern(this.moduleCount - 7, 0) 120 this.setupPositionProbePattern(0, this.moduleCount - 7) 121 this.setupPositionAdjustPattern() 122 this.setupTimingPattern() 123 this.setupTypeInfo(test, maskPattern) 124 if (this.typeNumber >= 7) { 125 this.setupTypeNumber(test) 126 } 127 if (this.dataCache == null) { 128 this.dataCache = QRCodeModel.createData( 129 this.typeNumber, 130 this.errorCorrectLevel, 131 this.dataList 132 ) 133 } 134 this.mapData(this.dataCache, maskPattern) 135 }, 136 setupPositionProbePattern: function (row, col) { 137 for (var r = -1; r <= 7; r++) { 138 if (row + r <= -1 || this.moduleCount <= row + r) continue 139 for (var c = -1; c <= 7; c++) { 140 if (col + c <= -1 || this.moduleCount <= col + c) continue 141 if ( 142 (r >= 0 && r <= 6 && (c == 0 || c == 6)) || 143 (c >= 0 && c <= 6 && (r == 0 || r == 6)) || 144 (r >= 2 && r <= 4 && c >= 2 && c <= 4) 145 ) { 146 this.modules[row + r][col + c] = true 147 } else { 148 this.modules[row + r][col + c] = false 149 } 150 } 151 } 152 }, 153 getBestMaskPattern: function () { 154 var minLostPoint = 0 155 var pattern = 0 156 for (var i = 0; i < 8; i++) { 157 this.makeImpl(true, i) 158 var lostPoint = QRUtil.getLostPoint(this) 159 if (i == 0 || minLostPoint > lostPoint) { 160 minLostPoint = lostPoint 161 pattern = i 162 } 163 } 164 return pattern 165 }, 166 createMovieClip: function (target_mc, instance_name, depth) { 167 var qr_mc = target_mc.createEmptyMovieClip(instance_name, depth) 168 var cs = 1 169 this.make() 170 for (var row = 0; row < this.modules.length; row++) { 171 var y = row * cs 172 for (var col = 0; col < this.modules[row].length; col++) { 173 var x = col * cs 174 var dark = this.modules[row][col] 175 if (dark) { 176 qr_mc.beginFill(0, 100) 177 qr_mc.moveTo(x, y) 178 qr_mc.lineTo(x + cs, y) 179 qr_mc.lineTo(x + cs, y + cs) 180 qr_mc.lineTo(x, y + cs) 181 qr_mc.endFill() 182 } 183 } 184 } 185 return qr_mc 186 }, 187 setupTimingPattern: function () { 188 for (var r = 8; r < this.moduleCount - 8; r++) { 189 if (this.modules[r][6] != null) { 190 continue 191 } 192 this.modules[r][6] = r % 2 == 0 193 } 194 for (var c = 8; c < this.moduleCount - 8; c++) { 195 if (this.modules[6][c] != null) { 196 continue 197 } 198 this.modules[6][c] = c % 2 == 0 199 } 200 }, 201 setupPositionAdjustPattern: function () { 202 var pos = QRUtil.getPatternPosition(this.typeNumber) 203 for (var i = 0; i < pos.length; i++) { 204 for (var j = 0; j < pos.length; j++) { 205 var row = pos[i] 206 var col = pos[j] 207 if (this.modules[row][col] != null) { 208 continue 209 } 210 for (var r = -2; r <= 2; r++) { 211 for (var c = -2; c <= 2; c++) { 212 if ( 213 r == -2 || 214 r == 2 || 215 c == -2 || 216 c == 2 || 217 (r == 0 && c == 0) 218 ) { 219 this.modules[row + r][col + c] = true 220 } else { 221 this.modules[row + r][col + c] = false 222 } 223 } 224 } 225 } 226 } 227 }, 228 setupTypeNumber: function (test) { 229 var bits = QRUtil.getBCHTypeNumber(this.typeNumber) 230 for (var i = 0; i < 18; i++) { 231 var mod = !test && ((bits >> i) & 1) == 1 232 this.modules[Math.floor(i / 3)][i % 3 + this.moduleCount - 8 - 3] = mod 233 } 234 for (var i = 0; i < 18; i++) { 235 var mod = !test && ((bits >> i) & 1) == 1 236 this.modules[i % 3 + this.moduleCount - 8 - 3][Math.floor(i / 3)] = mod 237 } 238 }, 239 setupTypeInfo: function (test, maskPattern) { 240 var data = (this.errorCorrectLevel << 3) | maskPattern 241 var bits = QRUtil.getBCHTypeInfo(data) 242 for (var i = 0; i < 15; i++) { 243 var mod = !test && ((bits >> i) & 1) == 1 244 if (i < 6) { 245 this.modules[i][8] = mod 246 } else if (i < 8) { 247 this.modules[i + 1][8] = mod 248 } else { 249 this.modules[this.moduleCount - 15 + i][8] = mod 250 } 251 } 252 for (var i = 0; i < 15; i++) { 253 var mod = !test && ((bits >> i) & 1) == 1 254 if (i < 8) { 255 this.modules[8][this.moduleCount - i - 1] = mod 256 } else if (i < 9) { 257 this.modules[8][15 - i - 1 + 1] = mod 258 } else { 259 this.modules[8][15 - i - 1] = mod 260 } 261 } 262 this.modules[this.moduleCount - 8][8] = !test 263 }, 264 mapData: function (data, maskPattern) { 265 var inc = -1 266 var row = this.moduleCount - 1 267 var bitIndex = 7 268 var byteIndex = 0 269 for (var col = this.moduleCount - 1; col > 0; col -= 2) { 270 if (col == 6) col-- 271 while (true) { 272 for (var c = 0; c < 2; c++) { 273 if (this.modules[row][col - c] == null) { 274 var dark = false 275 if (byteIndex < data.length) { 276 dark = ((data[byteIndex] >>> bitIndex) & 1) == 1 277 } 278 var mask = QRUtil.getMask(maskPattern, row, col - c) 279 if (mask) { 280 dark = !dark 281 } 282 this.modules[row][col - c] = dark 283 bitIndex-- 284 if (bitIndex == -1) { 285 byteIndex++ 286 bitIndex = 7 287 } 288 } 289 } 290 row += inc 291 if (row < 0 || this.moduleCount <= row) { 292 row -= inc 293 inc = -inc 294 break 295 } 296 } 297 } 298 } 299 } 300 QRCodeModel.PAD0 = 0xec 301 QRCodeModel.PAD1 = 0x11 302 QRCodeModel.createData = function (typeNumber, errorCorrectLevel, dataList) { 303 var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel) 304 var buffer = new QRBitBuffer() 305 for (var i = 0; i < dataList.length; i++) { 306 var data = dataList[i] 307 buffer.put(data.mode, 4) 308 buffer.put( 309 data.getLength(), 310 QRUtil.getLengthInBits(data.mode, typeNumber) 311 ) 312 data.write(buffer) 313 } 314 var totalDataCount = 0 315 for (var i = 0; i < rsBlocks.length; i++) { 316 totalDataCount += rsBlocks[i].dataCount 317 } 318 if (buffer.getLengthInBits() > totalDataCount * 8) { 319 throw new Error( 320 'code length overflow. (' + 321 buffer.getLengthInBits() + 322 '>' + 323 totalDataCount * 8 + 324 ')' 325 ) 326 } 327 if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) { 328 buffer.put(0, 4) 329 } 330 while (buffer.getLengthInBits() % 8 != 0) { 331 buffer.putBit(false) 332 } 333 while (true) { 334 if (buffer.getLengthInBits() >= totalDataCount * 8) { 335 break 336 } 337 buffer.put(QRCodeModel.PAD0, 8) 338 if (buffer.getLengthInBits() >= totalDataCount * 8) { 339 break 340 } 341 buffer.put(QRCodeModel.PAD1, 8) 342 } 343 return QRCodeModel.createBytes(buffer, rsBlocks) 344 } 345 QRCodeModel.createBytes = function (buffer, rsBlocks) { 346 var offset = 0 347 var maxDcCount = 0 348 var maxEcCount = 0 349 var dcdata = new Array(rsBlocks.length) 350 var ecdata = new Array(rsBlocks.length) 351 for (var r = 0; r < rsBlocks.length; r++) { 352 var dcCount = rsBlocks[r].dataCount 353 var ecCount = rsBlocks[r].totalCount - dcCount 354 maxDcCount = Math.max(maxDcCount, dcCount) 355 maxEcCount = Math.max(maxEcCount, ecCount) 356 dcdata[r] = new Array(dcCount) 357 for (var i = 0; i < dcdata[r].length; i++) { 358 dcdata[r][i] = 0xff & buffer.buffer[i + offset] 359 } 360 offset += dcCount 361 var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount) 362 var rawPoly = new QRPolynomial(dcdata[r], rsPoly.getLength() - 1) 363 var modPoly = rawPoly.mod(rsPoly) 364 ecdata[r] = new Array(rsPoly.getLength() - 1) 365 for (var i = 0; i < ecdata[r].length; i++) { 366 var modIndex = i + modPoly.getLength() - ecdata[r].length 367 ecdata[r][i] = modIndex >= 0 ? modPoly.get(modIndex) : 0 368 } 369 } 370 var totalCodeCount = 0 371 for (var i = 0; i < rsBlocks.length; i++) { 372 totalCodeCount += rsBlocks[i].totalCount 373 } 374 var data = new Array(totalCodeCount) 375 var index = 0 376 for (var i = 0; i < maxDcCount; i++) { 377 for (var r = 0; r < rsBlocks.length; r++) { 378 if (i < dcdata[r].length) { 379 data[index++] = dcdata[r][i] 380 } 381 } 382 } 383 for (var i = 0; i < maxEcCount; i++) { 384 for (var r = 0; r < rsBlocks.length; r++) { 385 if (i < ecdata[r].length) { 386 data[index++] = ecdata[r][i] 387 } 388 } 389 } 390 return data 391 } 392 var QRMode = { 393 MODE_NUMBER: 1 << 0, 394 MODE_ALPHA_NUM: 1 << 1, 395 MODE_8BIT_BYTE: 1 << 2, 396 MODE_KANJI: 1 << 3 397 } 398 var QRErrorCorrectLevel = { L: 1, M: 0, Q: 3, H: 2 } 399 var QRMaskPattern = { 400 PATTERN000: 0, 401 PATTERN001: 1, 402 PATTERN010: 2, 403 PATTERN011: 3, 404 PATTERN100: 4, 405 PATTERN101: 5, 406 PATTERN110: 6, 407 PATTERN111: 7 408 } 409 var QRUtil = { 410 PATTERN_POSITION_TABLE: [ 411 [], 412 [6, 18], 413 [6, 22], 414 [6, 26], 415 [6, 30], 416 [6, 34], 417 [6, 22, 38], 418 [6, 24, 42], 419 [6, 26, 46], 420 [6, 28, 50], 421 [6, 30, 54], 422 [6, 32, 58], 423 [6, 34, 62], 424 [6, 26, 46, 66], 425 [6, 26, 48, 70], 426 [6, 26, 50, 74], 427 [6, 30, 54, 78], 428 [6, 30, 56, 82], 429 [6, 30, 58, 86], 430 [6, 34, 62, 90], 431 [6, 28, 50, 72, 94], 432 [6, 26, 50, 74, 98], 433 [6, 30, 54, 78, 102], 434 [6, 28, 54, 80, 106], 435 [6, 32, 58, 84, 110], 436 [6, 30, 58, 86, 114], 437 [6, 34, 62, 90, 118], 438 [6, 26, 50, 74, 98, 122], 439 [6, 30, 54, 78, 102, 126], 440 [6, 26, 52, 78, 104, 130], 441 [6, 30, 56, 82, 108, 134], 442 [6, 34, 60, 86, 112, 138], 443 [6, 30, 58, 86, 114, 142], 444 [6, 34, 62, 90, 118, 146], 445 [6, 30, 54, 78, 102, 126, 150], 446 [6, 24, 50, 76, 102, 128, 154], 447 [6, 28, 54, 80, 106, 132, 158], 448 [6, 32, 58, 84, 110, 136, 162], 449 [6, 26, 54, 82, 110, 138, 166], 450 [6, 30, 58, 86, 114, 142, 170] 451 ], 452 G15: 453 (1 << 10) | 454 (1 << 8) | 455 (1 << 5) | 456 (1 << 4) | 457 (1 << 2) | 458 (1 << 1) | 459 (1 << 0), 460 G18: 461 (1 << 12) | 462 (1 << 11) | 463 (1 << 10) | 464 (1 << 9) | 465 (1 << 8) | 466 (1 << 5) | 467 (1 << 2) | 468 (1 << 0), 469 G15_MASK: (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1), 470 getBCHTypeInfo: function (data) { 471 var d = data << 10 472 while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0) { 473 d ^= 474 QRUtil.G15 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15)) 475 } 476 return ((data << 10) | d) ^ QRUtil.G15_MASK 477 }, 478 getBCHTypeNumber: function (data) { 479 var d = data << 12 480 while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0) { 481 d ^= 482 QRUtil.G18 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18)) 483 } 484 return (data << 12) | d 485 }, 486 getBCHDigit: function (data) { 487 var digit = 0 488 while (data != 0) { 489 digit++ 490 data >>>= 1 491 } 492 return digit 493 }, 494 getPatternPosition: function (typeNumber) { 495 return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1] 496 }, 497 getMask: function (maskPattern, i, j) { 498 switch (maskPattern) { 499 case QRMaskPattern.PATTERN000: 500 return (i + j) % 2 == 0 501 case QRMaskPattern.PATTERN001: 502 return i % 2 == 0 503 case QRMaskPattern.PATTERN010: 504 return j % 3 == 0 505 case QRMaskPattern.PATTERN011: 506 return (i + j) % 3 == 0 507 case QRMaskPattern.PATTERN100: 508 return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 == 0 509 case QRMaskPattern.PATTERN101: 510 return (i * j) % 2 + (i * j) % 3 == 0 511 case QRMaskPattern.PATTERN110: 512 return ((i * j) % 2 + (i * j) % 3) % 2 == 0 513 case QRMaskPattern.PATTERN111: 514 return ((i * j) % 3 + (i + j) % 2) % 2 == 0 515 default: 516 throw new Error('bad maskPattern:' + maskPattern) 517 } 518 }, 519 getErrorCorrectPolynomial: function (errorCorrectLength) { 520 var a = new QRPolynomial([1], 0) 521 for (var i = 0; i < errorCorrectLength; i++) { 522 a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0)) 523 } 524 return a 525 }, 526 getLengthInBits: function (mode, type) { 527 if (type >= 1 && type < 10) { 528 switch (mode) { 529 case QRMode.MODE_NUMBER: 530 return 10 531 case QRMode.MODE_ALPHA_NUM: 532 return 9 533 case QRMode.MODE_8BIT_BYTE: 534 return 8 535 case QRMode.MODE_KANJI: 536 return 8 537 default: 538 throw new Error('mode:' + mode) 539 } 540 } else if (type < 27) { 541 switch (mode) { 542 case QRMode.MODE_NUMBER: 543 return 12 544 case QRMode.MODE_ALPHA_NUM: 545 return 11 546 case QRMode.MODE_8BIT_BYTE: 547 return 16 548 case QRMode.MODE_KANJI: 549 return 10 550 default: 551 throw new Error('mode:' + mode) 552 } 553 } else if (type < 41) { 554 switch (mode) { 555 case QRMode.MODE_NUMBER: 556 return 14 557 case QRMode.MODE_ALPHA_NUM: 558 return 13 559 case QRMode.MODE_8BIT_BYTE: 560 return 16 561 case QRMode.MODE_KANJI: 562 return 12 563 default: 564 throw new Error('mode:' + mode) 565 } 566 } else { 567 throw new Error('type:' + type) 568 } 569 }, 570 getLostPoint: function (qrCode) { 571 var moduleCount = qrCode.getModuleCount() 572 var lostPoint = 0 573 for (var row = 0; row < moduleCount; row++) { 574 for (var col = 0; col < moduleCount; col++) { 575 var sameCount = 0 576 var dark = qrCode.isDark(row, col) 577 for (var r = -1; r <= 1; r++) { 578 if (row + r < 0 || moduleCount <= row + r) { 579 continue 580 } 581 for (var c = -1; c <= 1; c++) { 582 if (col + c < 0 || moduleCount <= col + c) { 583 continue 584 } 585 if (r == 0 && c == 0) { 586 continue 587 } 588 if (dark == qrCode.isDark(row + r, col + c)) { 589 sameCount++ 590 } 591 } 592 } 593 if (sameCount > 5) { 594 lostPoint += 3 + sameCount - 5 595 } 596 } 597 } 598 for (var row = 0; row < moduleCount - 1; row++) { 599 for (var col = 0; col < moduleCount - 1; col++) { 600 var count = 0 601 if (qrCode.isDark(row, col)) count++ 602 if (qrCode.isDark(row + 1, col)) count++ 603 if (qrCode.isDark(row, col + 1)) count++ 604 if (qrCode.isDark(row + 1, col + 1)) count++ 605 if (count == 0 || count == 4) { 606 lostPoint += 3 607 } 608 } 609 } 610 for (var row = 0; row < moduleCount; row++) { 611 for (var col = 0; col < moduleCount - 6; col++) { 612 if ( 613 qrCode.isDark(row, col) && 614 !qrCode.isDark(row, col + 1) && 615 qrCode.isDark(row, col + 2) && 616 qrCode.isDark(row, col + 3) && 617 qrCode.isDark(row, col + 4) && 618 !qrCode.isDark(row, col + 5) && 619 qrCode.isDark(row, col + 6) 620 ) { 621 lostPoint += 40 622 } 623 } 624 } 625 for (var col = 0; col < moduleCount; col++) { 626 for (var row = 0; row < moduleCount - 6; row++) { 627 if ( 628 qrCode.isDark(row, col) && 629 !qrCode.isDark(row + 1, col) && 630 qrCode.isDark(row + 2, col) && 631 qrCode.isDark(row + 3, col) && 632 qrCode.isDark(row + 4, col) && 633 !qrCode.isDark(row + 5, col) && 634 qrCode.isDark(row + 6, col) 635 ) { 636 lostPoint += 40 637 } 638 } 639 } 640 var darkCount = 0 641 for (var col = 0; col < moduleCount; col++) { 642 for (var row = 0; row < moduleCount; row++) { 643 if (qrCode.isDark(row, col)) { 644 darkCount++ 645 } 646 } 647 } 648 var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5 649 lostPoint += ratio * 10 650 return lostPoint 651 } 652 } 653 var QRMath = { 654 glog: function (n) { 655 if (n < 1) { 656 throw new Error('glog(' + n + ')') 657 } 658 return QRMath.LOG_TABLE[n] 659 }, 660 gexp: function (n) { 661 while (n < 0) { 662 n += 255 663 } 664 while (n >= 256) { 665 n -= 255 666 } 667 return QRMath.EXP_TABLE[n] 668 }, 669 EXP_TABLE: new Array(256), 670 LOG_TABLE: new Array(256) 671 } 672 for (var i = 0; i < 8; i++) { 673 QRMath.EXP_TABLE[i] = 1 << i 674 } 675 for (var i = 8; i < 256; i++) { 676 QRMath.EXP_TABLE[i] = 677 QRMath.EXP_TABLE[i - 4] ^ 678 QRMath.EXP_TABLE[i - 5] ^ 679 QRMath.EXP_TABLE[i - 6] ^ 680 QRMath.EXP_TABLE[i - 8] 681 } 682 for (var i = 0; i < 255; i++) { 683 QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]] = i 684 } 685 function QRPolynomial (num, shift) { 686 if (num.length == undefined) { 687 throw new Error(num.length + '/' + shift) 688 } 689 var offset = 0 690 while (offset < num.length && num[offset] == 0) { 691 offset++ 692 } 693 this.num = new Array(num.length - offset + shift) 694 for (var i = 0; i < num.length - offset; i++) { 695 this.num[i] = num[i + offset] 696 } 697 } 698 QRPolynomial.prototype = { 699 get: function (index) { 700 return this.num[index] 701 }, 702 getLength: function () { 703 return this.num.length 704 }, 705 multiply: function (e) { 706 var num = new Array(this.getLength() + e.getLength() - 1) 707 for (var i = 0; i < this.getLength(); i++) { 708 for (var j = 0; j < e.getLength(); j++) { 709 num[i + j] ^= QRMath.gexp( 710 QRMath.glog(this.get(i)) + QRMath.glog(e.get(j)) 711 ) 712 } 713 } 714 return new QRPolynomial(num, 0) 715 }, 716 mod: function (e) { 717 if (this.getLength() - e.getLength() < 0) { 718 return this 719 } 720 var ratio = QRMath.glog(this.get(0)) - QRMath.glog(e.get(0)) 721 var num = new Array(this.getLength()) 722 for (var i = 0; i < this.getLength(); i++) { 723 num[i] = this.get(i) 724 } 725 for (var i = 0; i < e.getLength(); i++) { 726 num[i] ^= QRMath.gexp(QRMath.glog(e.get(i)) + ratio) 727 } 728 return new QRPolynomial(num, 0).mod(e) 729 } 730 } 731 function QRRSBlock (totalCount, dataCount) { 732 this.totalCount = totalCount 733 this.dataCount = dataCount 734 } 735 QRRSBlock.RS_BLOCK_TABLE = [ 736 [1, 26, 19], 737 [1, 26, 16], 738 [1, 26, 13], 739 [1, 26, 9], 740 [1, 44, 34], 741 [1, 44, 28], 742 [1, 44, 22], 743 [1, 44, 16], 744 [1, 70, 55], 745 [1, 70, 44], 746 [2, 35, 17], 747 [2, 35, 13], 748 [1, 100, 80], 749 [2, 50, 32], 750 [2, 50, 24], 751 [4, 25, 9], 752 [1, 134, 108], 753 [2, 67, 43], 754 [2, 33, 15, 2, 34, 16], 755 [2, 33, 11, 2, 34, 12], 756 [2, 86, 68], 757 [4, 43, 27], 758 [4, 43, 19], 759 [4, 43, 15], 760 [2, 98, 78], 761 [4, 49, 31], 762 [2, 32, 14, 4, 33, 15], 763 [4, 39, 13, 1, 40, 14], 764 [2, 121, 97], 765 [2, 60, 38, 2, 61, 39], 766 [4, 40, 18, 2, 41, 19], 767 [4, 40, 14, 2, 41, 15], 768 [2, 146, 116], 769 [3, 58, 36, 2, 59, 37], 770 [4, 36, 16, 4, 37, 17], 771 [4, 36, 12, 4, 37, 13], 772 [2, 86, 68, 2, 87, 69], 773 [4, 69, 43, 1, 70, 44], 774 [6, 43, 19, 2, 44, 20], 775 [6, 43, 15, 2, 44, 16], 776 [4, 101, 81], 777 [1, 80, 50, 4, 81, 51], 778 [4, 50, 22, 4, 51, 23], 779 [3, 36, 12, 8, 37, 13], 780 [2, 116, 92, 2, 117, 93], 781 [6, 58, 36, 2, 59, 37], 782 [4, 46, 20, 6, 47, 21], 783 [7, 42, 14, 4, 43, 15], 784 [4, 133, 107], 785 [8, 59, 37, 1, 60, 38], 786 [8, 44, 20, 4, 45, 21], 787 [12, 33, 11, 4, 34, 12], 788 [3, 145, 115, 1, 146, 116], 789 [4, 64, 40, 5, 65, 41], 790 [11, 36, 16, 5, 37, 17], 791 [11, 36, 12, 5, 37, 13], 792 [5, 109, 87, 1, 110, 88], 793 [5, 65, 41, 5, 66, 42], 794 [5, 54, 24, 7, 55, 25], 795 [11, 36, 12], 796 [5, 122, 98, 1, 123, 99], 797 [7, 73, 45, 3, 74, 46], 798 [15, 43, 19, 2, 44, 20], 799 [3, 45, 15, 13, 46, 16], 800 [1, 135, 107, 5, 136, 108], 801 [10, 74, 46, 1, 75, 47], 802 [1, 50, 22, 15, 51, 23], 803 [2, 42, 14, 17, 43, 15], 804 [5, 150, 120, 1, 151, 121], 805 [9, 69, 43, 4, 70, 44], 806 [17, 50, 22, 1, 51, 23], 807 [2, 42, 14, 19, 43, 15], 808 [3, 141, 113, 4, 142, 114], 809 [3, 70, 44, 11, 71, 45], 810 [17, 47, 21, 4, 48, 22], 811 [9, 39, 13, 16, 40, 14], 812 [3, 135, 107, 5, 136, 108], 813 [3, 67, 41, 13, 68, 42], 814 [15, 54, 24, 5, 55, 25], 815 [15, 43, 15, 10, 44, 16], 816 [4, 144, 116, 4, 145, 117], 817 [17, 68, 42], 818 [17, 50, 22, 6, 51, 23], 819 [19, 46, 16, 6, 47, 17], 820 [2, 139, 111, 7, 140, 112], 821 [17, 74, 46], 822 [7, 54, 24, 16, 55, 25], 823 [34, 37, 13], 824 [4, 151, 121, 5, 152, 122], 825 [4, 75, 47, 14, 76, 48], 826 [11, 54, 24, 14, 55, 25], 827 [16, 45, 15, 14, 46, 16], 828 [6, 147, 117, 4, 148, 118], 829 [6, 73, 45, 14, 74, 46], 830 [11, 54, 24, 16, 55, 25], 831 [30, 46, 16, 2, 47, 17], 832 [8, 132, 106, 4, 133, 107], 833 [8, 75, 47, 13, 76, 48], 834 [7, 54, 24, 22, 55, 25], 835 [22, 45, 15, 13, 46, 16], 836 [10, 142, 114, 2, 143, 115], 837 [19, 74, 46, 4, 75, 47], 838 [28, 50, 22, 6, 51, 23], 839 [33, 46, 16, 4, 47, 17], 840 [8, 152, 122, 4, 153, 123], 841 [22, 73, 45, 3, 74, 46], 842 [8, 53, 23, 26, 54, 24], 843 [12, 45, 15, 28, 46, 16], 844 [3, 147, 117, 10, 148, 118], 845 [3, 73, 45, 23, 74, 46], 846 [4, 54, 24, 31, 55, 25], 847 [11, 45, 15, 31, 46, 16], 848 [7, 146, 116, 7, 147, 117], 849 [21, 73, 45, 7, 74, 46], 850 [1, 53, 23, 37, 54, 24], 851 [19, 45, 15, 26, 46, 16], 852 [5, 145, 115, 10, 146, 116], 853 [19, 75, 47, 10, 76, 48], 854 [15, 54, 24, 25, 55, 25], 855 [23, 45, 15, 25, 46, 16], 856 [13, 145, 115, 3, 146, 116], 857 [2, 74, 46, 29, 75, 47], 858 [42, 54, 24, 1, 55, 25], 859 [23, 45, 15, 28, 46, 16], 860 [17, 145, 115], 861 [10, 74, 46, 23, 75, 47], 862 [10, 54, 24, 35, 55, 25], 863 [19, 45, 15, 35, 46, 16], 864 [17, 145, 115, 1, 146, 116], 865 [14, 74, 46, 21, 75, 47], 866 [29, 54, 24, 19, 55, 25], 867 [11, 45, 15, 46, 46, 16], 868 [13, 145, 115, 6, 146, 116], 869 [14, 74, 46, 23, 75, 47], 870 [44, 54, 24, 7, 55, 25], 871 [59, 46, 16, 1, 47, 17], 872 [12, 151, 121, 7, 152, 122], 873 [12, 75, 47, 26, 76, 48], 874 [39, 54, 24, 14, 55, 25], 875 [22, 45, 15, 41, 46, 16], 876 [6, 151, 121, 14, 152, 122], 877 [6, 75, 47, 34, 76, 48], 878 [46, 54, 24, 10, 55, 25], 879 [2, 45, 15, 64, 46, 16], 880 [17, 152, 122, 4, 153, 123], 881 [29, 74, 46, 14, 75, 47], 882 [49, 54, 24, 10, 55, 25], 883 [24, 45, 15, 46, 46, 16], 884 [4, 152, 122, 18, 153, 123], 885 [13, 74, 46, 32, 75, 47], 886 [48, 54, 24, 14, 55, 25], 887 [42, 45, 15, 32, 46, 16], 888 [20, 147, 117, 4, 148, 118], 889 [40, 75, 47, 7, 76, 48], 890 [43, 54, 24, 22, 55, 25], 891 [10, 45, 15, 67, 46, 16], 892 [19, 148, 118, 6, 149, 119], 893 [18, 75, 47, 31, 76, 48], 894 [34, 54, 24, 34, 55, 25], 895 [20, 45, 15, 61, 46, 16] 896 ] 897 QRRSBlock.getRSBlocks = function (typeNumber, errorCorrectLevel) { 898 var rsBlock = QRRSBlock.getRsBlockTable(typeNumber, errorCorrectLevel) 899 if (rsBlock == undefined) { 900 throw new Error( 901 'bad rs block @ typeNumber:' + 902 typeNumber + 903 '/errorCorrectLevel:' + 904 errorCorrectLevel 905 ) 906 } 907 var length = rsBlock.length / 3 908 var list = [] 909 for (var i = 0; i < length; i++) { 910 var count = rsBlock[i * 3 + 0] 911 var totalCount = rsBlock[i * 3 + 1] 912 var dataCount = rsBlock[i * 3 + 2] 913 for (var j = 0; j < count; j++) { 914 list.push(new QRRSBlock(totalCount, dataCount)) 915 } 916 } 917 return list 918 } 919 QRRSBlock.getRsBlockTable = function (typeNumber, errorCorrectLevel) { 920 switch (errorCorrectLevel) { 921 case QRErrorCorrectLevel.L: 922 return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0] 923 case QRErrorCorrectLevel.M: 924 return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1] 925 case QRErrorCorrectLevel.Q: 926 return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2] 927 case QRErrorCorrectLevel.H: 928 return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3] 929 default: 930 return undefined 931 } 932 } 933 function QRBitBuffer () { 934 this.buffer = [] 935 this.length = 0 936 } 937 QRBitBuffer.prototype = { 938 get: function (index) { 939 var bufIndex = Math.floor(index / 8) 940 return ((this.buffer[bufIndex] >>> (7 - index % 8)) & 1) == 1 941 }, 942 put: function (num, length) { 943 for (var i = 0; i < length; i++) { 944 this.putBit(((num >>> (length - i - 1)) & 1) == 1) 945 } 946 }, 947 getLengthInBits: function () { 948 return this.length 949 }, 950 putBit: function (bit) { 951 var bufIndex = Math.floor(this.length / 8) 952 if (this.buffer.length <= bufIndex) { 953 this.buffer.push(0) 954 } 955 if (bit) { 956 this.buffer[bufIndex] |= 0x80 >>> (this.length % 8) 957 } 958 this.length++ 959 } 960 } 961 var QRCodeLimitLength = [ 962 [17, 14, 11, 7], 963 [32, 26, 20, 14], 964 [53, 42, 32, 24], 965 [78, 62, 46, 34], 966 [106, 84, 60, 44], 967 [134, 106, 74, 58], 968 [154, 122, 86, 64], 969 [192, 152, 108, 84], 970 [230, 180, 130, 98], 971 [271, 213, 151, 119], 972 [321, 251, 177, 137], 973 [367, 287, 203, 155], 974 [425, 331, 241, 177], 975 [458, 362, 258, 194], 976 [520, 412, 292, 220], 977 [586, 450, 322, 250], 978 [644, 504, 364, 280], 979 [718, 560, 394, 310], 980 [792, 624, 442, 338], 981 [858, 666, 482, 382], 982 [929, 711, 509, 403], 983 [1003, 779, 565, 439], 984 [1091, 857, 611, 461], 985 [1171, 911, 661, 511], 986 [1273, 997, 715, 535], 987 [1367, 1059, 751, 593], 988 [1465, 1125, 805, 625], 989 [1528, 1190, 868, 658], 990 [1628, 1264, 908, 698], 991 [1732, 1370, 982, 742], 992 [1840, 1452, 1030, 790], 993 [1952, 1538, 1112, 842], 994 [2068, 1628, 1168, 898], 995 [2188, 1722, 1228, 958], 996 [2303, 1809, 1283, 983], 997 [2431, 1911, 1351, 1051], 998 [2563, 1989, 1423, 1093], 999 [2699, 2099, 1499, 1139], 1000 [2809, 2213, 1579, 1219], 1001 [2953, 2331, 1663, 1273] 1002 ] 1003 1004 function _isSupportCanvas () { 1005 return typeof CanvasRenderingContext2D !== 'undefined' 1006 } 1007 1008 // android 2.x doesn't support Data-URI spec 1009 function _getAndroid () { 1010 var android = false 1011 var sAgent = navigator.userAgent 1012 1013 if (/android/i.test(sAgent)) { 1014 // android 1015 android = true 1016 var aMat = sAgent.toString().match(/android ([0-9]\.[0-9])/i) 1017 1018 if (aMat && aMat[1]) { 1019 android = parseFloat(aMat[1]) 1020 } 1021 } 1022 1023 return android 1024 } 1025 1026 var svgDrawer = (function () { 1027 var Drawing = function (el, htOption) { 1028 this._el = el 1029 this._htOption = htOption 1030 } 1031 1032 Drawing.prototype.draw = function (oQRCode) { 1033 var _htOption = this._htOption 1034 var _el = this._el 1035 var nCount = oQRCode.getModuleCount() 1036 var nWidth = Math.floor(_htOption.width / nCount) 1037 var nHeight = Math.floor(_htOption.height / nCount) 1038 1039 this.clear() 1040 1041 function makeSVG (tag, attrs) { 1042 var el = document.createElementNS('http://www.w3.org/2000/svg', tag) 1043 for (var k in attrs) { 1044 if (attrs.hasOwnProperty(k)) el.setAttribute(k, attrs[k]) 1045 } 1046 return el 1047 } 1048 1049 var svg = makeSVG('svg', { 1050 viewBox: '0 0 ' + String(nCount) + ' ' + String(nCount), 1051 width: '100%', 1052 height: '100%', 1053 fill: _htOption.colorLight 1054 }) 1055 svg.setAttributeNS( 1056 'http://www.w3.org/2000/xmlns/', 1057 'xmlns:xlink', 1058 'http://www.w3.org/1999/xlink' 1059 ) 1060 _el.appendChild(svg) 1061 1062 svg.appendChild( 1063 makeSVG('rect', { 1064 fill: _htOption.colorLight, 1065 width: '100%', 1066 height: '100%' 1067 }) 1068 ) 1069 svg.appendChild( 1070 makeSVG('rect', { 1071 fill: _htOption.colorDark, 1072 width: '1', 1073 height: '1', 1074 id: 'template' 1075 }) 1076 ) 1077 1078 for (var row = 0; row < nCount; row++) { 1079 for (var col = 0; col < nCount; col++) { 1080 if (oQRCode.isDark(row, col)) { 1081 var child = makeSVG('use', { x: String(col), y: String(row) }) 1082 child.setAttributeNS( 1083 'http://www.w3.org/1999/xlink', 1084 'href', 1085 '#template' 1086 ) 1087 svg.appendChild(child) 1088 } 1089 } 1090 } 1091 } 1092 Drawing.prototype.clear = function () { 1093 while (this._el.hasChildNodes()) this._el.removeChild(this._el.lastChild) 1094 } 1095 return Drawing 1096 })() 1097 1098 var useSVG = document.documentElement.tagName.toLowerCase() === 'svg' 1099 1100 // Drawing in DOM by using Table tag 1101 var Drawing = useSVG 1102 ? svgDrawer 1103 : !_isSupportCanvas() 1104 ? (function () { 1105 var Drawing = function (el, htOption) { 1106 this._el = el 1107 this._htOption = htOption 1108 } 1109 1110 /** 1111 * Draw the QRCode 1112 * 1113 * @param {QRCode} oQRCode 1114 */ 1115 Drawing.prototype.draw = function (oQRCode) { 1116 var _htOption = this._htOption 1117 var _el = this._el 1118 var nCount = oQRCode.getModuleCount() 1119 var nWidth = Math.floor(_htOption.width / nCount) 1120 var nHeight = Math.floor(_htOption.height / nCount) 1121 var aHTML = ['<table style="border:0;border-collapse:collapse;">'] 1122 1123 for (var row = 0; row < nCount; row++) { 1124 aHTML.push('<tr>') 1125 1126 for (var col = 0; col < nCount; col++) { 1127 aHTML.push( 1128 '<td style="border:0;border-collapse:collapse;padding:0;margin:0;width:' + 1129 nWidth + 1130 'px;height:' + 1131 nHeight + 1132 'px;background-color:' + 1133 (oQRCode.isDark(row, col) 1134 ? _htOption.colorDark 1135 : _htOption.colorLight) + 1136 ';"></td>' 1137 ) 1138 } 1139 1140 aHTML.push('</tr>') 1141 } 1142 1143 aHTML.push('</table>') 1144 _el.innerHTML = aHTML.join('') 1145 1146 // Fix the margin values as real size. 1147 var elTable = _el.childNodes[0] 1148 var nLeftMarginTable = (_htOption.width - elTable.offsetWidth) / 2 1149 var nTopMarginTable = (_htOption.height - elTable.offsetHeight) / 2 1150 1151 if (nLeftMarginTable > 0 && nTopMarginTable > 0) { 1152 elTable.style.margin = 1153 nTopMarginTable + 'px ' + nLeftMarginTable + 'px' 1154 } 1155 } 1156 1157 /** 1158 * Clear the QRCode 1159 */ 1160 Drawing.prototype.clear = function () { 1161 this._el.innerHTML = '' 1162 } 1163 1164 return Drawing 1165 })() 1166 : (function () { 1167 // Drawing in Canvas 1168 function _onMakeImage () { 1169 this._elImage.src = this._elCanvas.toDataURL('image/png') 1170 this._elImage.style.display = 'block' 1171 this._elCanvas.style.display = 'none' 1172 } 1173 1174 // Android 2.1 bug workaround 1175 // http://code.google.com/p/android/issues/detail?id=5141 1176 if (this._android && this._android <= 2.1) { 1177 var factor = 1 / window.devicePixelRatio 1178 var drawImage = CanvasRenderingContext2D.prototype.drawImage 1179 CanvasRenderingContext2D.prototype.drawImage = function ( 1180 image, 1181 sx, 1182 sy, 1183 sw, 1184 sh, 1185 dx, 1186 dy, 1187 dw, 1188 dh 1189 ) { 1190 if ('nodeName' in image && /img/i.test(image.nodeName)) { 1191 for (var i = arguments.length - 1; i >= 1; i--) { 1192 arguments[i] = arguments[i] * factor 1193 } 1194 } else if (typeof dw === 'undefined') { 1195 arguments[1] *= factor 1196 arguments[2] *= factor 1197 arguments[3] *= factor 1198 arguments[4] *= factor 1199 } 1200 1201 drawImage.apply(this, arguments) 1202 } 1203 } 1204 1205 /** 1206 * Check whether the user's browser supports Data URI or not 1207 * 1208 * @private 1209 * @param {Function} fSuccess Occurs if it supports Data URI 1210 * @param {Function} fFail Occurs if it doesn't support Data URI 1211 */ 1212 function _safeSetDataURI (fSuccess, fFail) { 1213 var self = this 1214 self._fFail = fFail 1215 self._fSuccess = fSuccess 1216 1217 // Check it just once 1218 if (self._bSupportDataURI === null) { 1219 var el = document.createElement('img') 1220 var fOnError = function () { 1221 self._bSupportDataURI = false 1222 1223 if (self._fFail) { 1224 self._fFail.call(self) 1225 } 1226 } 1227 var fOnSuccess = function () { 1228 self._bSupportDataURI = true 1229 1230 if (self._fSuccess) { 1231 self._fSuccess.call(self) 1232 } 1233 } 1234 1235 el.onabort = fOnError 1236 el.onerror = fOnError 1237 el.onload = fOnSuccess 1238 el.src = 1239 'data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==' // the Image contains 1px data. 1240 } else if (self._bSupportDataURI === true && self._fSuccess) { 1241 self._fSuccess.call(self) 1242 } else if (self._bSupportDataURI === false && self._fFail) { 1243 self._fFail.call(self) 1244 } 1245 } 1246 1247 /** 1248 * Drawing QRCode by using canvas 1249 * 1250 * @constructor 1251 * @param {HTMLElement} el 1252 * @param {Object} htOption QRCode Options 1253 */ 1254 var Drawing = function (el, htOption) { 1255 this._bIsPainted = false 1256 this._android = _getAndroid() 1257 1258 this._htOption = htOption 1259 this._elCanvas = document.createElement('canvas') 1260 this._elCanvas.width = htOption.width 1261 this._elCanvas.height = htOption.height 1262 el.appendChild(this._elCanvas) 1263 this._el = el 1264 this._oContext = this._elCanvas.getContext('2d') 1265 this._bIsPainted = false 1266 this._elImage = document.createElement('img') 1267 this._elImage.alt = 'Scan me!' 1268 this._elImage.style.display = 'none' 1269 this._el.appendChild(this._elImage) 1270 this._bSupportDataURI = null 1271 } 1272 1273 /** 1274 * Draw the QRCode 1275 * 1276 * @param {QRCode} oQRCode 1277 */ 1278 Drawing.prototype.draw = function (oQRCode) { 1279 var _elImage = this._elImage 1280 var _oContext = this._oContext 1281 var _htOption = this._htOption 1282 1283 var nCount = oQRCode.getModuleCount() 1284 var nWidth = _htOption.width / nCount 1285 var nHeight = _htOption.height / nCount 1286 var nRoundedWidth = Math.round(nWidth) 1287 var nRoundedHeight = Math.round(nHeight) 1288 1289 _elImage.style.display = 'none' 1290 this.clear() 1291 1292 for (var row = 0; row < nCount; row++) { 1293 for (var col = 0; col < nCount; col++) { 1294 var bIsDark = oQRCode.isDark(row, col) 1295 var nLeft = col * nWidth 1296 var nTop = row * nHeight 1297 _oContext.strokeStyle = bIsDark 1298 ? _htOption.colorDark 1299 : _htOption.colorLight 1300 _oContext.lineWidth = 1 1301 _oContext.fillStyle = bIsDark 1302 ? _htOption.colorDark 1303 : _htOption.colorLight 1304 _oContext.fillRect(nLeft, nTop, nWidth, nHeight) 1305 1306 // 안티 앨리어싱 방지 처리 1307 _oContext.strokeRect( 1308 Math.floor(nLeft) + 0.5, 1309 Math.floor(nTop) + 0.5, 1310 nRoundedWidth, 1311 nRoundedHeight 1312 ) 1313 1314 _oContext.strokeRect( 1315 Math.ceil(nLeft) - 0.5, 1316 Math.ceil(nTop) - 0.5, 1317 nRoundedWidth, 1318 nRoundedHeight 1319 ) 1320 } 1321 } 1322 1323 this._bIsPainted = true 1324 } 1325 1326 /** 1327 * Make the image from Canvas if the browser supports Data URI. 1328 */ 1329 Drawing.prototype.makeImage = function () { 1330 if (this._bIsPainted) { 1331 _safeSetDataURI.call(this, _onMakeImage) 1332 } 1333 } 1334 1335 /** 1336 * Return whether the QRCode is painted or not 1337 * 1338 * @return {Boolean} 1339 */ 1340 Drawing.prototype.isPainted = function () { 1341 return this._bIsPainted 1342 } 1343 1344 /** 1345 * Clear the QRCode 1346 */ 1347 Drawing.prototype.clear = function () { 1348 this._oContext.clearRect( 1349 0, 1350 0, 1351 this._elCanvas.width, 1352 this._elCanvas.height 1353 ) 1354 this._bIsPainted = false 1355 } 1356 1357 /** 1358 * @private 1359 * @param {Number} nNumber 1360 */ 1361 Drawing.prototype.round = function (nNumber) { 1362 if (!nNumber) { 1363 return nNumber 1364 } 1365 1366 return Math.floor(nNumber * 1000) / 1000 1367 } 1368 1369 return Drawing 1370 })() 1371 1372 /** 1373 * Get the type by string length 1374 * 1375 * @private 1376 * @param {String} sText 1377 * @param {Number} nCorrectLevel 1378 * @return {Number} type 1379 */ 1380 function _getTypeNumber (sText, nCorrectLevel) { 1381 var nType = 1 1382 var length = _getUTF8Length(sText) 1383 1384 for (var i = 0, len = QRCodeLimitLength.length; i <= len; i++) { 1385 var nLimit = 0 1386 1387 switch (nCorrectLevel) { 1388 case QRErrorCorrectLevel.L: 1389 nLimit = QRCodeLimitLength[i][0] 1390 break 1391 case QRErrorCorrectLevel.M: 1392 nLimit = QRCodeLimitLength[i][1] 1393 break 1394 case QRErrorCorrectLevel.Q: 1395 nLimit = QRCodeLimitLength[i][2] 1396 break 1397 case QRErrorCorrectLevel.H: 1398 nLimit = QRCodeLimitLength[i][3] 1399 break 1400 } 1401 1402 if (length <= nLimit) { 1403 break 1404 } else { 1405 nType++ 1406 } 1407 } 1408 1409 if (nType > QRCodeLimitLength.length) { 1410 throw new Error('Too long data') 1411 } 1412 1413 return nType 1414 } 1415 1416 function _getUTF8Length (sText) { 1417 var replacedText = encodeURI(sText) 1418 .toString() 1419 .replace(/\%[0-9a-fA-F]{2}/g, 'a') 1420 return replacedText.length + (replacedText.length != sText ? 3 : 0) 1421 } 1422 1423 /** 1424 * @class QRCode 1425 * @constructor 1426 * @example 1427 * new QRCode(document.getElementById("test"), "http://jindo.dev.naver.com/collie"); 1428 * 1429 * @example 1430 * var oQRCode = new QRCode("test", { 1431 * text : "http://naver.com", 1432 * width : 128, 1433 * height : 128 1434 * }); 1435 * 1436 * oQRCode.clear(); // Clear the QRCode. 1437 * oQRCode.makeCode("http://map.naver.com"); // Re-create the QRCode. 1438 * 1439 * @param {HTMLElement|String} el target element or 'id' attribute of element. 1440 * @param {Object|String} vOption 1441 * @param {String} vOption.text QRCode link data 1442 * @param {Number} [vOption.width=256] 1443 * @param {Number} [vOption.height=256] 1444 * @param {String} [vOption.colorDark="#000000"] 1445 * @param {String} [vOption.colorLight="#ffffff"] 1446 * @param {QRCode.CorrectLevel} [vOption.correctLevel=QRCode.CorrectLevel.H] [L|M|Q|H] 1447 */ 1448 QRCode = function (el, vOption) { 1449 this._htOption = { 1450 width: 256, 1451 height: 256, 1452 typeNumber: 4, 1453 colorDark: '#000000', 1454 colorLight: '#ffffff', 1455 correctLevel: QRErrorCorrectLevel.H 1456 } 1457 1458 if (typeof vOption === 'string') { 1459 vOption = { 1460 text: vOption 1461 } 1462 } 1463 1464 // Overwrites options 1465 if (vOption) { 1466 for (var i in vOption) { 1467 this._htOption[i] = vOption[i] 1468 } 1469 } 1470 1471 if (typeof el === 'string') { 1472 el = document.getElementById(el) 1473 } 1474 1475 if (this._htOption.useSVG) { 1476 Drawing = svgDrawer 1477 } 1478 1479 this._android = _getAndroid() 1480 this._el = el 1481 this._oQRCode = null 1482 this._oDrawing = new Drawing(this._el, this._htOption) 1483 1484 if (this._htOption.text) { 1485 this.makeCode(this._htOption.text) 1486 } 1487 } 1488 1489 /** 1490 * Make the QRCode 1491 * 1492 * @param {String} sText link data 1493 */ 1494 QRCode.prototype.makeCode = function (sText) { 1495 this._oQRCode = new QRCodeModel( 1496 _getTypeNumber(sText, this._htOption.correctLevel), 1497 this._htOption.correctLevel 1498 ) 1499 this._oQRCode.addData(sText) 1500 this._oQRCode.make() 1501 this._el.title = sText 1502 this._oDrawing.draw(this._oQRCode) 1503 this.makeImage() 1504 } 1505 1506 /** 1507 * Make the Image from Canvas element 1508 * - It occurs automatically 1509 * - Android below 3 doesn't support Data-URI spec. 1510 * 1511 * @private 1512 */ 1513 QRCode.prototype.makeImage = function () { 1514 if ( 1515 typeof this._oDrawing.makeImage === 'function' && 1516 (!this._android || this._android >= 3) 1517 ) { 1518 this._oDrawing.makeImage() 1519 } 1520 } 1521 1522 /** 1523 * Clear the QRCode 1524 */ 1525 QRCode.prototype.clear = function () { 1526 this._oDrawing.clear() 1527 } 1528 1529 /** 1530 * @name QRCode.CorrectLevel 1531 */ 1532 QRCode.CorrectLevel = QRErrorCorrectLevel 1533 })()