qrcode.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  1. /* eslint-disable */
  2. const QR = function () {
  3. // alignment pattern
  4. const adelta = [0, 11, 15, 19, 23, 27, 31, // force 1 pat
  5. 16, 18, 20, 22, 24, 26, 28, 20, 22, 24, 24, 26, 28, 28, 22, 24, 24, 26, 26, 28, 28, 24, 24, 26, 26, 26, 28, 28, 24, 26, 26, 26, 28, 28]; // version block
  6. const vpat = [0xc94, 0x5bc, 0xa99, 0x4d3, 0xbf6, 0x762, 0x847, 0x60d, 0x928, 0xb78, 0x45d, 0xa17, 0x532, 0x9a6, 0x683, 0x8c9, 0x7ec, 0xec4, 0x1e1, 0xfab, 0x08e, 0xc1a, 0x33f, 0xd75, 0x250, 0x9d5, 0x6f0, 0x8ba, 0x79f, 0xb0b, 0x42e, 0xa64, 0x541, 0xc69]; // final format bits with mask: level << 3 | mask
  7. const fmtword = [0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976, // L
  8. 0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0, // M
  9. 0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed, // Q
  10. 0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b // H
  11. ]; // 4 per version: number of blocks 1,2; data width; ecc width
  12. const eccblocks = [1, 0, 19, 7, 1, 0, 16, 10, 1, 0, 13, 13, 1, 0, 9, 17, 1, 0, 34, 10, 1, 0, 28, 16, 1, 0, 22, 22, 1, 0, 16, 28, 1, 0, 55, 15, 1, 0, 44, 26, 2, 0, 17, 18, 2, 0, 13, 22, 1, 0, 80, 20, 2, 0, 32, 18, 2, 0, 24, 26, 4, 0, 9, 16, 1, 0, 108, 26, 2, 0, 43, 24, 2, 2, 15, 18, 2, 2, 11, 22, 2, 0, 68, 18, 4, 0, 27, 16, 4, 0, 19, 24, 4, 0, 15, 28, 2, 0, 78, 20, 4, 0, 31, 18, 2, 4, 14, 18, 4, 1, 13, 26, 2, 0, 97, 24, 2, 2, 38, 22, 4, 2, 18, 22, 4, 2, 14, 26, 2, 0, 116, 30, 3, 2, 36, 22, 4, 4, 16, 20, 4, 4, 12, 24, 2, 2, 68, 18, 4, 1, 43, 26, 6, 2, 19, 24, 6, 2, 15, 28, 4, 0, 81, 20, 1, 4, 50, 30, 4, 4, 22, 28, 3, 8, 12, 24, 2, 2, 92, 24, 6, 2, 36, 22, 4, 6, 20, 26, 7, 4, 14, 28, 4, 0, 107, 26, 8, 1, 37, 22, 8, 4, 20, 24, 12, 4, 11, 22, 3, 1, 115, 30, 4, 5, 40, 24, 11, 5, 16, 20, 11, 5, 12, 24, 5, 1, 87, 22, 5, 5, 41, 24, 5, 7, 24, 30, 11, 7, 12, 24, 5, 1, 98, 24, 7, 3, 45, 28, 15, 2, 19, 24, 3, 13, 15, 30, 1, 5, 107, 28, 10, 1, 46, 28, 1, 15, 22, 28, 2, 17, 14, 28, 5, 1, 120, 30, 9, 4, 43, 26, 17, 1, 22, 28, 2, 19, 14, 28, 3, 4, 113, 28, 3, 11, 44, 26, 17, 4, 21, 26, 9, 16, 13, 26, 3, 5, 107, 28, 3, 13, 41, 26, 15, 5, 24, 30, 15, 10, 15, 28, 4, 4, 116, 28, 17, 0, 42, 26, 17, 6, 22, 28, 19, 6, 16, 30, 2, 7, 111, 28, 17, 0, 46, 28, 7, 16, 24, 30, 34, 0, 13, 24, 4, 5, 121, 30, 4, 14, 47, 28, 11, 14, 24, 30, 16, 14, 15, 30, 6, 4, 117, 30, 6, 14, 45, 28, 11, 16, 24, 30, 30, 2, 16, 30, 8, 4, 106, 26, 8, 13, 47, 28, 7, 22, 24, 30, 22, 13, 15, 30, 10, 2, 114, 28, 19, 4, 46, 28, 28, 6, 22, 28, 33, 4, 16, 30, 8, 4, 122, 30, 22, 3, 45, 28, 8, 26, 23, 30, 12, 28, 15, 30, 3, 10, 117, 30, 3, 23, 45, 28, 4, 31, 24, 30, 11, 31, 15, 30, 7, 7, 116, 30, 21, 7, 45, 28, 1, 37, 23, 30, 19, 26, 15, 30, 5, 10, 115, 30, 19, 10, 47, 28, 15, 25, 24, 30, 23, 25, 15, 30, 13, 3, 115, 30, 2, 29, 46, 28, 42, 1, 24, 30, 23, 28, 15, 30, 17, 0, 115, 30, 10, 23, 46, 28, 10, 35, 24, 30, 19, 35, 15, 30, 17, 1, 115, 30, 14, 21, 46, 28, 29, 19, 24, 30, 11, 46, 15, 30, 13, 6, 115, 30, 14, 23, 46, 28, 44, 7, 24, 30, 59, 1, 16, 30, 12, 7, 121, 30, 12, 26, 47, 28, 39, 14, 24, 30, 22, 41, 15, 30, 6, 14, 121, 30, 6, 34, 47, 28, 46, 10, 24, 30, 2, 64, 15, 30, 17, 4, 122, 30, 29, 14, 46, 28, 49, 10, 24, 30, 24, 46, 15, 30, 4, 18, 122, 30, 13, 32, 46, 28, 48, 14, 24, 30, 42, 32, 15, 30, 20, 4, 117, 30, 40, 7, 47, 28, 43, 22, 24, 30, 10, 67, 15, 30, 19, 6, 118, 30, 18, 31, 47, 28, 34, 34, 24, 30, 20, 61, 15, 30]; // Galois field log table
  13. const glog = [0xff, 0x00, 0x01, 0x19, 0x02, 0x32, 0x1a, 0xc6, 0x03, 0xdf, 0x33, 0xee, 0x1b, 0x68, 0xc7, 0x4b, 0x04, 0x64, 0xe0, 0x0e, 0x34, 0x8d, 0xef, 0x81, 0x1c, 0xc1, 0x69, 0xf8, 0xc8, 0x08, 0x4c, 0x71, 0x05, 0x8a, 0x65, 0x2f, 0xe1, 0x24, 0x0f, 0x21, 0x35, 0x93, 0x8e, 0xda, 0xf0, 0x12, 0x82, 0x45, 0x1d, 0xb5, 0xc2, 0x7d, 0x6a, 0x27, 0xf9, 0xb9, 0xc9, 0x9a, 0x09, 0x78, 0x4d, 0xe4, 0x72, 0xa6, 0x06, 0xbf, 0x8b, 0x62, 0x66, 0xdd, 0x30, 0xfd, 0xe2, 0x98, 0x25, 0xb3, 0x10, 0x91, 0x22, 0x88, 0x36, 0xd0, 0x94, 0xce, 0x8f, 0x96, 0xdb, 0xbd, 0xf1, 0xd2, 0x13, 0x5c, 0x83, 0x38, 0x46, 0x40, 0x1e, 0x42, 0xb6, 0xa3, 0xc3, 0x48, 0x7e, 0x6e, 0x6b, 0x3a, 0x28, 0x54, 0xfa, 0x85, 0xba, 0x3d, 0xca, 0x5e, 0x9b, 0x9f, 0x0a, 0x15, 0x79, 0x2b, 0x4e, 0xd4, 0xe5, 0xac, 0x73, 0xf3, 0xa7, 0x57, 0x07, 0x70, 0xc0, 0xf7, 0x8c, 0x80, 0x63, 0x0d, 0x67, 0x4a, 0xde, 0xed, 0x31, 0xc5, 0xfe, 0x18, 0xe3, 0xa5, 0x99, 0x77, 0x26, 0xb8, 0xb4, 0x7c, 0x11, 0x44, 0x92, 0xd9, 0x23, 0x20, 0x89, 0x2e, 0x37, 0x3f, 0xd1, 0x5b, 0x95, 0xbc, 0xcf, 0xcd, 0x90, 0x87, 0x97, 0xb2, 0xdc, 0xfc, 0xbe, 0x61, 0xf2, 0x56, 0xd3, 0xab, 0x14, 0x2a, 0x5d, 0x9e, 0x84, 0x3c, 0x39, 0x53, 0x47, 0x6d, 0x41, 0xa2, 0x1f, 0x2d, 0x43, 0xd8, 0xb7, 0x7b, 0xa4, 0x76, 0xc4, 0x17, 0x49, 0xec, 0x7f, 0x0c, 0x6f, 0xf6, 0x6c, 0xa1, 0x3b, 0x52, 0x29, 0x9d, 0x55, 0xaa, 0xfb, 0x60, 0x86, 0xb1, 0xbb, 0xcc, 0x3e, 0x5a, 0xcb, 0x59, 0x5f, 0xb0, 0x9c, 0xa9, 0xa0, 0x51, 0x0b, 0xf5, 0x16, 0xeb, 0x7a, 0x75, 0x2c, 0xd7, 0x4f, 0xae, 0xd5, 0xe9, 0xe6, 0xe7, 0xad, 0xe8, 0x74, 0xd6, 0xf4, 0xea, 0xa8, 0x50, 0x58, 0xaf]; // Galios field exponent table
  14. const gexp = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1d, 0x3a, 0x74, 0xe8, 0xcd, 0x87, 0x13, 0x26, 0x4c, 0x98, 0x2d, 0x5a, 0xb4, 0x75, 0xea, 0xc9, 0x8f, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x9d, 0x27, 0x4e, 0x9c, 0x25, 0x4a, 0x94, 0x35, 0x6a, 0xd4, 0xb5, 0x77, 0xee, 0xc1, 0x9f, 0x23, 0x46, 0x8c, 0x05, 0x0a, 0x14, 0x28, 0x50, 0xa0, 0x5d, 0xba, 0x69, 0xd2, 0xb9, 0x6f, 0xde, 0xa1, 0x5f, 0xbe, 0x61, 0xc2, 0x99, 0x2f, 0x5e, 0xbc, 0x65, 0xca, 0x89, 0x0f, 0x1e, 0x3c, 0x78, 0xf0, 0xfd, 0xe7, 0xd3, 0xbb, 0x6b, 0xd6, 0xb1, 0x7f, 0xfe, 0xe1, 0xdf, 0xa3, 0x5b, 0xb6, 0x71, 0xe2, 0xd9, 0xaf, 0x43, 0x86, 0x11, 0x22, 0x44, 0x88, 0x0d, 0x1a, 0x34, 0x68, 0xd0, 0xbd, 0x67, 0xce, 0x81, 0x1f, 0x3e, 0x7c, 0xf8, 0xed, 0xc7, 0x93, 0x3b, 0x76, 0xec, 0xc5, 0x97, 0x33, 0x66, 0xcc, 0x85, 0x17, 0x2e, 0x5c, 0xb8, 0x6d, 0xda, 0xa9, 0x4f, 0x9e, 0x21, 0x42, 0x84, 0x15, 0x2a, 0x54, 0xa8, 0x4d, 0x9a, 0x29, 0x52, 0xa4, 0x55, 0xaa, 0x49, 0x92, 0x39, 0x72, 0xe4, 0xd5, 0xb7, 0x73, 0xe6, 0xd1, 0xbf, 0x63, 0xc6, 0x91, 0x3f, 0x7e, 0xfc, 0xe5, 0xd7, 0xb3, 0x7b, 0xf6, 0xf1, 0xff, 0xe3, 0xdb, 0xab, 0x4b, 0x96, 0x31, 0x62, 0xc4, 0x95, 0x37, 0x6e, 0xdc, 0xa5, 0x57, 0xae, 0x41, 0x82, 0x19, 0x32, 0x64, 0xc8, 0x8d, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0, 0xdd, 0xa7, 0x53, 0xa6, 0x51, 0xa2, 0x59, 0xb2, 0x79, 0xf2, 0xf9, 0xef, 0xc3, 0x9b, 0x2b, 0x56, 0xac, 0x45, 0x8a, 0x09, 0x12, 0x24, 0x48, 0x90, 0x3d, 0x7a, 0xf4, 0xf5, 0xf7, 0xf3, 0xfb, 0xeb, 0xcb, 0x8b, 0x0b, 0x16, 0x2c, 0x58, 0xb0, 0x7d, 0xfa, 0xe9, 0xcf, 0x83, 0x1b, 0x36, 0x6c, 0xd8, 0xad, 0x47, 0x8e, 0x00]; // Working buffers:
  15. // data input and ecc append, image working buffer, fixed part of image, run lengths for badness
  16. let strinbuf = [];
  17. const eccbuf = [];
  18. let qrframe = [];
  19. const framask = [];
  20. const rlens = []; // Control values - width is based on version, last 4 are from table.
  21. let version;
  22. let width;
  23. let neccblk1;
  24. let neccblk2;
  25. let datablkw;
  26. let eccblkwid;
  27. let ecclevel = 2; // set bit to indicate cell in qrframe is immutable. symmetric around diagonal
  28. function setmask(x, y) {
  29. let bt;
  30. if (x > y) {
  31. bt = x;
  32. x = y;
  33. y = bt;
  34. } // y*y = 1+3+5...
  35. bt = y;
  36. bt *= y;
  37. bt += y;
  38. bt >>= 1;
  39. bt += x;
  40. framask[bt] = 1;
  41. } // enter alignment pattern - black to qrframe, white to mask (later black frame merged to mask)
  42. function putalign(x, y) {
  43. let j;
  44. qrframe[x + width * y] = 1;
  45. for (j = -2; j < 2; j++) {
  46. qrframe[x + j + width * (y - 2)] = 1;
  47. qrframe[x - 2 + width * (y + j + 1)] = 1;
  48. qrframe[x + 2 + width * (y + j)] = 1;
  49. qrframe[x + j + 1 + width * (y + 2)] = 1;
  50. }
  51. for (j = 0; j < 2; j++) {
  52. setmask(x - 1, y + j);
  53. setmask(x + 1, y - j);
  54. setmask(x - j, y - 1);
  55. setmask(x + j, y + 1);
  56. }
  57. } //= =======================================================================
  58. // Reed Solomon error correction
  59. // exponentiation mod N
  60. function modnn(x) {
  61. while (x >= 255) {
  62. x -= 255;
  63. x = (x >> 8) + (x & 255);
  64. }
  65. return x;
  66. }
  67. const genpoly = []; // Calculate and append ECC data to data block. Block is in strinbuf, indexes to buffers given.
  68. function appendrs(data, dlen, ecbuf, eclen) {
  69. let i;
  70. let j;
  71. let fb;
  72. for (i = 0; i < eclen; i++) strinbuf[ecbuf + i] = 0;
  73. for (i = 0; i < dlen; i++) {
  74. fb = glog[strinbuf[data + i] ^ strinbuf[ecbuf]];
  75. if (fb != 255)
  76. /* fb term is non-zero */
  77. {
  78. for (j = 1; j < eclen; j++) strinbuf[ecbuf + j - 1] = strinbuf[ecbuf + j] ^ gexp[modnn(fb + genpoly[eclen - j])];
  79. } else for (j = ecbuf; j < ecbuf + eclen; j++) strinbuf[j] = strinbuf[j + 1];
  80. strinbuf[ecbuf + eclen - 1] = fb == 255 ? 0 : gexp[modnn(fb + genpoly[0])];
  81. }
  82. } //= =======================================================================
  83. // Frame data insert following the path rules
  84. // check mask - since symmetrical use half.
  85. function ismasked(x, y) {
  86. let bt;
  87. if (x > y) {
  88. bt = x;
  89. x = y;
  90. y = bt;
  91. }
  92. bt = y;
  93. bt += y * y;
  94. bt >>= 1;
  95. bt += x;
  96. return framask[bt];
  97. } //= =======================================================================
  98. // Apply the selected mask out of the 8.
  99. function applymask(m) {
  100. let x;
  101. let y;
  102. let r3x;
  103. let r3y;
  104. switch (m) {
  105. case 0:
  106. for (y = 0; y < width; y++) for (x = 0; x < width; x++) if (!(x + y & 1) && !ismasked(x, y)) qrframe[x + y * width] ^= 1;
  107. break;
  108. case 1:
  109. for (y = 0; y < width; y++) for (x = 0; x < width; x++) if (!(y & 1) && !ismasked(x, y)) qrframe[x + y * width] ^= 1;
  110. break;
  111. case 2:
  112. for (y = 0; y < width; y++) {
  113. for (r3x = 0, x = 0; x < width; x++, r3x++) {
  114. if (r3x == 3) r3x = 0;
  115. if (!r3x && !ismasked(x, y)) qrframe[x + y * width] ^= 1;
  116. }
  117. }
  118. break;
  119. case 3:
  120. for (r3y = 0, y = 0; y < width; y++, r3y++) {
  121. if (r3y == 3) r3y = 0;
  122. for (r3x = r3y, x = 0; x < width; x++, r3x++) {
  123. if (r3x == 3) r3x = 0;
  124. if (!r3x && !ismasked(x, y)) qrframe[x + y * width] ^= 1;
  125. }
  126. }
  127. break;
  128. case 4:
  129. for (y = 0; y < width; y++) {
  130. for (r3x = 0, r3y = y >> 1 & 1, x = 0; x < width; x++, r3x++) {
  131. if (r3x == 3) {
  132. r3x = 0;
  133. r3y = !r3y;
  134. }
  135. if (!r3y && !ismasked(x, y)) qrframe[x + y * width] ^= 1;
  136. }
  137. }
  138. break;
  139. case 5:
  140. for (r3y = 0, y = 0; y < width; y++, r3y++) {
  141. if (r3y == 3) r3y = 0;
  142. for (r3x = 0, x = 0; x < width; x++, r3x++) {
  143. if (r3x == 3) r3x = 0;
  144. if (!((x & y & 1) + !(!r3x | !r3y)) && !ismasked(x, y)) qrframe[x + y * width] ^= 1;
  145. }
  146. }
  147. break;
  148. case 6:
  149. for (r3y = 0, y = 0; y < width; y++, r3y++) {
  150. if (r3y == 3) r3y = 0;
  151. for (r3x = 0, x = 0; x < width; x++, r3x++) {
  152. if (r3x == 3) r3x = 0;
  153. if (!((x & y & 1) + (r3x && r3x == r3y) & 1) && !ismasked(x, y)) qrframe[x + y * width] ^= 1;
  154. }
  155. }
  156. break;
  157. case 7:
  158. for (r3y = 0, y = 0; y < width; y++, r3y++) {
  159. if (r3y == 3) r3y = 0;
  160. for (r3x = 0, x = 0; x < width; x++, r3x++) {
  161. if (r3x == 3) r3x = 0;
  162. if (!((r3x && r3x == r3y) + (x + y & 1) & 1) && !ismasked(x, y)) qrframe[x + y * width] ^= 1;
  163. }
  164. }
  165. break;
  166. }
  167. } // Badness coefficients.
  168. const N1 = 3;
  169. const N2 = 3;
  170. const N3 = 40;
  171. const N4 = 10; // Using the table of the length of each run, calculate the amount of bad image
  172. // - long runs or those that look like finders; called twice, once each for X and Y
  173. function badruns(length) {
  174. let i;
  175. let runsbad = 0;
  176. for (i = 0; i <= length; i++) if (rlens[i] >= 5) runsbad += N1 + rlens[i] - 5; // BwBBBwB as in finder
  177. for (i = 3; i < length - 1; i += 2) {
  178. if (rlens[i - 2] == rlens[i + 2] && rlens[i + 2] == rlens[i - 1] && rlens[i - 1] == rlens[i + 1] && rlens[i - 1] * 3 == rlens[i] // white around the black pattern? Not part of spec
  179. && (rlens[i - 3] == 0 // beginning
  180. || i + 3 > length // end
  181. || rlens[i - 3] * 3 >= rlens[i] * 4 || rlens[i + 3] * 3 >= rlens[i] * 4)) runsbad += N3;
  182. }
  183. return runsbad;
  184. } // Calculate how bad the masked image is - blocks, imbalance, runs, or finders.
  185. function badcheck() {
  186. let x;
  187. let y;
  188. let h;
  189. let b;
  190. let b1;
  191. let thisbad = 0;
  192. let bw = 0; // blocks of same color.
  193. for (y = 0; y < width - 1; y++) {
  194. for (x = 0; x < width - 1; x++) {
  195. if (qrframe[x + width * y] && qrframe[x + 1 + width * y] && qrframe[x + width * (y + 1)] && qrframe[x + 1 + width * (y + 1)] // all black
  196. || !(qrframe[x + width * y] || qrframe[x + 1 + width * y] || qrframe[x + width * (y + 1)] || qrframe[x + 1 + width * (y + 1)])) // all white
  197. {
  198. thisbad += N2;
  199. }
  200. }
  201. } // X runs
  202. for (y = 0; y < width; y++) {
  203. rlens[0] = 0;
  204. for (h = b = x = 0; x < width; x++) {
  205. if ((b1 = qrframe[x + width * y]) == b) rlens[h]++;else rlens[++h] = 1;
  206. b = b1;
  207. bw += b ? 1 : -1;
  208. }
  209. thisbad += badruns(h);
  210. } // black/white imbalance
  211. if (bw < 0) bw = -bw;
  212. let big = bw;
  213. let count = 0;
  214. big += big << 2;
  215. big <<= 1;
  216. while (big > width * width) big -= width * width, count++;
  217. thisbad += count * N4; // Y runs
  218. for (x = 0; x < width; x++) {
  219. rlens[0] = 0;
  220. for (h = b = y = 0; y < width; y++) {
  221. if ((b1 = qrframe[x + width * y]) == b) rlens[h]++;else rlens[++h] = 1;
  222. b = b1;
  223. }
  224. thisbad += badruns(h);
  225. }
  226. return thisbad;
  227. }
  228. function genframe(instring) {
  229. let x;
  230. let y;
  231. let k;
  232. let t;
  233. let v;
  234. let i;
  235. let j;
  236. let m; // find the smallest version that fits the string
  237. t = instring.length;
  238. version = 0;
  239. do {
  240. version++;
  241. k = (ecclevel - 1) * 4 + (version - 1) * 16;
  242. neccblk1 = eccblocks[k++];
  243. neccblk2 = eccblocks[k++];
  244. datablkw = eccblocks[k++];
  245. eccblkwid = eccblocks[k];
  246. k = datablkw * (neccblk1 + neccblk2) + neccblk2 - 3 + (version <= 9);
  247. if (t <= k) break;
  248. } while (version < 40); // FIXME - insure that it fits insted of being truncated
  249. width = 17 + 4 * version; // allocate, clear and setup data structures
  250. v = datablkw + (datablkw + eccblkwid) * (neccblk1 + neccblk2) + neccblk2;
  251. for (t = 0; t < v; t++) eccbuf[t] = 0;
  252. strinbuf = instring.slice(0);
  253. for (t = 0; t < width * width; t++) qrframe[t] = 0;
  254. for (t = 0; t < (width * (width + 1) + 1) / 2; t++) framask[t] = 0; // insert finders - black to frame, white to mask
  255. for (t = 0; t < 3; t++) {
  256. k = 0;
  257. y = 0;
  258. if (t == 1) k = width - 7;
  259. if (t == 2) y = width - 7;
  260. qrframe[y + 3 + width * (k + 3)] = 1;
  261. for (x = 0; x < 6; x++) {
  262. qrframe[y + x + width * k] = 1;
  263. qrframe[y + width * (k + x + 1)] = 1;
  264. qrframe[y + 6 + width * (k + x)] = 1;
  265. qrframe[y + x + 1 + width * (k + 6)] = 1;
  266. }
  267. for (x = 1; x < 5; x++) {
  268. setmask(y + x, k + 1);
  269. setmask(y + 1, k + x + 1);
  270. setmask(y + 5, k + x);
  271. setmask(y + x + 1, k + 5);
  272. }
  273. for (x = 2; x < 4; x++) {
  274. qrframe[y + x + width * (k + 2)] = 1;
  275. qrframe[y + 2 + width * (k + x + 1)] = 1;
  276. qrframe[y + 4 + width * (k + x)] = 1;
  277. qrframe[y + x + 1 + width * (k + 4)] = 1;
  278. }
  279. } // alignment blocks
  280. if (version > 1) {
  281. t = adelta[version];
  282. y = width - 7;
  283. for (;;) {
  284. x = width - 7;
  285. while (x > t - 3) {
  286. putalign(x, y);
  287. if (x < t) break;
  288. x -= t;
  289. }
  290. if (y <= t + 9) break;
  291. y -= t;
  292. putalign(6, y);
  293. putalign(y, 6);
  294. }
  295. } // single black
  296. qrframe[8 + width * (width - 8)] = 1; // timing gap - mask only
  297. for (y = 0; y < 7; y++) {
  298. setmask(7, y);
  299. setmask(width - 8, y);
  300. setmask(7, y + width - 7);
  301. }
  302. for (x = 0; x < 8; x++) {
  303. setmask(x, 7);
  304. setmask(x + width - 8, 7);
  305. setmask(x, width - 8);
  306. } // reserve mask-format area
  307. for (x = 0; x < 9; x++) setmask(x, 8);
  308. for (x = 0; x < 8; x++) {
  309. setmask(x + width - 8, 8);
  310. setmask(8, x);
  311. }
  312. for (y = 0; y < 7; y++) setmask(8, y + width - 7); // timing row/col
  313. for (x = 0; x < width - 14; x++) {
  314. if (x & 1) {
  315. setmask(8 + x, 6);
  316. setmask(6, 8 + x);
  317. } else {
  318. qrframe[8 + x + width * 6] = 1;
  319. qrframe[6 + width * (8 + x)] = 1;
  320. }
  321. } // version block
  322. if (version > 6) {
  323. t = vpat[version - 7];
  324. k = 17;
  325. for (x = 0; x < 6; x++) {
  326. for (y = 0; y < 3; y++, k--) {
  327. if (1 & (k > 11 ? version >> k - 12 : t >> k)) {
  328. qrframe[5 - x + width * (2 - y + width - 11)] = 1;
  329. qrframe[2 - y + width - 11 + width * (5 - x)] = 1;
  330. } else {
  331. setmask(5 - x, 2 - y + width - 11);
  332. setmask(2 - y + width - 11, 5 - x);
  333. }
  334. }
  335. }
  336. } // sync mask bits - only set above for white spaces, so add in black bits
  337. for (y = 0; y < width; y++) for (x = 0; x <= y; x++) if (qrframe[x + width * y]) setmask(x, y); // convert string to bitstream
  338. // 8 bit data to QR-coded 8 bit data (numeric or alphanum, or kanji not supported)
  339. v = strinbuf.length; // string to array
  340. for (i = 0; i < v; i++) eccbuf[i] = strinbuf.charCodeAt(i);
  341. strinbuf = eccbuf.slice(0); // calculate max string length
  342. x = datablkw * (neccblk1 + neccblk2) + neccblk2;
  343. if (v >= x - 2) {
  344. v = x - 2;
  345. if (version > 9) v--;
  346. } // shift and repack to insert length prefix
  347. i = v;
  348. if (version > 9) {
  349. strinbuf[i + 2] = 0;
  350. strinbuf[i + 3] = 0;
  351. while (i--) {
  352. t = strinbuf[i];
  353. strinbuf[i + 3] |= 255 & t << 4;
  354. strinbuf[i + 2] = t >> 4;
  355. }
  356. strinbuf[2] |= 255 & v << 4;
  357. strinbuf[1] = v >> 4;
  358. strinbuf[0] = 0x40 | v >> 12;
  359. } else {
  360. strinbuf[i + 1] = 0;
  361. strinbuf[i + 2] = 0;
  362. while (i--) {
  363. t = strinbuf[i];
  364. strinbuf[i + 2] |= 255 & t << 4;
  365. strinbuf[i + 1] = t >> 4;
  366. }
  367. strinbuf[1] |= 255 & v << 4;
  368. strinbuf[0] = 0x40 | v >> 4;
  369. } // fill to end with pad pattern
  370. i = v + 3 - (version < 10);
  371. while (i < x) {
  372. strinbuf[i++] = 0xec; // buffer has room if (i == x) break;
  373. strinbuf[i++] = 0x11;
  374. } // calculate and append ECC
  375. // calculate generator polynomial
  376. genpoly[0] = 1;
  377. for (i = 0; i < eccblkwid; i++) {
  378. genpoly[i + 1] = 1;
  379. for (j = i; j > 0; j--) {
  380. genpoly[j] = genpoly[j] ? genpoly[j - 1] ^ gexp[modnn(glog[genpoly[j]] + i)] : genpoly[j - 1];
  381. }
  382. genpoly[0] = gexp[modnn(glog[genpoly[0]] + i)];
  383. }
  384. for (i = 0; i <= eccblkwid; i++) genpoly[i] = glog[genpoly[i]]; // use logs for genpoly[] to save calc step
  385. // append ecc to data buffer
  386. k = x;
  387. y = 0;
  388. for (i = 0; i < neccblk1; i++) {
  389. appendrs(y, datablkw, k, eccblkwid);
  390. y += datablkw;
  391. k += eccblkwid;
  392. }
  393. for (i = 0; i < neccblk2; i++) {
  394. appendrs(y, datablkw + 1, k, eccblkwid);
  395. y += datablkw + 1;
  396. k += eccblkwid;
  397. } // interleave blocks
  398. y = 0;
  399. for (i = 0; i < datablkw; i++) {
  400. for (j = 0; j < neccblk1; j++) eccbuf[y++] = strinbuf[i + j * datablkw];
  401. for (j = 0; j < neccblk2; j++) eccbuf[y++] = strinbuf[neccblk1 * datablkw + i + j * (datablkw + 1)];
  402. }
  403. for (j = 0; j < neccblk2; j++) eccbuf[y++] = strinbuf[neccblk1 * datablkw + i + j * (datablkw + 1)];
  404. for (i = 0; i < eccblkwid; i++) for (j = 0; j < neccblk1 + neccblk2; j++) eccbuf[y++] = strinbuf[x + i + j * eccblkwid];
  405. strinbuf = eccbuf; // pack bits into frame avoiding masked area.
  406. x = y = width - 1;
  407. k = v = 1; // up, minus
  408. /* inteleaved data and ecc codes */
  409. m = (datablkw + eccblkwid) * (neccblk1 + neccblk2) + neccblk2;
  410. for (i = 0; i < m; i++) {
  411. t = strinbuf[i];
  412. for (j = 0; j < 8; j++, t <<= 1) {
  413. if (0x80 & t) qrframe[x + width * y] = 1;
  414. do {
  415. // find next fill position
  416. if (v) x--;else {
  417. x++;
  418. if (k) {
  419. if (y != 0) y--;else {
  420. x -= 2;
  421. k = !k;
  422. if (x == 6) {
  423. x--;
  424. y = 9;
  425. }
  426. }
  427. } else if (y != width - 1) y++;else {
  428. x -= 2;
  429. k = !k;
  430. if (x == 6) {
  431. x--;
  432. y -= 8;
  433. }
  434. }
  435. }
  436. v = !v;
  437. } while (ismasked(x, y));
  438. }
  439. } // save pre-mask copy of frame
  440. strinbuf = qrframe.slice(0);
  441. t = 0; // best
  442. y = 30000; // demerit
  443. // for instead of while since in original arduino code
  444. // if an early mask was "good enough" it wouldn't try for a better one
  445. // since they get more complex and take longer.
  446. for (k = 0; k < 8; k++) {
  447. applymask(k); // returns black-white imbalance
  448. x = badcheck();
  449. if (x < y) {
  450. // current mask better than previous best?
  451. y = x;
  452. t = k;
  453. }
  454. if (t == 7) break; // don't increment i to a void redoing mask
  455. qrframe = strinbuf.slice(0); // reset for next pass
  456. }
  457. if (t != k) // redo best mask - none good enough, last wasn't t
  458. {
  459. applymask(t);
  460. } // add in final mask/ecclevel bytes
  461. y = fmtword[t + (ecclevel - 1 << 3)]; // low byte
  462. for (k = 0; k < 8; k++, y >>= 1) {
  463. if (y & 1) {
  464. qrframe[width - 1 - k + width * 8] = 1;
  465. if (k < 6) qrframe[8 + width * k] = 1;else qrframe[8 + width * (k + 1)] = 1;
  466. }
  467. } // high byte
  468. for (k = 0; k < 7; k++, y >>= 1) {
  469. if (y & 1) {
  470. qrframe[8 + width * (width - 7 + k)] = 1;
  471. if (k) qrframe[6 - k + width * 8] = 1;else qrframe[7 + width * 8] = 1;
  472. }
  473. } // return image
  474. return qrframe;
  475. }
  476. let _canvas = null;
  477. let _size = null;
  478. const api = {
  479. get ecclevel() {
  480. return ecclevel;
  481. },
  482. set ecclevel(val) {
  483. ecclevel = val;
  484. },
  485. get size() {
  486. return _size;
  487. },
  488. set size(val) {
  489. _size = val;
  490. },
  491. get canvas() {
  492. return _canvas;
  493. },
  494. set canvas(el) {
  495. _canvas = el;
  496. },
  497. getFrame(string) {
  498. return genframe(string);
  499. },
  500. draw(string, canvas, size, ecc) {
  501. ecclevel = ecc || ecclevel;
  502. canvas = canvas || _canvas;
  503. if (!canvas) {
  504. console.warn('No canvas provided to draw QR code in!');
  505. return;
  506. }
  507. size = size || _size || Math.min(canvas.width, canvas.height);
  508. const frame = genframe(string);
  509. const {
  510. ctx
  511. } = canvas;
  512. const px = Math.round(size / (width + 8));
  513. const roundedSize = px * (width + 8);
  514. const offset = Math.floor((size - roundedSize) / 2);
  515. size = roundedSize;
  516. ctx.clearRect(0, 0, canvas.width, canvas.height);
  517. ctx.setFillStyle('#000000');
  518. for (let i = 0; i < width; i++) {
  519. for (let j = 0; j < width; j++) {
  520. if (frame[j * width + i]) {
  521. ctx.fillRect(px * (4 + i) + offset, px * (4 + j) + offset, px, px);
  522. }
  523. }
  524. }
  525. ctx.draw();
  526. }
  527. };
  528. module.exports = {
  529. api
  530. };
  531. }();