qrcode.mjs (51921B)
1 //--------------------------------------------------------------------- 2 // 3 // QR Code Generator for JavaScript 4 // 5 // Copyright (c) 2009 Kazuhiko Arase 6 // 7 // URL: http://www.d-project.com/ 8 // 9 // Licensed under the MIT license: 10 // http://www.opensource.org/licenses/mit-license.php 11 // 12 // The word 'QR Code' is registered trademark of 13 // DENSO WAVE INCORPORATED 14 // http://www.denso-wave.com/qrcode/faqpatent-e.html 15 // 16 //--------------------------------------------------------------------- 17 18 //--------------------------------------------------------------------- 19 // qrcode 20 //--------------------------------------------------------------------- 21 22 /** 23 * qrcode 24 * @param typeNumber 1 to 40 25 * @param errorCorrectionLevel 'L','M','Q','H' 26 */ 27 export const qrcode = function(typeNumber, errorCorrectionLevel) { 28 29 const PAD0 = 0xEC; 30 const PAD1 = 0x11; 31 32 let _typeNumber = typeNumber; 33 const _errorCorrectionLevel = QRErrorCorrectionLevel[errorCorrectionLevel]; 34 let _modules = null; 35 let _moduleCount = 0; 36 let _dataCache = null; 37 const _dataList = []; 38 39 const _this = {}; 40 41 const makeImpl = function(test, maskPattern) { 42 43 _moduleCount = _typeNumber * 4 + 17; 44 _modules = function(moduleCount) { 45 const modules = new Array(moduleCount); 46 for (let row = 0; row < moduleCount; row += 1) { 47 modules[row] = new Array(moduleCount); 48 for (let col = 0; col < moduleCount; col += 1) { 49 modules[row][col] = null; 50 } 51 } 52 return modules; 53 }(_moduleCount); 54 55 setupPositionProbePattern(0, 0); 56 setupPositionProbePattern(_moduleCount - 7, 0); 57 setupPositionProbePattern(0, _moduleCount - 7); 58 setupPositionAdjustPattern(); 59 setupTimingPattern(); 60 setupTypeInfo(test, maskPattern); 61 62 if (_typeNumber >= 7) { 63 setupTypeNumber(test); 64 } 65 66 if (_dataCache == null) { 67 _dataCache = createData(_typeNumber, _errorCorrectionLevel, _dataList); 68 } 69 70 mapData(_dataCache, maskPattern); 71 }; 72 73 const setupPositionProbePattern = function(row, col) { 74 75 for (let r = -1; r <= 7; r += 1) { 76 77 if (row + r <= -1 || _moduleCount <= row + r) continue; 78 79 for (let c = -1; c <= 7; c += 1) { 80 81 if (col + c <= -1 || _moduleCount <= col + c) continue; 82 83 if ( (0 <= r && r <= 6 && (c == 0 || c == 6) ) 84 || (0 <= c && c <= 6 && (r == 0 || r == 6) ) 85 || (2 <= r && r <= 4 && 2 <= c && c <= 4) ) { 86 _modules[row + r][col + c] = true; 87 } else { 88 _modules[row + r][col + c] = false; 89 } 90 } 91 } 92 }; 93 94 const getBestMaskPattern = function() { 95 96 let minLostPoint = 0; 97 let pattern = 0; 98 99 for (let i = 0; i < 8; i += 1) { 100 101 makeImpl(true, i); 102 103 const lostPoint = QRUtil.getLostPoint(_this); 104 105 if (i == 0 || minLostPoint > lostPoint) { 106 minLostPoint = lostPoint; 107 pattern = i; 108 } 109 } 110 111 return pattern; 112 }; 113 114 const setupTimingPattern = function() { 115 116 for (let r = 8; r < _moduleCount - 8; r += 1) { 117 if (_modules[r][6] != null) { 118 continue; 119 } 120 _modules[r][6] = (r % 2 == 0); 121 } 122 123 for (let c = 8; c < _moduleCount - 8; c += 1) { 124 if (_modules[6][c] != null) { 125 continue; 126 } 127 _modules[6][c] = (c % 2 == 0); 128 } 129 }; 130 131 const setupPositionAdjustPattern = function() { 132 133 const pos = QRUtil.getPatternPosition(_typeNumber); 134 135 for (let i = 0; i < pos.length; i += 1) { 136 137 for (let j = 0; j < pos.length; j += 1) { 138 139 const row = pos[i]; 140 const col = pos[j]; 141 142 if (_modules[row][col] != null) { 143 continue; 144 } 145 146 for (let r = -2; r <= 2; r += 1) { 147 148 for (let c = -2; c <= 2; c += 1) { 149 150 if (r == -2 || r == 2 || c == -2 || c == 2 151 || (r == 0 && c == 0) ) { 152 _modules[row + r][col + c] = true; 153 } else { 154 _modules[row + r][col + c] = false; 155 } 156 } 157 } 158 } 159 } 160 }; 161 162 const setupTypeNumber = function(test) { 163 164 const bits = QRUtil.getBCHTypeNumber(_typeNumber); 165 166 for (let i = 0; i < 18; i += 1) { 167 const mod = (!test && ( (bits >> i) & 1) == 1); 168 _modules[Math.floor(i / 3)][i % 3 + _moduleCount - 8 - 3] = mod; 169 } 170 171 for (let i = 0; i < 18; i += 1) { 172 const mod = (!test && ( (bits >> i) & 1) == 1); 173 _modules[i % 3 + _moduleCount - 8 - 3][Math.floor(i / 3)] = mod; 174 } 175 }; 176 177 const setupTypeInfo = function(test, maskPattern) { 178 179 const data = (_errorCorrectionLevel << 3) | maskPattern; 180 const bits = QRUtil.getBCHTypeInfo(data); 181 182 // vertical 183 for (let i = 0; i < 15; i += 1) { 184 185 const mod = (!test && ( (bits >> i) & 1) == 1); 186 187 if (i < 6) { 188 _modules[i][8] = mod; 189 } else if (i < 8) { 190 _modules[i + 1][8] = mod; 191 } else { 192 _modules[_moduleCount - 15 + i][8] = mod; 193 } 194 } 195 196 // horizontal 197 for (let i = 0; i < 15; i += 1) { 198 199 const mod = (!test && ( (bits >> i) & 1) == 1); 200 201 if (i < 8) { 202 _modules[8][_moduleCount - i - 1] = mod; 203 } else if (i < 9) { 204 _modules[8][15 - i - 1 + 1] = mod; 205 } else { 206 _modules[8][15 - i - 1] = mod; 207 } 208 } 209 210 // fixed module 211 _modules[_moduleCount - 8][8] = (!test); 212 }; 213 214 const mapData = function(data, maskPattern) { 215 216 let inc = -1; 217 let row = _moduleCount - 1; 218 let bitIndex = 7; 219 let byteIndex = 0; 220 const maskFunc = QRUtil.getMaskFunction(maskPattern); 221 222 for (let col = _moduleCount - 1; col > 0; col -= 2) { 223 224 if (col == 6) col -= 1; 225 226 while (true) { 227 228 for (let c = 0; c < 2; c += 1) { 229 230 if (_modules[row][col - c] == null) { 231 232 let dark = false; 233 234 if (byteIndex < data.length) { 235 dark = ( ( (data[byteIndex] >>> bitIndex) & 1) == 1); 236 } 237 238 const mask = maskFunc(row, col - c); 239 240 if (mask) { 241 dark = !dark; 242 } 243 244 _modules[row][col - c] = dark; 245 bitIndex -= 1; 246 247 if (bitIndex == -1) { 248 byteIndex += 1; 249 bitIndex = 7; 250 } 251 } 252 } 253 254 row += inc; 255 256 if (row < 0 || _moduleCount <= row) { 257 row -= inc; 258 inc = -inc; 259 break; 260 } 261 } 262 } 263 }; 264 265 const createBytes = function(buffer, rsBlocks) { 266 267 let offset = 0; 268 269 let maxDcCount = 0; 270 let maxEcCount = 0; 271 272 const dcdata = new Array(rsBlocks.length); 273 const ecdata = new Array(rsBlocks.length); 274 275 for (let r = 0; r < rsBlocks.length; r += 1) { 276 277 const dcCount = rsBlocks[r].dataCount; 278 const ecCount = rsBlocks[r].totalCount - dcCount; 279 280 maxDcCount = Math.max(maxDcCount, dcCount); 281 maxEcCount = Math.max(maxEcCount, ecCount); 282 283 dcdata[r] = new Array(dcCount); 284 285 for (let i = 0; i < dcdata[r].length; i += 1) { 286 dcdata[r][i] = 0xff & buffer.getBuffer()[i + offset]; 287 } 288 offset += dcCount; 289 290 const rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount); 291 const rawPoly = qrPolynomial(dcdata[r], rsPoly.getLength() - 1); 292 293 const modPoly = rawPoly.mod(rsPoly); 294 ecdata[r] = new Array(rsPoly.getLength() - 1); 295 for (let i = 0; i < ecdata[r].length; i += 1) { 296 const modIndex = i + modPoly.getLength() - ecdata[r].length; 297 ecdata[r][i] = (modIndex >= 0)? modPoly.getAt(modIndex) : 0; 298 } 299 } 300 301 let totalCodeCount = 0; 302 for (let i = 0; i < rsBlocks.length; i += 1) { 303 totalCodeCount += rsBlocks[i].totalCount; 304 } 305 306 const data = new Array(totalCodeCount); 307 let index = 0; 308 309 for (let i = 0; i < maxDcCount; i += 1) { 310 for (let r = 0; r < rsBlocks.length; r += 1) { 311 if (i < dcdata[r].length) { 312 data[index] = dcdata[r][i]; 313 index += 1; 314 } 315 } 316 } 317 318 for (let i = 0; i < maxEcCount; i += 1) { 319 for (let r = 0; r < rsBlocks.length; r += 1) { 320 if (i < ecdata[r].length) { 321 data[index] = ecdata[r][i]; 322 index += 1; 323 } 324 } 325 } 326 327 return data; 328 }; 329 330 const createData = function(typeNumber, errorCorrectionLevel, dataList) { 331 332 const rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectionLevel); 333 334 const buffer = qrBitBuffer(); 335 336 for (let i = 0; i < dataList.length; i += 1) { 337 const data = dataList[i]; 338 buffer.put(data.getMode(), 4); 339 buffer.put(data.getLength(), QRUtil.getLengthInBits(data.getMode(), typeNumber) ); 340 data.write(buffer); 341 } 342 343 // calc num max data. 344 let totalDataCount = 0; 345 for (let i = 0; i < rsBlocks.length; i += 1) { 346 totalDataCount += rsBlocks[i].dataCount; 347 } 348 349 if (buffer.getLengthInBits() > totalDataCount * 8) { 350 throw 'code length overflow. (' 351 + buffer.getLengthInBits() 352 + '>' 353 + totalDataCount * 8 354 + ')'; 355 } 356 357 // end code 358 if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) { 359 buffer.put(0, 4); 360 } 361 362 // padding 363 while (buffer.getLengthInBits() % 8 != 0) { 364 buffer.putBit(false); 365 } 366 367 // padding 368 while (true) { 369 370 if (buffer.getLengthInBits() >= totalDataCount * 8) { 371 break; 372 } 373 buffer.put(PAD0, 8); 374 375 if (buffer.getLengthInBits() >= totalDataCount * 8) { 376 break; 377 } 378 buffer.put(PAD1, 8); 379 } 380 381 return createBytes(buffer, rsBlocks); 382 }; 383 384 _this.addData = function(data, mode) { 385 386 mode = mode || 'Byte'; 387 388 let newData = null; 389 390 switch(mode) { 391 case 'Numeric' : 392 newData = qrNumber(data); 393 break; 394 case 'Alphanumeric' : 395 newData = qrAlphaNum(data); 396 break; 397 case 'Byte' : 398 newData = qr8BitByte(data); 399 break; 400 case 'Kanji' : 401 newData = qrKanji(data); 402 break; 403 default : 404 throw 'mode:' + mode; 405 } 406 407 _dataList.push(newData); 408 _dataCache = null; 409 }; 410 411 _this.isDark = function(row, col) { 412 if (row < 0 || _moduleCount <= row || col < 0 || _moduleCount <= col) { 413 throw row + ',' + col; 414 } 415 return _modules[row][col]; 416 }; 417 418 _this.getModuleCount = function() { 419 return _moduleCount; 420 }; 421 422 _this.make = function() { 423 if (_typeNumber < 1) { 424 let typeNumber = 1; 425 426 for (; typeNumber < 40; typeNumber++) { 427 const rsBlocks = QRRSBlock.getRSBlocks(typeNumber, _errorCorrectionLevel); 428 const buffer = qrBitBuffer(); 429 430 for (let i = 0; i < _dataList.length; i++) { 431 const data = _dataList[i]; 432 buffer.put(data.getMode(), 4); 433 buffer.put(data.getLength(), QRUtil.getLengthInBits(data.getMode(), typeNumber) ); 434 data.write(buffer); 435 } 436 437 let totalDataCount = 0; 438 for (let i = 0; i < rsBlocks.length; i++) { 439 totalDataCount += rsBlocks[i].dataCount; 440 } 441 442 if (buffer.getLengthInBits() <= totalDataCount * 8) { 443 break; 444 } 445 } 446 447 _typeNumber = typeNumber; 448 } 449 450 makeImpl(false, getBestMaskPattern() ); 451 }; 452 453 _this.createTableTag = function(cellSize, margin) { 454 455 cellSize = cellSize || 2; 456 margin = (typeof margin == 'undefined')? cellSize * 4 : margin; 457 458 let qrHtml = ''; 459 460 qrHtml += '<table style="'; 461 qrHtml += ' border-width: 0px; border-style: none;'; 462 qrHtml += ' border-collapse: collapse;'; 463 qrHtml += ' padding: 0px; margin: ' + margin + 'px;'; 464 qrHtml += '">'; 465 qrHtml += '<tbody>'; 466 467 for (let r = 0; r < _this.getModuleCount(); r += 1) { 468 469 qrHtml += '<tr>'; 470 471 for (let c = 0; c < _this.getModuleCount(); c += 1) { 472 qrHtml += '<td style="'; 473 qrHtml += ' border-width: 0px; border-style: none;'; 474 qrHtml += ' border-collapse: collapse;'; 475 qrHtml += ' padding: 0px; margin: 0px;'; 476 qrHtml += ' width: ' + cellSize + 'px;'; 477 qrHtml += ' height: ' + cellSize + 'px;'; 478 qrHtml += ' background-color: '; 479 qrHtml += _this.isDark(r, c)? '#000000' : '#ffffff'; 480 qrHtml += ';'; 481 qrHtml += '"/>'; 482 } 483 484 qrHtml += '</tr>'; 485 } 486 487 qrHtml += '</tbody>'; 488 qrHtml += '</table>'; 489 490 return qrHtml; 491 }; 492 493 _this.createSvgTag = function(cellSize, margin, alt, title) { 494 495 let opts = {}; 496 if (typeof arguments[0] == 'object') { 497 // Called by options. 498 opts = arguments[0]; 499 // overwrite cellSize and margin. 500 cellSize = opts.cellSize; 501 margin = opts.margin; 502 alt = opts.alt; 503 title = opts.title; 504 } 505 506 cellSize = cellSize || 2; 507 margin = (typeof margin == 'undefined')? cellSize * 4 : margin; 508 509 // Compose alt property surrogate 510 alt = (typeof alt === 'string') ? {text: alt} : alt || {}; 511 alt.text = alt.text || null; 512 alt.id = (alt.text) ? alt.id || 'qrcode-description' : null; 513 514 // Compose title property surrogate 515 title = (typeof title === 'string') ? {text: title} : title || {}; 516 title.text = title.text || null; 517 title.id = (title.text) ? title.id || 'qrcode-title' : null; 518 519 const size = _this.getModuleCount() * cellSize + margin * 2; 520 let c, mc, r, mr, qrSvg='', rect; 521 522 rect = 'l' + cellSize + ',0 0,' + cellSize + 523 ' -' + cellSize + ',0 0,-' + cellSize + 'z '; 524 525 qrSvg += '<svg version="1.1" xmlns="http://www.w3.org/2000/svg"'; 526 qrSvg += !opts.scalable ? ' width="' + size + 'px" height="' + size + 'px"' : ''; 527 qrSvg += ' viewBox="0 0 ' + size + ' ' + size + '" '; 528 qrSvg += ' preserveAspectRatio="xMinYMin meet"'; 529 qrSvg += (title.text || alt.text) ? ' role="img" aria-labelledby="' + 530 escapeXml([title.id, alt.id].join(' ').trim() ) + '"' : ''; 531 qrSvg += '>'; 532 qrSvg += (title.text) ? '<title id="' + escapeXml(title.id) + '">' + 533 escapeXml(title.text) + '</title>' : ''; 534 qrSvg += (alt.text) ? '<description id="' + escapeXml(alt.id) + '">' + 535 escapeXml(alt.text) + '</description>' : ''; 536 qrSvg += '<rect width="100%" height="100%" fill="white" cx="0" cy="0"/>'; 537 qrSvg += '<path d="'; 538 539 for (r = 0; r < _this.getModuleCount(); r += 1) { 540 mr = r * cellSize + margin; 541 for (c = 0; c < _this.getModuleCount(); c += 1) { 542 if (_this.isDark(r, c) ) { 543 mc = c*cellSize+margin; 544 qrSvg += 'M' + mc + ',' + mr + rect; 545 } 546 } 547 } 548 549 qrSvg += '" stroke="transparent" fill="black"/>'; 550 qrSvg += '</svg>'; 551 552 return qrSvg; 553 }; 554 555 _this.createDataURL = function(cellSize, margin) { 556 557 cellSize = cellSize || 2; 558 margin = (typeof margin == 'undefined')? cellSize * 4 : margin; 559 560 const size = _this.getModuleCount() * cellSize + margin * 2; 561 const min = margin; 562 const max = size - margin; 563 564 return createDataURL(size, size, function(x, y) { 565 if (min <= x && x < max && min <= y && y < max) { 566 const c = Math.floor( (x - min) / cellSize); 567 const r = Math.floor( (y - min) / cellSize); 568 return _this.isDark(r, c)? 0 : 1; 569 } else { 570 return 1; 571 } 572 } ); 573 }; 574 575 _this.createImgTag = function(cellSize, margin, alt) { 576 577 cellSize = cellSize || 2; 578 margin = (typeof margin == 'undefined')? cellSize * 4 : margin; 579 580 const size = _this.getModuleCount() * cellSize + margin * 2; 581 582 let img = ''; 583 img += '<img'; 584 img += '\u0020src="'; 585 img += _this.createDataURL(cellSize, margin); 586 img += '"'; 587 img += '\u0020width="'; 588 img += size; 589 img += '"'; 590 img += '\u0020height="'; 591 img += size; 592 img += '"'; 593 if (alt) { 594 img += '\u0020alt="'; 595 img += escapeXml(alt); 596 img += '"'; 597 } 598 img += '/>'; 599 600 return img; 601 }; 602 603 const escapeXml = function(s) { 604 let escaped = ''; 605 for (let i = 0; i < s.length; i += 1) { 606 const c = s.charAt(i); 607 switch(c) { 608 case '<': escaped += '<'; break; 609 case '>': escaped += '>'; break; 610 case '&': escaped += '&'; break; 611 case '"': escaped += '"'; break; 612 default : escaped += c; break; 613 } 614 } 615 return escaped; 616 }; 617 618 const _createHalfASCII = function(margin) { 619 const cellSize = 1; 620 margin = (typeof margin == 'undefined')? cellSize * 2 : margin; 621 622 const size = _this.getModuleCount() * cellSize + margin * 2; 623 const min = margin; 624 const max = size - margin; 625 626 let y, x, r1, r2, p; 627 628 const blocks = { 629 '██': '█', 630 '█ ': '▀', 631 ' █': '▄', 632 ' ': ' ' 633 }; 634 635 const blocksLastLineNoMargin = { 636 '██': '▀', 637 '█ ': '▀', 638 ' █': ' ', 639 ' ': ' ' 640 }; 641 642 let ascii = ''; 643 for (y = 0; y < size; y += 2) { 644 r1 = Math.floor((y - min) / cellSize); 645 r2 = Math.floor((y + 1 - min) / cellSize); 646 for (x = 0; x < size; x += 1) { 647 p = '█'; 648 649 if (min <= x && x < max && min <= y && y < max && _this.isDark(r1, Math.floor((x - min) / cellSize))) { 650 p = ' '; 651 } 652 653 if (min <= x && x < max && min <= y+1 && y+1 < max && _this.isDark(r2, Math.floor((x - min) / cellSize))) { 654 p += ' '; 655 } 656 else { 657 p += '█'; 658 } 659 660 // Output 2 characters per pixel, to create full square. 1 character per pixels gives only half width of square. 661 ascii += (margin < 1 && y+1 >= max) ? blocksLastLineNoMargin[p] : blocks[p]; 662 } 663 664 ascii += '\n'; 665 } 666 667 if (size % 2 && margin > 0) { 668 return ascii.substring(0, ascii.length - size - 1) + Array(size+1).join('▀'); 669 } 670 671 return ascii.substring(0, ascii.length-1); 672 }; 673 674 _this.createASCII = function(cellSize, margin) { 675 cellSize = cellSize || 1; 676 677 if (cellSize < 2) { 678 return _createHalfASCII(margin); 679 } 680 681 cellSize -= 1; 682 margin = (typeof margin == 'undefined')? cellSize * 2 : margin; 683 684 const size = _this.getModuleCount() * cellSize + margin * 2; 685 const min = margin; 686 const max = size - margin; 687 688 let y, x, r, p; 689 690 const white = Array(cellSize+1).join('██'); 691 const black = Array(cellSize+1).join(' '); 692 693 let ascii = ''; 694 let line = ''; 695 for (y = 0; y < size; y += 1) { 696 r = Math.floor( (y - min) / cellSize); 697 line = ''; 698 for (x = 0; x < size; x += 1) { 699 p = 1; 700 701 if (min <= x && x < max && min <= y && y < max && _this.isDark(r, Math.floor((x - min) / cellSize))) { 702 p = 0; 703 } 704 705 // Output 2 characters per pixel, to create full square. 1 character per pixels gives only half width of square. 706 line += p ? white : black; 707 } 708 709 for (r = 0; r < cellSize; r += 1) { 710 ascii += line + '\n'; 711 } 712 } 713 714 return ascii.substring(0, ascii.length-1); 715 }; 716 717 _this.renderTo2dContext = function(context, cellSize) { 718 cellSize = cellSize || 2; 719 const length = _this.getModuleCount(); 720 for (let row = 0; row < length; row++) { 721 for (let col = 0; col < length; col++) { 722 context.fillStyle = _this.isDark(row, col) ? 'black' : 'white'; 723 context.fillRect(col * cellSize, row * cellSize, cellSize, cellSize); 724 } 725 } 726 } 727 728 return _this; 729 }; 730 731 //--------------------------------------------------------------------- 732 // qrcode.stringToBytes 733 //--------------------------------------------------------------------- 734 735 qrcode.stringToBytes = function(s) { 736 const bytes = []; 737 for (let i = 0; i < s.length; i += 1) { 738 const c = s.charCodeAt(i); 739 bytes.push(c & 0xff); 740 } 741 return bytes; 742 }; 743 744 //--------------------------------------------------------------------- 745 // qrcode.createStringToBytes 746 //--------------------------------------------------------------------- 747 748 /** 749 * @param unicodeData base64 string of byte array. 750 * [16bit Unicode],[16bit Bytes], ... 751 * @param numChars 752 */ 753 qrcode.createStringToBytes = function(unicodeData, numChars) { 754 755 // create conversion map. 756 757 const unicodeMap = function() { 758 759 const bin = base64DecodeInputStream(unicodeData); 760 const read = function() { 761 const b = bin.read(); 762 if (b == -1) throw 'eof'; 763 return b; 764 }; 765 766 let count = 0; 767 const unicodeMap = {}; 768 while (true) { 769 const b0 = bin.read(); 770 if (b0 == -1) break; 771 const b1 = read(); 772 const b2 = read(); 773 const b3 = read(); 774 const k = String.fromCharCode( (b0 << 8) | b1); 775 const v = (b2 << 8) | b3; 776 unicodeMap[k] = v; 777 count += 1; 778 } 779 if (count != numChars) { 780 throw count + ' != ' + numChars; 781 } 782 783 return unicodeMap; 784 }(); 785 786 const unknownChar = '?'.charCodeAt(0); 787 788 return function(s) { 789 const bytes = []; 790 for (let i = 0; i < s.length; i += 1) { 791 const c = s.charCodeAt(i); 792 if (c < 128) { 793 bytes.push(c); 794 } else { 795 const b = unicodeMap[s.charAt(i)]; 796 if (typeof b == 'number') { 797 if ( (b & 0xff) == b) { 798 // 1byte 799 bytes.push(b); 800 } else { 801 // 2bytes 802 bytes.push(b >>> 8); 803 bytes.push(b & 0xff); 804 } 805 } else { 806 bytes.push(unknownChar); 807 } 808 } 809 } 810 return bytes; 811 }; 812 }; 813 814 //--------------------------------------------------------------------- 815 // QRMode 816 //--------------------------------------------------------------------- 817 818 const QRMode = { 819 MODE_NUMBER : 1 << 0, 820 MODE_ALPHA_NUM : 1 << 1, 821 MODE_8BIT_BYTE : 1 << 2, 822 MODE_KANJI : 1 << 3 823 }; 824 825 //--------------------------------------------------------------------- 826 // QRErrorCorrectionLevel 827 //--------------------------------------------------------------------- 828 829 export const QRErrorCorrectionLevel = { 830 L : 1, 831 M : 0, 832 Q : 3, 833 H : 2 834 }; 835 836 //--------------------------------------------------------------------- 837 // QRMaskPattern 838 //--------------------------------------------------------------------- 839 840 const QRMaskPattern = { 841 PATTERN000 : 0, 842 PATTERN001 : 1, 843 PATTERN010 : 2, 844 PATTERN011 : 3, 845 PATTERN100 : 4, 846 PATTERN101 : 5, 847 PATTERN110 : 6, 848 PATTERN111 : 7 849 }; 850 851 //--------------------------------------------------------------------- 852 // QRUtil 853 //--------------------------------------------------------------------- 854 855 const QRUtil = function() { 856 857 const PATTERN_POSITION_TABLE = [ 858 [], 859 [6, 18], 860 [6, 22], 861 [6, 26], 862 [6, 30], 863 [6, 34], 864 [6, 22, 38], 865 [6, 24, 42], 866 [6, 26, 46], 867 [6, 28, 50], 868 [6, 30, 54], 869 [6, 32, 58], 870 [6, 34, 62], 871 [6, 26, 46, 66], 872 [6, 26, 48, 70], 873 [6, 26, 50, 74], 874 [6, 30, 54, 78], 875 [6, 30, 56, 82], 876 [6, 30, 58, 86], 877 [6, 34, 62, 90], 878 [6, 28, 50, 72, 94], 879 [6, 26, 50, 74, 98], 880 [6, 30, 54, 78, 102], 881 [6, 28, 54, 80, 106], 882 [6, 32, 58, 84, 110], 883 [6, 30, 58, 86, 114], 884 [6, 34, 62, 90, 118], 885 [6, 26, 50, 74, 98, 122], 886 [6, 30, 54, 78, 102, 126], 887 [6, 26, 52, 78, 104, 130], 888 [6, 30, 56, 82, 108, 134], 889 [6, 34, 60, 86, 112, 138], 890 [6, 30, 58, 86, 114, 142], 891 [6, 34, 62, 90, 118, 146], 892 [6, 30, 54, 78, 102, 126, 150], 893 [6, 24, 50, 76, 102, 128, 154], 894 [6, 28, 54, 80, 106, 132, 158], 895 [6, 32, 58, 84, 110, 136, 162], 896 [6, 26, 54, 82, 110, 138, 166], 897 [6, 30, 58, 86, 114, 142, 170] 898 ]; 899 const G15 = (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0); 900 const G18 = (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0); 901 const G15_MASK = (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1); 902 903 const _this = {}; 904 905 const getBCHDigit = function(data) { 906 let digit = 0; 907 while (data != 0) { 908 digit += 1; 909 data >>>= 1; 910 } 911 return digit; 912 }; 913 914 _this.getBCHTypeInfo = function(data) { 915 let d = data << 10; 916 while (getBCHDigit(d) - getBCHDigit(G15) >= 0) { 917 d ^= (G15 << (getBCHDigit(d) - getBCHDigit(G15) ) ); 918 } 919 return ( (data << 10) | d) ^ G15_MASK; 920 }; 921 922 _this.getBCHTypeNumber = function(data) { 923 let d = data << 12; 924 while (getBCHDigit(d) - getBCHDigit(G18) >= 0) { 925 d ^= (G18 << (getBCHDigit(d) - getBCHDigit(G18) ) ); 926 } 927 return (data << 12) | d; 928 }; 929 930 _this.getPatternPosition = function(typeNumber) { 931 return PATTERN_POSITION_TABLE[typeNumber - 1]; 932 }; 933 934 _this.getMaskFunction = function(maskPattern) { 935 936 switch (maskPattern) { 937 938 case QRMaskPattern.PATTERN000 : 939 return function(i, j) { return (i + j) % 2 == 0; }; 940 case QRMaskPattern.PATTERN001 : 941 return function(i, j) { return i % 2 == 0; }; 942 case QRMaskPattern.PATTERN010 : 943 return function(i, j) { return j % 3 == 0; }; 944 case QRMaskPattern.PATTERN011 : 945 return function(i, j) { return (i + j) % 3 == 0; }; 946 case QRMaskPattern.PATTERN100 : 947 return function(i, j) { return (Math.floor(i / 2) + Math.floor(j / 3) ) % 2 == 0; }; 948 case QRMaskPattern.PATTERN101 : 949 return function(i, j) { return (i * j) % 2 + (i * j) % 3 == 0; }; 950 case QRMaskPattern.PATTERN110 : 951 return function(i, j) { return ( (i * j) % 2 + (i * j) % 3) % 2 == 0; }; 952 case QRMaskPattern.PATTERN111 : 953 return function(i, j) { return ( (i * j) % 3 + (i + j) % 2) % 2 == 0; }; 954 955 default : 956 throw 'bad maskPattern:' + maskPattern; 957 } 958 }; 959 960 _this.getErrorCorrectPolynomial = function(errorCorrectLength) { 961 let a = qrPolynomial([1], 0); 962 for (let i = 0; i < errorCorrectLength; i += 1) { 963 a = a.multiply(qrPolynomial([1, QRMath.gexp(i)], 0) ); 964 } 965 return a; 966 }; 967 968 _this.getLengthInBits = function(mode, type) { 969 970 if (1 <= type && type < 10) { 971 972 // 1 - 9 973 974 switch(mode) { 975 case QRMode.MODE_NUMBER : return 10; 976 case QRMode.MODE_ALPHA_NUM : return 9; 977 case QRMode.MODE_8BIT_BYTE : return 8; 978 case QRMode.MODE_KANJI : return 8; 979 default : 980 throw 'mode:' + mode; 981 } 982 983 } else if (type < 27) { 984 985 // 10 - 26 986 987 switch(mode) { 988 case QRMode.MODE_NUMBER : return 12; 989 case QRMode.MODE_ALPHA_NUM : return 11; 990 case QRMode.MODE_8BIT_BYTE : return 16; 991 case QRMode.MODE_KANJI : return 10; 992 default : 993 throw 'mode:' + mode; 994 } 995 996 } else if (type < 41) { 997 998 // 27 - 40 999 1000 switch(mode) { 1001 case QRMode.MODE_NUMBER : return 14; 1002 case QRMode.MODE_ALPHA_NUM : return 13; 1003 case QRMode.MODE_8BIT_BYTE : return 16; 1004 case QRMode.MODE_KANJI : return 12; 1005 default : 1006 throw 'mode:' + mode; 1007 } 1008 1009 } else { 1010 throw 'type:' + type; 1011 } 1012 }; 1013 1014 _this.getLostPoint = function(qrcode) { 1015 1016 const moduleCount = qrcode.getModuleCount(); 1017 1018 let lostPoint = 0; 1019 1020 // LEVEL1 1021 1022 for (let row = 0; row < moduleCount; row += 1) { 1023 for (let col = 0; col < moduleCount; col += 1) { 1024 1025 let sameCount = 0; 1026 const dark = qrcode.isDark(row, col); 1027 1028 for (let r = -1; r <= 1; r += 1) { 1029 1030 if (row + r < 0 || moduleCount <= row + r) { 1031 continue; 1032 } 1033 1034 for (let c = -1; c <= 1; c += 1) { 1035 1036 if (col + c < 0 || moduleCount <= col + c) { 1037 continue; 1038 } 1039 1040 if (r == 0 && c == 0) { 1041 continue; 1042 } 1043 1044 if (dark == qrcode.isDark(row + r, col + c) ) { 1045 sameCount += 1; 1046 } 1047 } 1048 } 1049 1050 if (sameCount > 5) { 1051 lostPoint += (3 + sameCount - 5); 1052 } 1053 } 1054 }; 1055 1056 // LEVEL2 1057 1058 for (let row = 0; row < moduleCount - 1; row += 1) { 1059 for (let col = 0; col < moduleCount - 1; col += 1) { 1060 let count = 0; 1061 if (qrcode.isDark(row, col) ) count += 1; 1062 if (qrcode.isDark(row + 1, col) ) count += 1; 1063 if (qrcode.isDark(row, col + 1) ) count += 1; 1064 if (qrcode.isDark(row + 1, col + 1) ) count += 1; 1065 if (count == 0 || count == 4) { 1066 lostPoint += 3; 1067 } 1068 } 1069 } 1070 1071 // LEVEL3 1072 1073 for (let row = 0; row < moduleCount; row += 1) { 1074 for (let col = 0; col < moduleCount - 6; col += 1) { 1075 if (qrcode.isDark(row, col) 1076 && !qrcode.isDark(row, col + 1) 1077 && qrcode.isDark(row, col + 2) 1078 && qrcode.isDark(row, col + 3) 1079 && qrcode.isDark(row, col + 4) 1080 && !qrcode.isDark(row, col + 5) 1081 && qrcode.isDark(row, col + 6) ) { 1082 lostPoint += 40; 1083 } 1084 } 1085 } 1086 1087 for (let col = 0; col < moduleCount; col += 1) { 1088 for (let row = 0; row < moduleCount - 6; row += 1) { 1089 if (qrcode.isDark(row, col) 1090 && !qrcode.isDark(row + 1, col) 1091 && qrcode.isDark(row + 2, col) 1092 && qrcode.isDark(row + 3, col) 1093 && qrcode.isDark(row + 4, col) 1094 && !qrcode.isDark(row + 5, col) 1095 && qrcode.isDark(row + 6, col) ) { 1096 lostPoint += 40; 1097 } 1098 } 1099 } 1100 1101 // LEVEL4 1102 1103 let darkCount = 0; 1104 1105 for (let col = 0; col < moduleCount; col += 1) { 1106 for (let row = 0; row < moduleCount; row += 1) { 1107 if (qrcode.isDark(row, col) ) { 1108 darkCount += 1; 1109 } 1110 } 1111 } 1112 1113 const ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5; 1114 lostPoint += ratio * 10; 1115 1116 return lostPoint; 1117 }; 1118 1119 return _this; 1120 }(); 1121 1122 //--------------------------------------------------------------------- 1123 // QRMath 1124 //--------------------------------------------------------------------- 1125 1126 const QRMath = function() { 1127 1128 const EXP_TABLE = new Array(256); 1129 const LOG_TABLE = new Array(256); 1130 1131 // initialize tables 1132 for (let i = 0; i < 8; i += 1) { 1133 EXP_TABLE[i] = 1 << i; 1134 } 1135 for (let i = 8; i < 256; i += 1) { 1136 EXP_TABLE[i] = EXP_TABLE[i - 4] 1137 ^ EXP_TABLE[i - 5] 1138 ^ EXP_TABLE[i - 6] 1139 ^ EXP_TABLE[i - 8]; 1140 } 1141 for (let i = 0; i < 255; i += 1) { 1142 LOG_TABLE[EXP_TABLE[i] ] = i; 1143 } 1144 1145 const _this = {}; 1146 1147 _this.glog = function(n) { 1148 1149 if (n < 1) { 1150 throw 'glog(' + n + ')'; 1151 } 1152 1153 return LOG_TABLE[n]; 1154 }; 1155 1156 _this.gexp = function(n) { 1157 1158 while (n < 0) { 1159 n += 255; 1160 } 1161 1162 while (n >= 256) { 1163 n -= 255; 1164 } 1165 1166 return EXP_TABLE[n]; 1167 }; 1168 1169 return _this; 1170 }(); 1171 1172 //--------------------------------------------------------------------- 1173 // qrPolynomial 1174 //--------------------------------------------------------------------- 1175 1176 const qrPolynomial = function(num, shift) { 1177 1178 if (typeof num.length == 'undefined') { 1179 throw num.length + '/' + shift; 1180 } 1181 1182 const _num = function() { 1183 let offset = 0; 1184 while (offset < num.length && num[offset] == 0) { 1185 offset += 1; 1186 } 1187 const _num = new Array(num.length - offset + shift); 1188 for (let i = 0; i < num.length - offset; i += 1) { 1189 _num[i] = num[i + offset]; 1190 } 1191 return _num; 1192 }(); 1193 1194 const _this = {}; 1195 1196 _this.getAt = function(index) { 1197 return _num[index]; 1198 }; 1199 1200 _this.getLength = function() { 1201 return _num.length; 1202 }; 1203 1204 _this.multiply = function(e) { 1205 1206 const num = new Array(_this.getLength() + e.getLength() - 1); 1207 1208 for (let i = 0; i < _this.getLength(); i += 1) { 1209 for (let j = 0; j < e.getLength(); j += 1) { 1210 num[i + j] ^= QRMath.gexp(QRMath.glog(_this.getAt(i) ) + QRMath.glog(e.getAt(j) ) ); 1211 } 1212 } 1213 1214 return qrPolynomial(num, 0); 1215 }; 1216 1217 _this.mod = function(e) { 1218 1219 if (_this.getLength() - e.getLength() < 0) { 1220 return _this; 1221 } 1222 1223 const ratio = QRMath.glog(_this.getAt(0) ) - QRMath.glog(e.getAt(0) ); 1224 1225 const num = new Array(_this.getLength() ); 1226 for (let i = 0; i < _this.getLength(); i += 1) { 1227 num[i] = _this.getAt(i); 1228 } 1229 1230 for (let i = 0; i < e.getLength(); i += 1) { 1231 num[i] ^= QRMath.gexp(QRMath.glog(e.getAt(i) ) + ratio); 1232 } 1233 1234 // recursive call 1235 return qrPolynomial(num, 0).mod(e); 1236 }; 1237 1238 return _this; 1239 }; 1240 1241 //--------------------------------------------------------------------- 1242 // QRRSBlock 1243 //--------------------------------------------------------------------- 1244 1245 export const QRRSBlock = function() { 1246 1247 const RS_BLOCK_TABLE = [ 1248 1249 // L 1250 // M 1251 // Q 1252 // H 1253 1254 // 1 1255 [1, 26, 19], 1256 [1, 26, 16], 1257 [1, 26, 13], 1258 [1, 26, 9], 1259 1260 // 2 1261 [1, 44, 34], 1262 [1, 44, 28], 1263 [1, 44, 22], 1264 [1, 44, 16], 1265 1266 // 3 1267 [1, 70, 55], 1268 [1, 70, 44], 1269 [2, 35, 17], 1270 [2, 35, 13], 1271 1272 // 4 1273 [1, 100, 80], 1274 [2, 50, 32], 1275 [2, 50, 24], 1276 [4, 25, 9], 1277 1278 // 5 1279 [1, 134, 108], 1280 [2, 67, 43], 1281 [2, 33, 15, 2, 34, 16], 1282 [2, 33, 11, 2, 34, 12], 1283 1284 // 6 1285 [2, 86, 68], 1286 [4, 43, 27], 1287 [4, 43, 19], 1288 [4, 43, 15], 1289 1290 // 7 1291 [2, 98, 78], 1292 [4, 49, 31], 1293 [2, 32, 14, 4, 33, 15], 1294 [4, 39, 13, 1, 40, 14], 1295 1296 // 8 1297 [2, 121, 97], 1298 [2, 60, 38, 2, 61, 39], 1299 [4, 40, 18, 2, 41, 19], 1300 [4, 40, 14, 2, 41, 15], 1301 1302 // 9 1303 [2, 146, 116], 1304 [3, 58, 36, 2, 59, 37], 1305 [4, 36, 16, 4, 37, 17], 1306 [4, 36, 12, 4, 37, 13], 1307 1308 // 10 1309 [2, 86, 68, 2, 87, 69], 1310 [4, 69, 43, 1, 70, 44], 1311 [6, 43, 19, 2, 44, 20], 1312 [6, 43, 15, 2, 44, 16], 1313 1314 // 11 1315 [4, 101, 81], 1316 [1, 80, 50, 4, 81, 51], 1317 [4, 50, 22, 4, 51, 23], 1318 [3, 36, 12, 8, 37, 13], 1319 1320 // 12 1321 [2, 116, 92, 2, 117, 93], 1322 [6, 58, 36, 2, 59, 37], 1323 [4, 46, 20, 6, 47, 21], 1324 [7, 42, 14, 4, 43, 15], 1325 1326 // 13 1327 [4, 133, 107], 1328 [8, 59, 37, 1, 60, 38], 1329 [8, 44, 20, 4, 45, 21], 1330 [12, 33, 11, 4, 34, 12], 1331 1332 // 14 1333 [3, 145, 115, 1, 146, 116], 1334 [4, 64, 40, 5, 65, 41], 1335 [11, 36, 16, 5, 37, 17], 1336 [11, 36, 12, 5, 37, 13], 1337 1338 // 15 1339 [5, 109, 87, 1, 110, 88], 1340 [5, 65, 41, 5, 66, 42], 1341 [5, 54, 24, 7, 55, 25], 1342 [11, 36, 12, 7, 37, 13], 1343 1344 // 16 1345 [5, 122, 98, 1, 123, 99], 1346 [7, 73, 45, 3, 74, 46], 1347 [15, 43, 19, 2, 44, 20], 1348 [3, 45, 15, 13, 46, 16], 1349 1350 // 17 1351 [1, 135, 107, 5, 136, 108], 1352 [10, 74, 46, 1, 75, 47], 1353 [1, 50, 22, 15, 51, 23], 1354 [2, 42, 14, 17, 43, 15], 1355 1356 // 18 1357 [5, 150, 120, 1, 151, 121], 1358 [9, 69, 43, 4, 70, 44], 1359 [17, 50, 22, 1, 51, 23], 1360 [2, 42, 14, 19, 43, 15], 1361 1362 // 19 1363 [3, 141, 113, 4, 142, 114], 1364 [3, 70, 44, 11, 71, 45], 1365 [17, 47, 21, 4, 48, 22], 1366 [9, 39, 13, 16, 40, 14], 1367 1368 // 20 1369 [3, 135, 107, 5, 136, 108], 1370 [3, 67, 41, 13, 68, 42], 1371 [15, 54, 24, 5, 55, 25], 1372 [15, 43, 15, 10, 44, 16], 1373 1374 // 21 1375 [4, 144, 116, 4, 145, 117], 1376 [17, 68, 42], 1377 [17, 50, 22, 6, 51, 23], 1378 [19, 46, 16, 6, 47, 17], 1379 1380 // 22 1381 [2, 139, 111, 7, 140, 112], 1382 [17, 74, 46], 1383 [7, 54, 24, 16, 55, 25], 1384 [34, 37, 13], 1385 1386 // 23 1387 [4, 151, 121, 5, 152, 122], 1388 [4, 75, 47, 14, 76, 48], 1389 [11, 54, 24, 14, 55, 25], 1390 [16, 45, 15, 14, 46, 16], 1391 1392 // 24 1393 [6, 147, 117, 4, 148, 118], 1394 [6, 73, 45, 14, 74, 46], 1395 [11, 54, 24, 16, 55, 25], 1396 [30, 46, 16, 2, 47, 17], 1397 1398 // 25 1399 [8, 132, 106, 4, 133, 107], 1400 [8, 75, 47, 13, 76, 48], 1401 [7, 54, 24, 22, 55, 25], 1402 [22, 45, 15, 13, 46, 16], 1403 1404 // 26 1405 [10, 142, 114, 2, 143, 115], 1406 [19, 74, 46, 4, 75, 47], 1407 [28, 50, 22, 6, 51, 23], 1408 [33, 46, 16, 4, 47, 17], 1409 1410 // 27 1411 [8, 152, 122, 4, 153, 123], 1412 [22, 73, 45, 3, 74, 46], 1413 [8, 53, 23, 26, 54, 24], 1414 [12, 45, 15, 28, 46, 16], 1415 1416 // 28 1417 [3, 147, 117, 10, 148, 118], 1418 [3, 73, 45, 23, 74, 46], 1419 [4, 54, 24, 31, 55, 25], 1420 [11, 45, 15, 31, 46, 16], 1421 1422 // 29 1423 [7, 146, 116, 7, 147, 117], 1424 [21, 73, 45, 7, 74, 46], 1425 [1, 53, 23, 37, 54, 24], 1426 [19, 45, 15, 26, 46, 16], 1427 1428 // 30 1429 [5, 145, 115, 10, 146, 116], 1430 [19, 75, 47, 10, 76, 48], 1431 [15, 54, 24, 25, 55, 25], 1432 [23, 45, 15, 25, 46, 16], 1433 1434 // 31 1435 [13, 145, 115, 3, 146, 116], 1436 [2, 74, 46, 29, 75, 47], 1437 [42, 54, 24, 1, 55, 25], 1438 [23, 45, 15, 28, 46, 16], 1439 1440 // 32 1441 [17, 145, 115], 1442 [10, 74, 46, 23, 75, 47], 1443 [10, 54, 24, 35, 55, 25], 1444 [19, 45, 15, 35, 46, 16], 1445 1446 // 33 1447 [17, 145, 115, 1, 146, 116], 1448 [14, 74, 46, 21, 75, 47], 1449 [29, 54, 24, 19, 55, 25], 1450 [11, 45, 15, 46, 46, 16], 1451 1452 // 34 1453 [13, 145, 115, 6, 146, 116], 1454 [14, 74, 46, 23, 75, 47], 1455 [44, 54, 24, 7, 55, 25], 1456 [59, 46, 16, 1, 47, 17], 1457 1458 // 35 1459 [12, 151, 121, 7, 152, 122], 1460 [12, 75, 47, 26, 76, 48], 1461 [39, 54, 24, 14, 55, 25], 1462 [22, 45, 15, 41, 46, 16], 1463 1464 // 36 1465 [6, 151, 121, 14, 152, 122], 1466 [6, 75, 47, 34, 76, 48], 1467 [46, 54, 24, 10, 55, 25], 1468 [2, 45, 15, 64, 46, 16], 1469 1470 // 37 1471 [17, 152, 122, 4, 153, 123], 1472 [29, 74, 46, 14, 75, 47], 1473 [49, 54, 24, 10, 55, 25], 1474 [24, 45, 15, 46, 46, 16], 1475 1476 // 38 1477 [4, 152, 122, 18, 153, 123], 1478 [13, 74, 46, 32, 75, 47], 1479 [48, 54, 24, 14, 55, 25], 1480 [42, 45, 15, 32, 46, 16], 1481 1482 // 39 1483 [20, 147, 117, 4, 148, 118], 1484 [40, 75, 47, 7, 76, 48], 1485 [43, 54, 24, 22, 55, 25], 1486 [10, 45, 15, 67, 46, 16], 1487 1488 // 40 1489 [19, 148, 118, 6, 149, 119], 1490 [18, 75, 47, 31, 76, 48], 1491 [34, 54, 24, 34, 55, 25], 1492 [20, 45, 15, 61, 46, 16] 1493 ]; 1494 1495 const qrRSBlock = function(totalCount, dataCount) { 1496 const _this = {}; 1497 _this.totalCount = totalCount; 1498 _this.dataCount = dataCount; 1499 return _this; 1500 }; 1501 1502 const _this = {}; 1503 1504 const getRsBlockTable = function(typeNumber, errorCorrectionLevel) { 1505 1506 switch(errorCorrectionLevel) { 1507 case QRErrorCorrectionLevel.L : 1508 return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0]; 1509 case QRErrorCorrectionLevel.M : 1510 return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1]; 1511 case QRErrorCorrectionLevel.Q : 1512 return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2]; 1513 case QRErrorCorrectionLevel.H : 1514 return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3]; 1515 default : 1516 return undefined; 1517 } 1518 }; 1519 1520 _this.getRSBlocks = function(typeNumber, errorCorrectionLevel) { 1521 1522 const rsBlock = getRsBlockTable(typeNumber, errorCorrectionLevel); 1523 1524 if (typeof rsBlock == 'undefined') { 1525 throw 'bad rs block @ typeNumber:' + typeNumber + 1526 '/errorCorrectionLevel:' + errorCorrectionLevel; 1527 } 1528 1529 const length = rsBlock.length / 3; 1530 1531 const list = []; 1532 1533 for (let i = 0; i < length; i += 1) { 1534 1535 const count = rsBlock[i * 3 + 0]; 1536 const totalCount = rsBlock[i * 3 + 1]; 1537 const dataCount = rsBlock[i * 3 + 2]; 1538 1539 for (let j = 0; j < count; j += 1) { 1540 list.push(qrRSBlock(totalCount, dataCount) ); 1541 } 1542 } 1543 1544 return list; 1545 }; 1546 1547 return _this; 1548 }(); 1549 1550 //--------------------------------------------------------------------- 1551 // qrBitBuffer 1552 //--------------------------------------------------------------------- 1553 1554 const qrBitBuffer = function() { 1555 1556 const _buffer = []; 1557 let _length = 0; 1558 1559 const _this = {}; 1560 1561 _this.getBuffer = function() { 1562 return _buffer; 1563 }; 1564 1565 _this.getAt = function(index) { 1566 const bufIndex = Math.floor(index / 8); 1567 return ( (_buffer[bufIndex] >>> (7 - index % 8) ) & 1) == 1; 1568 }; 1569 1570 _this.put = function(num, length) { 1571 for (let i = 0; i < length; i += 1) { 1572 _this.putBit( ( (num >>> (length - i - 1) ) & 1) == 1); 1573 } 1574 }; 1575 1576 _this.getLengthInBits = function() { 1577 return _length; 1578 }; 1579 1580 _this.putBit = function(bit) { 1581 1582 const bufIndex = Math.floor(_length / 8); 1583 if (_buffer.length <= bufIndex) { 1584 _buffer.push(0); 1585 } 1586 1587 if (bit) { 1588 _buffer[bufIndex] |= (0x80 >>> (_length % 8) ); 1589 } 1590 1591 _length += 1; 1592 }; 1593 1594 return _this; 1595 }; 1596 1597 //--------------------------------------------------------------------- 1598 // qrNumber 1599 //--------------------------------------------------------------------- 1600 1601 const qrNumber = function(data) { 1602 1603 const _mode = QRMode.MODE_NUMBER; 1604 const _data = data; 1605 1606 const _this = {}; 1607 1608 _this.getMode = function() { 1609 return _mode; 1610 }; 1611 1612 _this.getLength = function(buffer) { 1613 return _data.length; 1614 }; 1615 1616 _this.write = function(buffer) { 1617 1618 const data = _data; 1619 1620 let i = 0; 1621 1622 while (i + 2 < data.length) { 1623 buffer.put(strToNum(data.substring(i, i + 3) ), 10); 1624 i += 3; 1625 } 1626 1627 if (i < data.length) { 1628 if (data.length - i == 1) { 1629 buffer.put(strToNum(data.substring(i, i + 1) ), 4); 1630 } else if (data.length - i == 2) { 1631 buffer.put(strToNum(data.substring(i, i + 2) ), 7); 1632 } 1633 } 1634 }; 1635 1636 const strToNum = function(s) { 1637 let num = 0; 1638 for (let i = 0; i < s.length; i += 1) { 1639 num = num * 10 + chatToNum(s.charAt(i) ); 1640 } 1641 return num; 1642 }; 1643 1644 const chatToNum = function(c) { 1645 if ('0' <= c && c <= '9') { 1646 return c.charCodeAt(0) - '0'.charCodeAt(0); 1647 } 1648 throw 'illegal char :' + c; 1649 }; 1650 1651 return _this; 1652 }; 1653 1654 //--------------------------------------------------------------------- 1655 // qrAlphaNum 1656 //--------------------------------------------------------------------- 1657 1658 const qrAlphaNum = function(data) { 1659 1660 const _mode = QRMode.MODE_ALPHA_NUM; 1661 const _data = data; 1662 1663 const _this = {}; 1664 1665 _this.getMode = function() { 1666 return _mode; 1667 }; 1668 1669 _this.getLength = function(buffer) { 1670 return _data.length; 1671 }; 1672 1673 _this.write = function(buffer) { 1674 1675 const s = _data; 1676 1677 let i = 0; 1678 1679 while (i + 1 < s.length) { 1680 buffer.put( 1681 getCode(s.charAt(i) ) * 45 + 1682 getCode(s.charAt(i + 1) ), 11); 1683 i += 2; 1684 } 1685 1686 if (i < s.length) { 1687 buffer.put(getCode(s.charAt(i) ), 6); 1688 } 1689 }; 1690 1691 const getCode = function(c) { 1692 1693 if ('0' <= c && c <= '9') { 1694 return c.charCodeAt(0) - '0'.charCodeAt(0); 1695 } else if ('A' <= c && c <= 'Z') { 1696 return c.charCodeAt(0) - 'A'.charCodeAt(0) + 10; 1697 } else { 1698 switch (c) { 1699 case '\u0020' : return 36; 1700 case '$' : return 37; 1701 case '%' : return 38; 1702 case '*' : return 39; 1703 case '+' : return 40; 1704 case '-' : return 41; 1705 case '.' : return 42; 1706 case '/' : return 43; 1707 case ':' : return 44; 1708 default : 1709 throw 'illegal char :' + c; 1710 } 1711 } 1712 }; 1713 1714 return _this; 1715 }; 1716 1717 //--------------------------------------------------------------------- 1718 // qr8BitByte 1719 //--------------------------------------------------------------------- 1720 1721 const qr8BitByte = function(data) { 1722 1723 const _mode = QRMode.MODE_8BIT_BYTE; 1724 const _data = data; 1725 const _bytes = qrcode.stringToBytes(data); 1726 1727 const _this = {}; 1728 1729 _this.getMode = function() { 1730 return _mode; 1731 }; 1732 1733 _this.getLength = function(buffer) { 1734 return _bytes.length; 1735 }; 1736 1737 _this.write = function(buffer) { 1738 for (let i = 0; i < _bytes.length; i += 1) { 1739 buffer.put(_bytes[i], 8); 1740 } 1741 }; 1742 1743 return _this; 1744 }; 1745 1746 //--------------------------------------------------------------------- 1747 // qrKanji 1748 //--------------------------------------------------------------------- 1749 1750 const qrKanji = function(data) { 1751 1752 const _mode = QRMode.MODE_KANJI; 1753 const _data = data; 1754 1755 const stringToBytes = qrcode.stringToBytes; 1756 !function(c, code) { 1757 // self test for sjis support. 1758 const test = stringToBytes(c); 1759 if (test.length != 2 || ( (test[0] << 8) | test[1]) != code) { 1760 throw 'sjis not supported.'; 1761 } 1762 }('\u53cb', 0x9746); 1763 1764 const _bytes = stringToBytes(data); 1765 1766 const _this = {}; 1767 1768 _this.getMode = function() { 1769 return _mode; 1770 }; 1771 1772 _this.getLength = function(buffer) { 1773 return ~~(_bytes.length / 2); 1774 }; 1775 1776 _this.write = function(buffer) { 1777 1778 const data = _bytes; 1779 1780 let i = 0; 1781 1782 while (i + 1 < data.length) { 1783 1784 let c = ( (0xff & data[i]) << 8) | (0xff & data[i + 1]); 1785 1786 if (0x8140 <= c && c <= 0x9FFC) { 1787 c -= 0x8140; 1788 } else if (0xE040 <= c && c <= 0xEBBF) { 1789 c -= 0xC140; 1790 } else { 1791 throw 'illegal char at ' + (i + 1) + '/' + c; 1792 } 1793 1794 c = ( (c >>> 8) & 0xff) * 0xC0 + (c & 0xff); 1795 1796 buffer.put(c, 13); 1797 1798 i += 2; 1799 } 1800 1801 if (i < data.length) { 1802 throw 'illegal char at ' + (i + 1); 1803 } 1804 }; 1805 1806 return _this; 1807 }; 1808 1809 //===================================================================== 1810 // GIF Support etc. 1811 // 1812 1813 //--------------------------------------------------------------------- 1814 // byteArrayOutputStream 1815 //--------------------------------------------------------------------- 1816 1817 const byteArrayOutputStream = function() { 1818 1819 const _bytes = []; 1820 1821 const _this = {}; 1822 1823 _this.writeByte = function(b) { 1824 _bytes.push(b & 0xff); 1825 }; 1826 1827 _this.writeShort = function(i) { 1828 _this.writeByte(i); 1829 _this.writeByte(i >>> 8); 1830 }; 1831 1832 _this.writeBytes = function(b, off, len) { 1833 off = off || 0; 1834 len = len || b.length; 1835 for (let i = 0; i < len; i += 1) { 1836 _this.writeByte(b[i + off]); 1837 } 1838 }; 1839 1840 _this.writeString = function(s) { 1841 for (let i = 0; i < s.length; i += 1) { 1842 _this.writeByte(s.charCodeAt(i) ); 1843 } 1844 }; 1845 1846 _this.toByteArray = function() { 1847 return _bytes; 1848 }; 1849 1850 _this.toString = function() { 1851 let s = ''; 1852 s += '['; 1853 for (let i = 0; i < _bytes.length; i += 1) { 1854 if (i > 0) { 1855 s += ','; 1856 } 1857 s += _bytes[i]; 1858 } 1859 s += ']'; 1860 return s; 1861 }; 1862 1863 return _this; 1864 }; 1865 1866 //--------------------------------------------------------------------- 1867 // base64EncodeOutputStream 1868 //--------------------------------------------------------------------- 1869 1870 const base64EncodeOutputStream = function() { 1871 1872 let _buffer = 0; 1873 let _buflen = 0; 1874 let _length = 0; 1875 let _base64 = ''; 1876 1877 const _this = {}; 1878 1879 const writeEncoded = function(b) { 1880 _base64 += String.fromCharCode(encode(b & 0x3f) ); 1881 }; 1882 1883 const encode = function(n) { 1884 if (n < 0) { 1885 throw 'n:' + n; 1886 } else if (n < 26) { 1887 return 0x41 + n; 1888 } else if (n < 52) { 1889 return 0x61 + (n - 26); 1890 } else if (n < 62) { 1891 return 0x30 + (n - 52); 1892 } else if (n == 62) { 1893 return 0x2b; 1894 } else if (n == 63) { 1895 return 0x2f; 1896 } else { 1897 throw 'n:' + n; 1898 } 1899 }; 1900 1901 _this.writeByte = function(n) { 1902 1903 _buffer = (_buffer << 8) | (n & 0xff); 1904 _buflen += 8; 1905 _length += 1; 1906 1907 while (_buflen >= 6) { 1908 writeEncoded(_buffer >>> (_buflen - 6) ); 1909 _buflen -= 6; 1910 } 1911 }; 1912 1913 _this.flush = function() { 1914 1915 if (_buflen > 0) { 1916 writeEncoded(_buffer << (6 - _buflen) ); 1917 _buffer = 0; 1918 _buflen = 0; 1919 } 1920 1921 if (_length % 3 != 0) { 1922 // padding 1923 const padlen = 3 - _length % 3; 1924 for (let i = 0; i < padlen; i += 1) { 1925 _base64 += '='; 1926 } 1927 } 1928 }; 1929 1930 _this.toString = function() { 1931 return _base64; 1932 }; 1933 1934 return _this; 1935 }; 1936 1937 //--------------------------------------------------------------------- 1938 // base64DecodeInputStream 1939 //--------------------------------------------------------------------- 1940 1941 const base64DecodeInputStream = function(str) { 1942 1943 const _str = str; 1944 let _pos = 0; 1945 let _buffer = 0; 1946 let _buflen = 0; 1947 1948 const _this = {}; 1949 1950 _this.read = function() { 1951 1952 while (_buflen < 8) { 1953 1954 if (_pos >= _str.length) { 1955 if (_buflen == 0) { 1956 return -1; 1957 } 1958 throw 'unexpected end of file./' + _buflen; 1959 } 1960 1961 const c = _str.charAt(_pos); 1962 _pos += 1; 1963 1964 if (c == '=') { 1965 _buflen = 0; 1966 return -1; 1967 } else if (c.match(/^\s$/) ) { 1968 // ignore if whitespace. 1969 continue; 1970 } 1971 1972 _buffer = (_buffer << 6) | decode(c.charCodeAt(0) ); 1973 _buflen += 6; 1974 } 1975 1976 const n = (_buffer >>> (_buflen - 8) ) & 0xff; 1977 _buflen -= 8; 1978 return n; 1979 }; 1980 1981 const decode = function(c) { 1982 if (0x41 <= c && c <= 0x5a) { 1983 return c - 0x41; 1984 } else if (0x61 <= c && c <= 0x7a) { 1985 return c - 0x61 + 26; 1986 } else if (0x30 <= c && c <= 0x39) { 1987 return c - 0x30 + 52; 1988 } else if (c == 0x2b) { 1989 return 62; 1990 } else if (c == 0x2f) { 1991 return 63; 1992 } else { 1993 throw 'c:' + c; 1994 } 1995 }; 1996 1997 return _this; 1998 }; 1999 2000 //--------------------------------------------------------------------- 2001 // gifImage (B/W) 2002 //--------------------------------------------------------------------- 2003 2004 const gifImage = function(width, height) { 2005 2006 const _width = width; 2007 const _height = height; 2008 const _data = new Array(width * height); 2009 2010 const _this = {}; 2011 2012 _this.setPixel = function(x, y, pixel) { 2013 _data[y * _width + x] = pixel; 2014 }; 2015 2016 _this.write = function(out) { 2017 2018 //--------------------------------- 2019 // GIF Signature 2020 2021 out.writeString('GIF87a'); 2022 2023 //--------------------------------- 2024 // Screen Descriptor 2025 2026 out.writeShort(_width); 2027 out.writeShort(_height); 2028 2029 out.writeByte(0x80); // 2bit 2030 out.writeByte(0); 2031 out.writeByte(0); 2032 2033 //--------------------------------- 2034 // Global Color Map 2035 2036 // black 2037 out.writeByte(0x00); 2038 out.writeByte(0x00); 2039 out.writeByte(0x00); 2040 2041 // white 2042 out.writeByte(0xff); 2043 out.writeByte(0xff); 2044 out.writeByte(0xff); 2045 2046 //--------------------------------- 2047 // Image Descriptor 2048 2049 out.writeString(','); 2050 out.writeShort(0); 2051 out.writeShort(0); 2052 out.writeShort(_width); 2053 out.writeShort(_height); 2054 out.writeByte(0); 2055 2056 //--------------------------------- 2057 // Local Color Map 2058 2059 //--------------------------------- 2060 // Raster Data 2061 2062 const lzwMinCodeSize = 2; 2063 const raster = getLZWRaster(lzwMinCodeSize); 2064 2065 out.writeByte(lzwMinCodeSize); 2066 2067 let offset = 0; 2068 2069 while (raster.length - offset > 255) { 2070 out.writeByte(255); 2071 out.writeBytes(raster, offset, 255); 2072 offset += 255; 2073 } 2074 2075 out.writeByte(raster.length - offset); 2076 out.writeBytes(raster, offset, raster.length - offset); 2077 out.writeByte(0x00); 2078 2079 //--------------------------------- 2080 // GIF Terminator 2081 out.writeString(';'); 2082 }; 2083 2084 const bitOutputStream = function(out) { 2085 2086 const _out = out; 2087 let _bitLength = 0; 2088 let _bitBuffer = 0; 2089 2090 const _this = {}; 2091 2092 _this.write = function(data, length) { 2093 2094 if ( (data >>> length) != 0) { 2095 throw 'length over'; 2096 } 2097 2098 while (_bitLength + length >= 8) { 2099 _out.writeByte(0xff & ( (data << _bitLength) | _bitBuffer) ); 2100 length -= (8 - _bitLength); 2101 data >>>= (8 - _bitLength); 2102 _bitBuffer = 0; 2103 _bitLength = 0; 2104 } 2105 2106 _bitBuffer = (data << _bitLength) | _bitBuffer; 2107 _bitLength = _bitLength + length; 2108 }; 2109 2110 _this.flush = function() { 2111 if (_bitLength > 0) { 2112 _out.writeByte(_bitBuffer); 2113 } 2114 }; 2115 2116 return _this; 2117 }; 2118 2119 const getLZWRaster = function(lzwMinCodeSize) { 2120 2121 const clearCode = 1 << lzwMinCodeSize; 2122 const endCode = (1 << lzwMinCodeSize) + 1; 2123 let bitLength = lzwMinCodeSize + 1; 2124 2125 // Setup LZWTable 2126 const table = lzwTable(); 2127 2128 for (let i = 0; i < clearCode; i += 1) { 2129 table.add(String.fromCharCode(i) ); 2130 } 2131 table.add(String.fromCharCode(clearCode) ); 2132 table.add(String.fromCharCode(endCode) ); 2133 2134 const byteOut = byteArrayOutputStream(); 2135 const bitOut = bitOutputStream(byteOut); 2136 2137 // clear code 2138 bitOut.write(clearCode, bitLength); 2139 2140 let dataIndex = 0; 2141 2142 let s = String.fromCharCode(_data[dataIndex]); 2143 dataIndex += 1; 2144 2145 while (dataIndex < _data.length) { 2146 2147 const c = String.fromCharCode(_data[dataIndex]); 2148 dataIndex += 1; 2149 2150 if (table.contains(s + c) ) { 2151 2152 s = s + c; 2153 2154 } else { 2155 2156 bitOut.write(table.indexOf(s), bitLength); 2157 2158 if (table.size() < 0xfff) { 2159 2160 if (table.size() == (1 << bitLength) ) { 2161 bitLength += 1; 2162 } 2163 2164 table.add(s + c); 2165 } 2166 2167 s = c; 2168 } 2169 } 2170 2171 bitOut.write(table.indexOf(s), bitLength); 2172 2173 // end code 2174 bitOut.write(endCode, bitLength); 2175 2176 bitOut.flush(); 2177 2178 return byteOut.toByteArray(); 2179 }; 2180 2181 const lzwTable = function() { 2182 2183 const _map = {}; 2184 let _size = 0; 2185 2186 const _this = {}; 2187 2188 _this.add = function(key) { 2189 if (_this.contains(key) ) { 2190 throw 'dup key:' + key; 2191 } 2192 _map[key] = _size; 2193 _size += 1; 2194 }; 2195 2196 _this.size = function() { 2197 return _size; 2198 }; 2199 2200 _this.indexOf = function(key) { 2201 return _map[key]; 2202 }; 2203 2204 _this.contains = function(key) { 2205 return typeof _map[key] != 'undefined'; 2206 }; 2207 2208 return _this; 2209 }; 2210 2211 return _this; 2212 }; 2213 2214 const createDataURL = function(width, height, getPixel) { 2215 const gif = gifImage(width, height); 2216 for (let y = 0; y < height; y += 1) { 2217 for (let x = 0; x < width; x += 1) { 2218 gif.setPixel(x, y, getPixel(x, y) ); 2219 } 2220 } 2221 2222 const b = byteArrayOutputStream(); 2223 gif.write(b); 2224 2225 const base64 = base64EncodeOutputStream(); 2226 const bytes = b.toByteArray(); 2227 for (let i = 0; i < bytes.length; i += 1) { 2228 base64.writeByte(bytes[i]); 2229 } 2230 base64.flush(); 2231 2232 return 'data:image/gif;base64,' + base64; 2233 }; 2234 2235 export default qrcode; 2236 2237 export const stringToBytes = qrcode.stringToBytes;