QR Code Generator

Generate QR Code for any string.

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.cn-greasyfork.org/scripts/535813/1589729/QR%20Code%20Generator.js

  1. // ==UserScript==
  2. // @name QR Code Generator
  3. // @namespace https://naeembolchhi.github.io/
  4. // @version 0.2
  5. // @description Generate QR Code for any string.
  6. // @author NaeemBolchhi
  7. // @license GPL-3.0
  8. // @grant none
  9. // ==/UserScript==
  10.  
  11. /* QR Code Generator
  12. * https://github.com/NaeemBolchhi/qrcodegen
  13.  
  14. * This project is licensed under GPL-3.0.
  15. * https://raw.githubusercontent.com/NaeemBolchhi/qrcodegen/refs/heads/main/LICENSE
  16. */
  17.  
  18. // alignment pattern
  19. adelta = [
  20. 0, 11, 15, 19, 23, 27, 31, // force 1 pat
  21. 16, 18, 20, 22, 24, 26, 28, 20, 22, 24, 24, 26, 28, 28, 22, 24, 24,
  22. 26, 26, 28, 28, 24, 24, 26, 26, 26, 28, 28, 24, 26, 26, 26, 28, 28
  23. ];
  24.  
  25. // version block
  26. vpat = [
  27. 0xc94, 0x5bc, 0xa99, 0x4d3, 0xbf6, 0x762, 0x847, 0x60d,
  28. 0x928, 0xb78, 0x45d, 0xa17, 0x532, 0x9a6, 0x683, 0x8c9,
  29. 0x7ec, 0xec4, 0x1e1, 0xfab, 0x08e, 0xc1a, 0x33f, 0xd75,
  30. 0x250, 0x9d5, 0x6f0, 0x8ba, 0x79f, 0xb0b, 0x42e, 0xa64,
  31. 0x541, 0xc69
  32. ];
  33.  
  34. // final format bits with mask: level << 3 | mask
  35. fmtword = [
  36. 0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976, //L
  37. 0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0, //M
  38. 0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed, //Q
  39. 0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b //H
  40. ];
  41.  
  42. // 4 per version: number of blocks 1,2; data width; ecc width
  43. eccblocks = [
  44. 1, 0, 19, 7, 1, 0, 16, 10, 1, 0, 13, 13, 1, 0, 9, 17,
  45. 1, 0, 34, 10, 1, 0, 28, 16, 1, 0, 22, 22, 1, 0, 16, 28,
  46. 1, 0, 55, 15, 1, 0, 44, 26, 2, 0, 17, 18, 2, 0, 13, 22,
  47. 1, 0, 80, 20, 2, 0, 32, 18, 2, 0, 24, 26, 4, 0, 9, 16,
  48. 1, 0, 108, 26, 2, 0, 43, 24, 2, 2, 15, 18, 2, 2, 11, 22,
  49. 2, 0, 68, 18, 4, 0, 27, 16, 4, 0, 19, 24, 4, 0, 15, 28,
  50. 2, 0, 78, 20, 4, 0, 31, 18, 2, 4, 14, 18, 4, 1, 13, 26,
  51. 2, 0, 97, 24, 2, 2, 38, 22, 4, 2, 18, 22, 4, 2, 14, 26,
  52. 2, 0, 116, 30, 3, 2, 36, 22, 4, 4, 16, 20, 4, 4, 12, 24,
  53. 2, 2, 68, 18, 4, 1, 43, 26, 6, 2, 19, 24, 6, 2, 15, 28,
  54. 4, 0, 81, 20, 1, 4, 50, 30, 4, 4, 22, 28, 3, 8, 12, 24,
  55. 2, 2, 92, 24, 6, 2, 36, 22, 4, 6, 20, 26, 7, 4, 14, 28,
  56. 4, 0, 107, 26, 8, 1, 37, 22, 8, 4, 20, 24, 12, 4, 11, 22,
  57. 3, 1, 115, 30, 4, 5, 40, 24, 11, 5, 16, 20, 11, 5, 12, 24,
  58. 5, 1, 87, 22, 5, 5, 41, 24, 5, 7, 24, 30, 11, 7, 12, 24,
  59. 5, 1, 98, 24, 7, 3, 45, 28, 15, 2, 19, 24, 3, 13, 15, 30,
  60. 1, 5, 107, 28, 10, 1, 46, 28, 1, 15, 22, 28, 2, 17, 14, 28,
  61. 5, 1, 120, 30, 9, 4, 43, 26, 17, 1, 22, 28, 2, 19, 14, 28,
  62. 3, 4, 113, 28, 3, 11, 44, 26, 17, 4, 21, 26, 9, 16, 13, 26,
  63. 3, 5, 107, 28, 3, 13, 41, 26, 15, 5, 24, 30, 15, 10, 15, 28,
  64. 4, 4, 116, 28, 17, 0, 42, 26, 17, 6, 22, 28, 19, 6, 16, 30,
  65. 2, 7, 111, 28, 17, 0, 46, 28, 7, 16, 24, 30, 34, 0, 13, 24,
  66. 4, 5, 121, 30, 4, 14, 47, 28, 11, 14, 24, 30, 16, 14, 15, 30,
  67. 6, 4, 117, 30, 6, 14, 45, 28, 11, 16, 24, 30, 30, 2, 16, 30,
  68. 8, 4, 106, 26, 8, 13, 47, 28, 7, 22, 24, 30, 22, 13, 15, 30,
  69. 10, 2, 114, 28, 19, 4, 46, 28, 28, 6, 22, 28, 33, 4, 16, 30,
  70. 8, 4, 122, 30, 22, 3, 45, 28, 8, 26, 23, 30, 12, 28, 15, 30,
  71. 3, 10, 117, 30, 3, 23, 45, 28, 4, 31, 24, 30, 11, 31, 15, 30,
  72. 7, 7, 116, 30, 21, 7, 45, 28, 1, 37, 23, 30, 19, 26, 15, 30,
  73. 5, 10, 115, 30, 19, 10, 47, 28, 15, 25, 24, 30, 23, 25, 15, 30,
  74. 13, 3, 115, 30, 2, 29, 46, 28, 42, 1, 24, 30, 23, 28, 15, 30,
  75. 17, 0, 115, 30, 10, 23, 46, 28, 10, 35, 24, 30, 19, 35, 15, 30,
  76. 17, 1, 115, 30, 14, 21, 46, 28, 29, 19, 24, 30, 11, 46, 15, 30,
  77. 13, 6, 115, 30, 14, 23, 46, 28, 44, 7, 24, 30, 59, 1, 16, 30,
  78. 12, 7, 121, 30, 12, 26, 47, 28, 39, 14, 24, 30, 22, 41, 15, 30,
  79. 6, 14, 121, 30, 6, 34, 47, 28, 46, 10, 24, 30, 2, 64, 15, 30,
  80. 17, 4, 122, 30, 29, 14, 46, 28, 49, 10, 24, 30, 24, 46, 15, 30,
  81. 4, 18, 122, 30, 13, 32, 46, 28, 48, 14, 24, 30, 42, 32, 15, 30,
  82. 20, 4, 117, 30, 40, 7, 47, 28, 43, 22, 24, 30, 10, 67, 15, 30,
  83. 19, 6, 118, 30, 18, 31, 47, 28, 34, 34, 24, 30, 20, 61, 15, 30
  84. ];
  85.  
  86. // Galois field log table
  87. glog = [
  88. 0xff, 0x00, 0x01, 0x19, 0x02, 0x32, 0x1a, 0xc6, 0x03, 0xdf, 0x33, 0xee, 0x1b, 0x68, 0xc7, 0x4b,
  89. 0x04, 0x64, 0xe0, 0x0e, 0x34, 0x8d, 0xef, 0x81, 0x1c, 0xc1, 0x69, 0xf8, 0xc8, 0x08, 0x4c, 0x71,
  90. 0x05, 0x8a, 0x65, 0x2f, 0xe1, 0x24, 0x0f, 0x21, 0x35, 0x93, 0x8e, 0xda, 0xf0, 0x12, 0x82, 0x45,
  91. 0x1d, 0xb5, 0xc2, 0x7d, 0x6a, 0x27, 0xf9, 0xb9, 0xc9, 0x9a, 0x09, 0x78, 0x4d, 0xe4, 0x72, 0xa6,
  92. 0x06, 0xbf, 0x8b, 0x62, 0x66, 0xdd, 0x30, 0xfd, 0xe2, 0x98, 0x25, 0xb3, 0x10, 0x91, 0x22, 0x88,
  93. 0x36, 0xd0, 0x94, 0xce, 0x8f, 0x96, 0xdb, 0xbd, 0xf1, 0xd2, 0x13, 0x5c, 0x83, 0x38, 0x46, 0x40,
  94. 0x1e, 0x42, 0xb6, 0xa3, 0xc3, 0x48, 0x7e, 0x6e, 0x6b, 0x3a, 0x28, 0x54, 0xfa, 0x85, 0xba, 0x3d,
  95. 0xca, 0x5e, 0x9b, 0x9f, 0x0a, 0x15, 0x79, 0x2b, 0x4e, 0xd4, 0xe5, 0xac, 0x73, 0xf3, 0xa7, 0x57,
  96. 0x07, 0x70, 0xc0, 0xf7, 0x8c, 0x80, 0x63, 0x0d, 0x67, 0x4a, 0xde, 0xed, 0x31, 0xc5, 0xfe, 0x18,
  97. 0xe3, 0xa5, 0x99, 0x77, 0x26, 0xb8, 0xb4, 0x7c, 0x11, 0x44, 0x92, 0xd9, 0x23, 0x20, 0x89, 0x2e,
  98. 0x37, 0x3f, 0xd1, 0x5b, 0x95, 0xbc, 0xcf, 0xcd, 0x90, 0x87, 0x97, 0xb2, 0xdc, 0xfc, 0xbe, 0x61,
  99. 0xf2, 0x56, 0xd3, 0xab, 0x14, 0x2a, 0x5d, 0x9e, 0x84, 0x3c, 0x39, 0x53, 0x47, 0x6d, 0x41, 0xa2,
  100. 0x1f, 0x2d, 0x43, 0xd8, 0xb7, 0x7b, 0xa4, 0x76, 0xc4, 0x17, 0x49, 0xec, 0x7f, 0x0c, 0x6f, 0xf6,
  101. 0x6c, 0xa1, 0x3b, 0x52, 0x29, 0x9d, 0x55, 0xaa, 0xfb, 0x60, 0x86, 0xb1, 0xbb, 0xcc, 0x3e, 0x5a,
  102. 0xcb, 0x59, 0x5f, 0xb0, 0x9c, 0xa9, 0xa0, 0x51, 0x0b, 0xf5, 0x16, 0xeb, 0x7a, 0x75, 0x2c, 0xd7,
  103. 0x4f, 0xae, 0xd5, 0xe9, 0xe6, 0xe7, 0xad, 0xe8, 0x74, 0xd6, 0xf4, 0xea, 0xa8, 0x50, 0x58, 0xaf
  104. ];
  105.  
  106. // Galios field exponent table
  107. gexp = [
  108. 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1d, 0x3a, 0x74, 0xe8, 0xcd, 0x87, 0x13, 0x26,
  109. 0x4c, 0x98, 0x2d, 0x5a, 0xb4, 0x75, 0xea, 0xc9, 0x8f, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0,
  110. 0x9d, 0x27, 0x4e, 0x9c, 0x25, 0x4a, 0x94, 0x35, 0x6a, 0xd4, 0xb5, 0x77, 0xee, 0xc1, 0x9f, 0x23,
  111. 0x46, 0x8c, 0x05, 0x0a, 0x14, 0x28, 0x50, 0xa0, 0x5d, 0xba, 0x69, 0xd2, 0xb9, 0x6f, 0xde, 0xa1,
  112. 0x5f, 0xbe, 0x61, 0xc2, 0x99, 0x2f, 0x5e, 0xbc, 0x65, 0xca, 0x89, 0x0f, 0x1e, 0x3c, 0x78, 0xf0,
  113. 0xfd, 0xe7, 0xd3, 0xbb, 0x6b, 0xd6, 0xb1, 0x7f, 0xfe, 0xe1, 0xdf, 0xa3, 0x5b, 0xb6, 0x71, 0xe2,
  114. 0xd9, 0xaf, 0x43, 0x86, 0x11, 0x22, 0x44, 0x88, 0x0d, 0x1a, 0x34, 0x68, 0xd0, 0xbd, 0x67, 0xce,
  115. 0x81, 0x1f, 0x3e, 0x7c, 0xf8, 0xed, 0xc7, 0x93, 0x3b, 0x76, 0xec, 0xc5, 0x97, 0x33, 0x66, 0xcc,
  116. 0x85, 0x17, 0x2e, 0x5c, 0xb8, 0x6d, 0xda, 0xa9, 0x4f, 0x9e, 0x21, 0x42, 0x84, 0x15, 0x2a, 0x54,
  117. 0xa8, 0x4d, 0x9a, 0x29, 0x52, 0xa4, 0x55, 0xaa, 0x49, 0x92, 0x39, 0x72, 0xe4, 0xd5, 0xb7, 0x73,
  118. 0xe6, 0xd1, 0xbf, 0x63, 0xc6, 0x91, 0x3f, 0x7e, 0xfc, 0xe5, 0xd7, 0xb3, 0x7b, 0xf6, 0xf1, 0xff,
  119. 0xe3, 0xdb, 0xab, 0x4b, 0x96, 0x31, 0x62, 0xc4, 0x95, 0x37, 0x6e, 0xdc, 0xa5, 0x57, 0xae, 0x41,
  120. 0x82, 0x19, 0x32, 0x64, 0xc8, 0x8d, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0, 0xdd, 0xa7, 0x53, 0xa6,
  121. 0x51, 0xa2, 0x59, 0xb2, 0x79, 0xf2, 0xf9, 0xef, 0xc3, 0x9b, 0x2b, 0x56, 0xac, 0x45, 0x8a, 0x09,
  122. 0x12, 0x24, 0x48, 0x90, 0x3d, 0x7a, 0xf4, 0xf5, 0xf7, 0xf3, 0xfb, 0xeb, 0xcb, 0x8b, 0x0b, 0x16,
  123. 0x2c, 0x58, 0xb0, 0x7d, 0xfa, 0xe9, 0xcf, 0x83, 0x1b, 0x36, 0x6c, 0xd8, 0xad, 0x47, 0x8e, 0x00
  124. ];
  125.  
  126. // Working buffers:
  127. // data input and ecc append, image working buffer, fixed part of image, run lengths for badness
  128. var strinbuf=[], eccbuf=[], qrframe=[], framask=[], rlens=[];
  129. // Control values - width is based on version, last 4 are from table.
  130. var version, width, neccblk1, neccblk2, datablkw, eccblkwid;
  131. var ecclevel = 1;
  132. // set bit to indicate cell in qrframe is immutable. symmetric around diagonal
  133. function setmask(x, y)
  134. {
  135. var bt;
  136. if (x > y) {
  137. bt = x;
  138. x = y;
  139. y = bt;
  140. }
  141. // y*y = 1+3+5...
  142. bt = y;
  143. bt *= y;
  144. bt += y;
  145. bt >>= 1;
  146. bt += x;
  147. framask[bt] = 1;
  148. }
  149.  
  150. // enter alignment pattern - black to qrframe, white to mask (later black frame merged to mask)
  151. function putalign(x, y)
  152. {
  153. var j;
  154.  
  155. qrframe[x + width * y] = 1;
  156. for (j = -2; j < 2; j++) {
  157. qrframe[(x + j) + width * (y - 2)] = 1;
  158. qrframe[(x - 2) + width * (y + j + 1)] = 1;
  159. qrframe[(x + 2) + width * (y + j)] = 1;
  160. qrframe[(x + j + 1) + width * (y + 2)] = 1;
  161. }
  162. for (j = 0; j < 2; j++) {
  163. setmask(x - 1, y + j);
  164. setmask(x + 1, y - j);
  165. setmask(x - j, y - 1);
  166. setmask(x + j, y + 1);
  167. }
  168. }
  169.  
  170. //========================================================================
  171. // Reed Solomon error correction
  172. // exponentiation mod N
  173. function modnn(x)
  174. {
  175. while (x >= 255) {
  176. x -= 255;
  177. x = (x >> 8) + (x & 255);
  178. }
  179. return x;
  180. }
  181.  
  182. var genpoly = [];
  183.  
  184. // Calculate and append ECC data to data block. Block is in strinbuf, indexes to buffers given.
  185. function appendrs(data, dlen, ecbuf, eclen)
  186. {
  187. var i, j, fb;
  188.  
  189. for (i = 0; i < eclen; i++)
  190. strinbuf[ecbuf + i] = 0;
  191. for (i = 0; i < dlen; i++) {
  192. fb = glog[strinbuf[data + i] ^ strinbuf[ecbuf]];
  193. if (fb != 255) /* fb term is non-zero */
  194. for (j = 1; j < eclen; j++)
  195. strinbuf[ecbuf + j - 1] = strinbuf[ecbuf + j] ^ gexp[modnn(fb + genpoly[eclen - j])];
  196. else
  197. for( j = ecbuf ; j < ecbuf + eclen; j++ )
  198. strinbuf[j] = strinbuf[j + 1];
  199. strinbuf[ ecbuf + eclen - 1] = fb == 255 ? 0 : gexp[modnn(fb + genpoly[0])];
  200. }
  201. }
  202.  
  203. //========================================================================
  204. // Frame data insert following the path rules
  205.  
  206. // check mask - since symmetrical use half.
  207. function ismasked(x, y)
  208. {
  209. var bt;
  210. if (x > y) {
  211. bt = x;
  212. x = y;
  213. y = bt;
  214. }
  215. bt = y;
  216. bt += y * y;
  217. bt >>= 1;
  218. bt += x;
  219. return framask[bt];
  220. }
  221.  
  222. //========================================================================
  223. // Apply the selected mask out of the 8.
  224. function applymask(m)
  225. {
  226. var x, y, r3x, r3y;
  227.  
  228. switch (m) {
  229. case 0:
  230. for (y = 0; y < width; y++)
  231. for (x = 0; x < width; x++)
  232. if (!((x + y) & 1) && !ismasked(x, y))
  233. qrframe[x + y * width] ^= 1;
  234. break;
  235. case 1:
  236. for (y = 0; y < width; y++)
  237. for (x = 0; x < width; x++)
  238. if (!(y & 1) && !ismasked(x, y))
  239. qrframe[x + y * width] ^= 1;
  240. break;
  241. case 2:
  242. for (y = 0; y < width; y++)
  243. for (r3x = 0, x = 0; x < width; x++, r3x++) {
  244. if (r3x == 3)
  245. r3x = 0;
  246. if (!r3x && !ismasked(x, y))
  247. qrframe[x + y * width] ^= 1;
  248. }
  249. break;
  250. case 3:
  251. for (r3y = 0, y = 0; y < width; y++, r3y++) {
  252. if (r3y == 3)
  253. r3y = 0;
  254. for (r3x = r3y, x = 0; x < width; x++, r3x++) {
  255. if (r3x == 3)
  256. r3x = 0;
  257. if (!r3x && !ismasked(x, y))
  258. qrframe[x + y * width] ^= 1;
  259. }
  260. }
  261. break;
  262. case 4:
  263. for (y = 0; y < width; y++)
  264. for (r3x = 0, r3y = ((y >> 1) & 1), x = 0; x < width; x++, r3x++) {
  265. if (r3x == 3) {
  266. r3x = 0;
  267. r3y = !r3y;
  268. }
  269. if (!r3y && !ismasked(x, y))
  270. qrframe[x + y * width] ^= 1;
  271. }
  272. break;
  273. case 5:
  274. for (r3y = 0, y = 0; y < width; y++, r3y++) {
  275. if (r3y == 3)
  276. r3y = 0;
  277. for (r3x = 0, x = 0; x < width; x++, r3x++) {
  278. if (r3x == 3)
  279. r3x = 0;
  280. if (!((x & y & 1) + !(!r3x | !r3y)) && !ismasked(x, y))
  281. qrframe[x + y * width] ^= 1;
  282. }
  283. }
  284. break;
  285. case 6:
  286. for (r3y = 0, y = 0; y < width; y++, r3y++) {
  287. if (r3y == 3)
  288. r3y = 0;
  289. for (r3x = 0, x = 0; x < width; x++, r3x++) {
  290. if (r3x == 3)
  291. r3x = 0;
  292. if (!(((x & y & 1) + (r3x && (r3x == r3y))) & 1) && !ismasked(x, y))
  293. qrframe[x + y * width] ^= 1;
  294. }
  295. }
  296. break;
  297. case 7:
  298. for (r3y = 0, y = 0; y < width; y++, r3y++) {
  299. if (r3y == 3)
  300. r3y = 0;
  301. for (r3x = 0, x = 0; x < width; x++, r3x++) {
  302. if (r3x == 3)
  303. r3x = 0;
  304. if (!(((r3x && (r3x == r3y)) + ((x + y) & 1)) & 1) && !ismasked(x, y))
  305. qrframe[x + y * width] ^= 1;
  306. }
  307. }
  308. break;
  309. }
  310. return;
  311. }
  312.  
  313. // Badness coefficients.
  314. var N1 = 3, N2 = 3, N3 = 40, N4 = 10;
  315.  
  316. // Using the table of the length of each run, calculate the amount of bad image
  317. // - long runs or those that look like finders; called twice, once each for X and Y
  318. function badruns(length)
  319. {
  320. var i;
  321. var runsbad = 0;
  322. for (i = 0; i <= length; i++)
  323. if (rlens[i] >= 5)
  324. runsbad += N1 + rlens[i] - 5;
  325. // BwBBBwB as in finder
  326. for (i = 3; i < length - 1; i += 2)
  327. if (rlens[i - 2] == rlens[i + 2]
  328. && rlens[i + 2] == rlens[i - 1]
  329. && rlens[i - 1] == rlens[i + 1]
  330. && rlens[i - 1] * 3 == rlens[i]
  331. // white around the black pattern? Not part of spec
  332. && (rlens[i - 3] == 0 // beginning
  333. || i + 3 > length // end
  334. || rlens[i - 3] * 3 >= rlens[i] * 4 || rlens[i + 3] * 3 >= rlens[i] * 4)
  335. )
  336. runsbad += N3;
  337. return runsbad;
  338. }
  339.  
  340. // Calculate how bad the masked image is - blocks, imbalance, runs, or finders.
  341. function badcheck()
  342. {
  343. var x, y, h, b, b1;
  344. var thisbad = 0;
  345. var bw = 0;
  346.  
  347. // blocks of same color.
  348. for (y = 0; y < width - 1; y++)
  349. for (x = 0; x < width - 1; x++)
  350. if ((qrframe[x + width * y] && qrframe[(x + 1) + width * y]
  351. && qrframe[x + width * (y + 1)] && qrframe[(x + 1) + width * (y + 1)]) // all black
  352. || !(qrframe[x + width * y] || qrframe[(x + 1) + width * y]
  353. || qrframe[x + width * (y + 1)] || qrframe[(x + 1) + width * (y + 1)])) // all white
  354. thisbad += N2;
  355.  
  356. // X runs
  357. for (y = 0; y < width; y++) {
  358. rlens[0] = 0;
  359. for (h = b = x = 0; x < width; x++) {
  360. if ((b1 = qrframe[x + width * y]) == b)
  361. rlens[h]++;
  362. else
  363. rlens[++h] = 1;
  364. b = b1;
  365. bw += b ? 1 : -1;
  366. }
  367. thisbad += badruns(h);
  368. }
  369.  
  370. // black/white imbalance
  371. if (bw < 0)
  372. bw = -bw;
  373.  
  374. var big = bw;
  375. count = 0;
  376. big += big << 2;
  377. big <<= 1;
  378. while (big > width * width)
  379. big -= width * width, count++;
  380. thisbad += count * N4;
  381.  
  382. // Y runs
  383. for (x = 0; x < width; x++) {
  384. rlens[0] = 0;
  385. for (h = b = y = 0; y < width; y++) {
  386. if ((b1 = qrframe[x + width * y]) == b)
  387. rlens[h]++;
  388. else
  389. rlens[++h] = 1;
  390. b = b1;
  391. }
  392. thisbad += badruns(h);
  393. }
  394. return thisbad;
  395. }
  396.  
  397. function genframe(instring)
  398. {
  399. var x, y, k, t, v, i, j, m;
  400.  
  401. // find the smallest version that fits the string
  402. t = instring.length;
  403. version = 0;
  404. do {
  405. version++;
  406. k = (ecclevel - 1) * 4 + (version - 1) * 16;
  407. neccblk1 = eccblocks[k++];
  408. neccblk2 = eccblocks[k++];
  409. datablkw = eccblocks[k++];
  410. eccblkwid = eccblocks[k];
  411. k = datablkw * (neccblk1 + neccblk2) + neccblk2 - 3 + (version <= 9);
  412. if (t <= k)
  413. break;
  414. } while (version < 40);
  415.  
  416. // FIXME - insure that it fits insted of being truncated
  417. width = 17 + 4 * version;
  418.  
  419. // allocate, clear and setup data structures
  420. v = datablkw + (datablkw + eccblkwid) * (neccblk1 + neccblk2) + neccblk2;
  421. for( t = 0; t < v; t++ )
  422. eccbuf[t] = 0;
  423. strinbuf = instring.slice(0);
  424.  
  425. for( t = 0; t < width * width; t++ )
  426. qrframe[t] = 0;
  427.  
  428. for( t = 0 ; t < (width * (width + 1) + 1) / 2; t++)
  429. framask[t] = 0;
  430.  
  431. // insert finders - black to frame, white to mask
  432. for (t = 0; t < 3; t++) {
  433. k = 0;
  434. y = 0;
  435. if (t == 1)
  436. k = (width - 7);
  437. if (t == 2)
  438. y = (width - 7);
  439. qrframe[(y + 3) + width * (k + 3)] = 1;
  440. for (x = 0; x < 6; x++) {
  441. qrframe[(y + x) + width * k] = 1;
  442. qrframe[y + width * (k + x + 1)] = 1;
  443. qrframe[(y + 6) + width * (k + x)] = 1;
  444. qrframe[(y + x + 1) + width * (k + 6)] = 1;
  445. }
  446. for (x = 1; x < 5; x++) {
  447. setmask(y + x, k + 1);
  448. setmask(y + 1, k + x + 1);
  449. setmask(y + 5, k + x);
  450. setmask(y + x + 1, k + 5);
  451. }
  452. for (x = 2; x < 4; x++) {
  453. qrframe[(y + x) + width * (k + 2)] = 1;
  454. qrframe[(y + 2) + width * (k + x + 1)] = 1;
  455. qrframe[(y + 4) + width * (k + x)] = 1;
  456. qrframe[(y + x + 1) + width * (k + 4)] = 1;
  457. }
  458. }
  459.  
  460. // alignment blocks
  461. if (version > 1) {
  462. t = adelta[version];
  463. y = width - 7;
  464. for (;;) {
  465. x = width - 7;
  466. while (x > t - 3) {
  467. putalign(x, y);
  468. if (x < t)
  469. break;
  470. x -= t;
  471. }
  472. if (y <= t + 9)
  473. break;
  474. y -= t;
  475. putalign(6, y);
  476. putalign(y, 6);
  477. }
  478. }
  479.  
  480. // single black
  481. qrframe[8 + width * (width - 8)] = 1;
  482.  
  483. // timing gap - mask only
  484. for (y = 0; y < 7; y++) {
  485. setmask(7, y);
  486. setmask(width - 8, y);
  487. setmask(7, y + width - 7);
  488. }
  489. for (x = 0; x < 8; x++) {
  490. setmask(x, 7);
  491. setmask(x + width - 8, 7);
  492. setmask(x, width - 8);
  493. }
  494.  
  495. // reserve mask-format area
  496. for (x = 0; x < 9; x++)
  497. setmask(x, 8);
  498. for (x = 0; x < 8; x++) {
  499. setmask(x + width - 8, 8);
  500. setmask(8, x);
  501. }
  502. for (y = 0; y < 7; y++)
  503. setmask(8, y + width - 7);
  504.  
  505. // timing row/col
  506. for (x = 0; x < width - 14; x++)
  507. if (x & 1) {
  508. setmask(8 + x, 6);
  509. setmask(6, 8 + x);
  510. }
  511. else {
  512. qrframe[(8 + x) + width * 6] = 1;
  513. qrframe[6 + width * (8 + x)] = 1;
  514. }
  515.  
  516. // version block
  517. if (version > 6) {
  518. t = vpat[version - 7];
  519. k = 17;
  520. for (x = 0; x < 6; x++)
  521. for (y = 0; y < 3; y++, k--)
  522. if (1 & (k > 11 ? version >> (k - 12) : t >> k)) {
  523. qrframe[(5 - x) + width * (2 - y + width - 11)] = 1;
  524. qrframe[(2 - y + width - 11) + width * (5 - x)] = 1;
  525. }
  526. else {
  527. setmask(5 - x, 2 - y + width - 11);
  528. setmask(2 - y + width - 11, 5 - x);
  529. }
  530. }
  531.  
  532. // sync mask bits - only set above for white spaces, so add in black bits
  533. for (y = 0; y < width; y++)
  534. for (x = 0; x <= y; x++)
  535. if (qrframe[x + width * y])
  536. setmask(x, y);
  537.  
  538. // convert string to bitstream
  539. // 8 bit data to QR-coded 8 bit data (numeric or alphanum, or kanji not supported)
  540. v = strinbuf.length;
  541.  
  542. // string to array
  543. for( i = 0 ; i < v; i++ )
  544. eccbuf[i] = strinbuf.charCodeAt(i);
  545. strinbuf = eccbuf.slice(0);
  546.  
  547. // calculate max string length
  548. x = datablkw * (neccblk1 + neccblk2) + neccblk2;
  549. if (v >= x - 2) {
  550. v = x - 2;
  551. if (version > 9)
  552. v--;
  553. }
  554.  
  555. // shift and repack to insert length prefix
  556. i = v;
  557. if (version > 9) {
  558. strinbuf[i + 2] = 0;
  559. strinbuf[i + 3] = 0;
  560. while (i--) {
  561. t = strinbuf[i];
  562. strinbuf[i + 3] |= 255 & (t << 4);
  563. strinbuf[i + 2] = t >> 4;
  564. }
  565. strinbuf[2] |= 255 & (v << 4);
  566. strinbuf[1] = v >> 4;
  567. strinbuf[0] = 0x40 | (v >> 12);
  568. }
  569. else {
  570. strinbuf[i + 1] = 0;
  571. strinbuf[i + 2] = 0;
  572. while (i--) {
  573. t = strinbuf[i];
  574. strinbuf[i + 2] |= 255 & (t << 4);
  575. strinbuf[i + 1] = t >> 4;
  576. }
  577. strinbuf[1] |= 255 & (v << 4);
  578. strinbuf[0] = 0x40 | (v >> 4);
  579. }
  580. // fill to end with pad pattern
  581. i = v + 3 - (version < 10);
  582. while (i < x) {
  583. strinbuf[i++] = 0xec;
  584. // buffer has room if (i == x) break;
  585. strinbuf[i++] = 0x11;
  586. }
  587.  
  588. // calculate and append ECC
  589.  
  590. // calculate generator polynomial
  591. genpoly[0] = 1;
  592. for (i = 0; i < eccblkwid; i++) {
  593. genpoly[i + 1] = 1;
  594. for (j = i; j > 0; j--)
  595. genpoly[j] = genpoly[j]
  596. ? genpoly[j - 1] ^ gexp[modnn(glog[genpoly[j]] + i)] : genpoly[j - 1];
  597. genpoly[0] = gexp[modnn(glog[genpoly[0]] + i)];
  598. }
  599. for (i = 0; i <= eccblkwid; i++)
  600. genpoly[i] = glog[genpoly[i]]; // use logs for genpoly[] to save calc step
  601.  
  602. // append ecc to data buffer
  603. k = x;
  604. y = 0;
  605. for (i = 0; i < neccblk1; i++) {
  606. appendrs(y, datablkw, k, eccblkwid);
  607. y += datablkw;
  608. k += eccblkwid;
  609. }
  610. for (i = 0; i < neccblk2; i++) {
  611. appendrs(y, datablkw + 1, k, eccblkwid);
  612. y += datablkw + 1;
  613. k += eccblkwid;
  614. }
  615. // interleave blocks
  616. y = 0;
  617. for (i = 0; i < datablkw; i++) {
  618. for (j = 0; j < neccblk1; j++)
  619. eccbuf[y++] = strinbuf[i + j * datablkw];
  620. for (j = 0; j < neccblk2; j++)
  621. eccbuf[y++] = strinbuf[(neccblk1 * datablkw) + i + (j * (datablkw + 1))];
  622. }
  623. for (j = 0; j < neccblk2; j++)
  624. eccbuf[y++] = strinbuf[(neccblk1 * datablkw) + i + (j * (datablkw + 1))];
  625. for (i = 0; i < eccblkwid; i++)
  626. for (j = 0; j < neccblk1 + neccblk2; j++)
  627. eccbuf[y++] = strinbuf[x + i + j * eccblkwid];
  628. strinbuf = eccbuf;
  629.  
  630. // pack bits into frame avoiding masked area.
  631. x = y = width - 1;
  632. k = v = 1; // up, minus
  633. /* inteleaved data and ecc codes */
  634. m = (datablkw + eccblkwid) * (neccblk1 + neccblk2) + neccblk2;
  635. for (i = 0; i < m; i++) {
  636. t = strinbuf[i];
  637. for (j = 0; j < 8; j++, t <<= 1) {
  638. if (0x80 & t)
  639. qrframe[x + width * y] = 1;
  640. do { // find next fill position
  641. if (v)
  642. x--;
  643. else {
  644. x++;
  645. if (k) {
  646. if (y != 0)
  647. y--;
  648. else {
  649. x -= 2;
  650. k = !k;
  651. if (x == 6) {
  652. x--;
  653. y = 9;
  654. }
  655. }
  656. }
  657. else {
  658. if (y != width - 1)
  659. y++;
  660. else {
  661. x -= 2;
  662. k = !k;
  663. if (x == 6) {
  664. x--;
  665. y -= 8;
  666. }
  667. }
  668. }
  669. }
  670. v = !v;
  671. } while (ismasked(x, y));
  672. }
  673. }
  674.  
  675. // save pre-mask copy of frame
  676. strinbuf = qrframe.slice(0);
  677. t = 0; // best
  678. y = 30000; // demerit
  679. // for instead of while since in original arduino code
  680. // if an early mask was "good enough" it wouldn't try for a better one
  681. // since they get more complex and take longer.
  682. for (k = 0; k < 8; k++) {
  683. applymask(k); // returns black-white imbalance
  684. x = badcheck();
  685. if (x < y) { // current mask better than previous best?
  686. y = x;
  687. t = k;
  688. }
  689. if (t == 7)
  690. break; // don't increment i to a void redoing mask
  691. qrframe = strinbuf.slice(0); // reset for next pass
  692. }
  693. if (t != k) // redo best mask - none good enough, last wasn't t
  694. applymask(t);
  695.  
  696. // add in final mask/ecclevel bytes
  697. y = fmtword[t + ((ecclevel - 1) << 3)];
  698. // low byte
  699. for (k = 0; k < 8; k++, y >>= 1)
  700. if (y & 1) {
  701. qrframe[(width - 1 - k) + width * 8] = 1;
  702. if (k < 6)
  703. qrframe[8 + width * k] = 1;
  704. else
  705. qrframe[8 + width * (k + 1)] = 1;
  706. }
  707. // high byte
  708. for (k = 0; k < 7; k++, y >>= 1)
  709. if (y & 1) {
  710. qrframe[8 + width * (width - 7 + k)] = 1;
  711. if (k)
  712. qrframe[(6 - k) + width * 8] = 1;
  713. else
  714. qrframe[7 + width * 8] = 1;
  715. }
  716.  
  717. // return image
  718. return qrframe;
  719. }
  720.  
  721. var wd, ht, qrc;
  722. function setupqr(container) {
  723. window.scrollTo(0,1)
  724. // wd = window.innerWidth-10;
  725. // ht = window.innerHeight-10;
  726. wd = 1000;
  727. ht = 1000;
  728.  
  729. // wd -= 4;
  730. // ht -= 80;
  731.  
  732. createCanvas(container);
  733.  
  734. var elem = document.getElementById('qrcanv');
  735. qrc = elem.getContext('2d');
  736. // qrc.canvas.width = wd;
  737. // qrc.canvas.height = ht;
  738. qrc.fillStyle = '#eee';
  739. qrc.fillRect(0,0,wd,ht);
  740. }
  741.  
  742. function createCanvas(container) {
  743. try {document.getElementById('qrcanv').remove();} catch {}
  744.  
  745. let canvas = document.createElement('canvas');
  746. canvas.id = 'qrcanv';
  747. canvas.setAttribute('width', '2000');
  748. canvas.setAttribute('height', '2000');
  749. canvas.setAttribute('style','position:fixed;left:-2000px;top:-2000px');
  750. canvas.textContent = 'No Canvas Support?';
  751. container.appendChild(canvas);
  752. }
  753.  
  754. function doqr(string, eccval, bg, fg, container) {
  755. // createCanvas();
  756. setupqr(container);
  757. d = document;
  758. ecclevel = eccval;
  759. qf = genframe(string);
  760. qrc.lineWidth=1;
  761.  
  762. px = wd;
  763. if (ht < wd) {px = ht;}
  764. px /= width;
  765. px=Math.round(px);
  766. qrc.clearRect(0,0,wd,ht);
  767. qrc.fillStyle = bg;
  768. // qrc.fillRect(0,0,px*(width+8),px*(width+8));
  769. qrc.fillRect(0,0,px*width,px*width);
  770.  
  771. qrc.fillStyle = fg;
  772. for (let i = 0; i < width; i++ ) {
  773. for (let j = 0; j < width; j++ ) {
  774. if (qf[j*width+i]) {
  775. // qrc.fillRect(px*(4+i),px*(4+j),px,px);
  776. qrc.fillRect(px*i,px*j,px,px);
  777. }
  778. }
  779. }
  780.  
  781. let img = document.createElement('img');
  782. newCanvas = trimCanvas(document.getElementById('qrcanv'));
  783. img.src = newCanvas.toDataURL("image/png");
  784. container.textContent = '';
  785. container.appendChild(img);
  786. container.appendChild(newCanvas);
  787. }
  788.  
  789. /* The Trim Canvas function is MIT.
  790. * http://rem.mit-license.org
  791. * Taken from Our Code World.
  792. * https://ourcodeworld.com/articles/read/683/how-to-remove-the-transparent-pixels-that-surrounds-a-canvas-in-javascript
  793. */
  794. function trimCanvas(c) {
  795. var ctx = c.getContext('2d'),
  796. copy = document.createElement('canvas').getContext('2d'),
  797. pixels = ctx.getImageData(0, 0, c.width, c.height),
  798. l = pixels.data.length,
  799. i,
  800. bound = {
  801. top: null,
  802. left: null,
  803. right: null,
  804. bottom: null
  805. },
  806. x, y;
  807. // Iterate over every pixel to find the highest
  808. // and where it ends on every axis ()
  809. for (i = 0; i < l; i += 4) {
  810. if (pixels.data[i + 3] !== 0) {
  811. x = (i / 4) % c.width;
  812. y = ~~((i / 4) / c.width);
  813.  
  814. if (bound.top === null) {
  815. bound.top = y;
  816. }
  817.  
  818. if (bound.left === null) {
  819. bound.left = x;
  820. } else if (x < bound.left) {
  821. bound.left = x;
  822. }
  823.  
  824. if (bound.right === null) {
  825. bound.right = x;
  826. } else if (bound.right < x) {
  827. bound.right = x;
  828. }
  829.  
  830. if (bound.bottom === null) {
  831. bound.bottom = y;
  832. } else if (bound.bottom < y) {
  833. bound.bottom = y;
  834. }
  835. }
  836. }
  837. // Calculate the height and width of the content
  838. var trimHeight = bound.bottom - bound.top,
  839. trimWidth = bound.right - bound.left,
  840. trimmed = ctx.getImageData(bound.left, bound.top, trimWidth, trimHeight);
  841.  
  842. copy.canvas.width = trimWidth;
  843. copy.canvas.height = trimHeight;
  844. copy.putImageData(trimmed, 0, 0);
  845.  
  846. // Return trimmed canvas
  847. return copy.canvas;
  848. }