当前位置:   article > 正文

小程序实现二维码条形码生成_drawqrcode

drawqrcode

  1. <!--index.wxml-->
  2. <view class="container page">
  3. <view class="panel">
  4. <view class="header">
  5. </view>
  6. <view class="barcode">
  7. <view class="barnum">{{code}}</view>
  8. <canvas canvas-id="barcode" />
  9. </view>
  10. <view class="qrcode">
  11. <canvas canvas-id="qrcode" />
  12. </view>
  13. </view>
  14. </view>
  15. //index.js
  16. var wxbarcode = require('../../utils/index.js');
  17. Page({
  18. data: {
  19. code: '123456'
  20. },
  21. onLoad: function () {
  22. wxbarcode.barcode('barcode',this.data.code, 680, 200);
  23. wxbarcode.qrcode('qrcode', this.data.code, 420, 420);
  24. }
  25. })
  26. /**index.wxss**/
  27. page {
  28. background-color:pink;
  29. }
  30. .page {
  31. display: flex;
  32. flex-direction: column;
  33. justify-content: center;
  34. align-items: center;
  35. }
  36. .container {
  37. padding-bottom: 10rpx;
  38. }
  39. .panel {
  40. display: flex;
  41. flex-direction: column;
  42. justify-content: space-between;
  43. align-items: stretch;
  44. box-sizing: border-box;
  45. width: 710rpx;
  46. margin-top: 40rpx;
  47. border-radius: 10rpx;
  48. background-color: #fff;
  49. }
  50. .header {
  51. height: 140rpx;
  52. background-color: #f0f0f0;
  53. border-radius: 10rpx 10rpx 0 0;
  54. }
  55. .barcode {
  56. display: flex;
  57. height: 320rpx;
  58. flex-direction: column;
  59. justify-content: center;
  60. align-items: center;
  61. }
  62. .barnum {
  63. width: 670rpx;
  64. height: 100rpx;
  65. line-height: 100rpx;
  66. font-size: 38rpx;
  67. font-weight: bold;
  68. text-align: center;
  69. letter-spacing: 10rpx;
  70. white-space: nowrap;
  71. }
  72. .barcode > canvas {
  73. width: 680rpx;
  74. height: 200rpx;
  75. }
  76. .qrcode {
  77. height: 420rpx;
  78. display: flex;
  79. flex-direction: column;
  80. justify-content: flex-end;
  81. align-items: center;
  82. }
  83. .qrcode > canvas {
  84. width: 420rpx;
  85. height: 420rpx;
  86. }
  1. //index.js
  2. // 数字转换二维码 条形码
  3. var barcode = require('./barcode');
  4. var qrcode = require('./qrcode');
  5. function convert_length(length) {
  6. return Math.round(wx.getSystemInfoSync().windowWidth * length / 750);
  7. }
  8. function barc(id, code, width, height) {
  9. barcode.code128(wx.createCanvasContext(id), code, convert_length(width), convert_length(height))
  10. }
  11. // 把数字转换成二维码
  12. function toQrcode(canvasId, code, width, height) {
  13. qrcode.api.draw(code, {
  14. ctx: wx.createCanvasContext(canvasId),
  15. width: convert_length(width),
  16. height: convert_length(height)
  17. })
  18. }
  19. module.exports = {
  20. barcode: barc,
  21. qrcode:toQrcode
  22. }

 

  1. //引入的插件borcode.js
  2. var CHAR_TILDE = 126;
  3. var CODE_FNC1 = 102;
  4. var SET_STARTA = 103;
  5. var SET_STARTB = 104;
  6. var SET_STARTC = 105;
  7. var SET_SHIFT = 98;
  8. var SET_CODEA = 101;
  9. var SET_CODEB = 100;
  10. var SET_STOP = 106;
  11. var REPLACE_CODES = {
  12. CHAR_TILDE: CODE_FNC1 //~ corresponds to FNC1 in GS1-128 standard
  13. }
  14. var CODESET = {
  15. ANY: 1,
  16. AB: 2,
  17. A: 3,
  18. B: 4,
  19. C: 5
  20. };
  21. function getBytes(str) {
  22. var bytes = [];
  23. for (var i = 0; i < str.length; i++) {
  24. bytes.push(str.charCodeAt(i));
  25. }
  26. return bytes;
  27. }
  28. exports.code128 = function (ctx, text, width, height) {
  29. width = parseInt(width);
  30. height = parseInt(height);
  31. var codes = stringToCode128(text);
  32. var g = new Graphics(ctx, width, height);
  33. var barWeight = g.area.width / ((codes.length - 3) * 11 + 35);
  34. var x = g.area.left;
  35. var y = g.area.top;
  36. for (var i = 0; i < codes.length; i++) {
  37. var c = codes[i];
  38. //two bars at a time: 1 black and 1 white
  39. for (var bar = 0; bar < 8; bar += 2) {
  40. var barW = PATTERNS[c][bar] * barWeight;
  41. // var barH = height - y - this.border;
  42. var barH = height - y;
  43. var spcW = PATTERNS[c][bar + 1] * barWeight;
  44. //no need to draw if 0 width
  45. if (barW > 0) {
  46. g.fillFgRect(x, y, barW, barH);
  47. }
  48. x += barW + spcW;
  49. }
  50. }
  51. ctx.draw();
  52. }
  53. function stringToCode128(text) {
  54. var barc = {
  55. currcs: CODESET.C
  56. };
  57. var bytes = getBytes(text);
  58. //decide starting codeset
  59. var index = bytes[0] == CHAR_TILDE ? 1 : 0;
  60. var csa1 = bytes.length > 0 ? codeSetAllowedFor(bytes[index++]) : CODESET.AB;
  61. var csa2 = bytes.length > 0 ? codeSetAllowedFor(bytes[index++]) : CODESET.AB;
  62. barc.currcs = getBestStartSet(csa1, csa2);
  63. barc.currcs = perhapsCodeC(bytes, barc.currcs);
  64. //if no codeset changes this will end up with bytes.length+3
  65. //start, checksum and stop
  66. var codes = new Array();
  67. switch (barc.currcs) {
  68. case CODESET.A:
  69. codes.push(SET_STARTA);
  70. break;
  71. case CODESET.B:
  72. codes.push(SET_STARTB);
  73. break;
  74. default:
  75. codes.push(SET_STARTC);
  76. break;
  77. }
  78. for (var i = 0; i < bytes.length; i++) {
  79. var b1 = bytes[i]; //get the first of a pair
  80. //should we translate/replace
  81. if (b1 in REPLACE_CODES) {
  82. codes.push(REPLACE_CODES[b1]);
  83. i++ //jump to next
  84. b1 = bytes[i];
  85. }
  86. //get the next in the pair if possible
  87. var b2 = bytes.length > (i + 1) ? bytes[i + 1] : -1;
  88. codes = codes.concat(codesForChar(b1, b2, barc.currcs));
  89. //code C takes 2 chars each time
  90. if (barc.currcs == CODESET.C) i++;
  91. }
  92. //calculate checksum according to Code 128 standards
  93. var checksum = codes[0];
  94. for (var weight = 1; weight < codes.length; weight++) {
  95. checksum += (weight * codes[weight]);
  96. }
  97. codes.push(checksum % 103);
  98. codes.push(SET_STOP);
  99. //encoding should now be complete
  100. return codes;
  101. function getBestStartSet(csa1, csa2) {
  102. //tries to figure out the best codeset
  103. //to start with to get the most compact code
  104. var vote = 0;
  105. vote += csa1 == CODESET.A ? 1 : 0;
  106. vote += csa1 == CODESET.B ? -1 : 0;
  107. vote += csa2 == CODESET.A ? 1 : 0;
  108. vote += csa2 == CODESET.B ? -1 : 0;
  109. //tie goes to B due to my own predudices
  110. return vote > 0 ? CODESET.A : CODESET.B;
  111. }
  112. function perhapsCodeC(bytes, codeset) {
  113. for (var i = 0; i < bytes.length; i++) {
  114. var b = bytes[i]
  115. if ((b < 48 || b > 57) && b != CHAR_TILDE)
  116. return codeset;
  117. }
  118. return CODESET.C;
  119. }
  120. //chr1 is current byte
  121. //chr2 is the next byte to process. looks ahead.
  122. function codesForChar(chr1, chr2, currcs) {
  123. var result = [];
  124. var shifter = -1;
  125. if (charCompatible(chr1, currcs)) {
  126. if (currcs == CODESET.C) {
  127. if (chr2 == -1) {
  128. shifter = SET_CODEB;
  129. currcs = CODESET.B;
  130. }
  131. else if ((chr2 != -1) && !charCompatible(chr2, currcs)) {
  132. //need to check ahead as well
  133. if (charCompatible(chr2, CODESET.A)) {
  134. shifter = SET_CODEA;
  135. currcs = CODESET.A;
  136. }
  137. else {
  138. shifter = SET_CODEB;
  139. currcs = CODESET.B;
  140. }
  141. }
  142. }
  143. }
  144. else {
  145. //if there is a next char AND that next char is also not compatible
  146. if ((chr2 != -1) && !charCompatible(chr2, currcs)) {
  147. //need to switch code sets
  148. switch (currcs) {
  149. case CODESET.A:
  150. shifter = SET_CODEB;
  151. currcs = CODESET.B;
  152. break;
  153. case CODESET.B:
  154. shifter = SET_CODEA;
  155. currcs = CODESET.A;
  156. break;
  157. }
  158. }
  159. else {
  160. //no need to shift code sets, a temporary SHIFT will suffice
  161. shifter = SET_SHIFT;
  162. }
  163. }
  164. //ok some type of shift is nessecary
  165. if (shifter != -1) {
  166. result.push(shifter);
  167. result.push(codeValue(chr1));
  168. }
  169. else {
  170. if (currcs == CODESET.C) {
  171. //include next as well
  172. result.push(codeValue(chr1, chr2));
  173. }
  174. else {
  175. result.push(codeValue(chr1));
  176. }
  177. }
  178. barc.currcs = currcs;
  179. return result;
  180. }
  181. }
  182. //reduce the ascii code to fit into the Code128 char table
  183. function codeValue(chr1, chr2) {
  184. if (typeof chr2 == "undefined") {
  185. return chr1 >= 32 ? chr1 - 32 : chr1 + 64;
  186. }
  187. else {
  188. return parseInt(String.fromCharCode(chr1) + String.fromCharCode(chr2));
  189. }
  190. }
  191. function charCompatible(chr, codeset) {
  192. var csa = codeSetAllowedFor(chr);
  193. if (csa == CODESET.ANY) return true;
  194. //if we need to change from current
  195. if (csa == CODESET.AB) return true;
  196. if (csa == CODESET.A && codeset == CODESET.A) return true;
  197. if (csa == CODESET.B && codeset == CODESET.B) return true;
  198. return false;
  199. }
  200. function codeSetAllowedFor(chr) {
  201. if (chr >= 48 && chr <= 57) {
  202. //0-9
  203. return CODESET.ANY;
  204. }
  205. else if (chr >= 32 && chr <= 95) {
  206. //0-9 A-Z
  207. return CODESET.AB;
  208. }
  209. else {
  210. //if non printable
  211. return chr < 32 ? CODESET.A : CODESET.B;
  212. }
  213. }
  214. var Graphics = function (ctx, width, height) {
  215. this.width = width;
  216. this.height = height;
  217. this.quiet = Math.round(this.width / 40);
  218. this.border_size = 0;
  219. this.padding_width = 0;
  220. this.area = {
  221. width: width - this.padding_width * 2 - this.quiet * 2,
  222. height: height - this.border_size * 2,
  223. top: this.border_size - 4,
  224. left: this.padding_width + this.quiet
  225. };
  226. this.ctx = ctx;
  227. this.fg = "#000000";
  228. this.bg = "#ffffff";
  229. // fill background
  230. this.fillBgRect(0, 0, width, height);
  231. // fill center to create border
  232. this.fillBgRect(0, this.border_size, width, height - this.border_size * 2);
  233. }
  234. //use native color
  235. Graphics.prototype._fillRect = function (x, y, width, height, color) {
  236. this.ctx.setFillStyle(color)
  237. this.ctx.fillRect(x, y, width, height)
  238. }
  239. Graphics.prototype.fillFgRect = function (x, y, width, height) {
  240. this._fillRect(x, y, width, height, this.fg);
  241. }
  242. Graphics.prototype.fillBgRect = function (x, y, width, height) {
  243. this._fillRect(x, y, width, height, this.bg);
  244. }
  245. var PATTERNS = [
  246. [2, 1, 2, 2, 2, 2, 0, 0], // 0
  247. [2, 2, 2, 1, 2, 2, 0, 0], // 1
  248. [2, 2, 2, 2, 2, 1, 0, 0], // 2
  249. [1, 2, 1, 2, 2, 3, 0, 0], // 3
  250. [1, 2, 1, 3, 2, 2, 0, 0], // 4
  251. [1, 3, 1, 2, 2, 2, 0, 0], // 5
  252. [1, 2, 2, 2, 1, 3, 0, 0], // 6
  253. [1, 2, 2, 3, 1, 2, 0, 0], // 7
  254. [1, 3, 2, 2, 1, 2, 0, 0], // 8
  255. [2, 2, 1, 2, 1, 3, 0, 0], // 9
  256. [2, 2, 1, 3, 1, 2, 0, 0], // 10
  257. [2, 3, 1, 2, 1, 2, 0, 0], // 11
  258. [1, 1, 2, 2, 3, 2, 0, 0], // 12
  259. [1, 2, 2, 1, 3, 2, 0, 0], // 13
  260. [1, 2, 2, 2, 3, 1, 0, 0], // 14
  261. [1, 1, 3, 2, 2, 2, 0, 0], // 15
  262. [1, 2, 3, 1, 2, 2, 0, 0], // 16
  263. [1, 2, 3, 2, 2, 1, 0, 0], // 17
  264. [2, 2, 3, 2, 1, 1, 0, 0], // 18
  265. [2, 2, 1, 1, 3, 2, 0, 0], // 19
  266. [2, 2, 1, 2, 3, 1, 0, 0], // 20
  267. [2, 1, 3, 2, 1, 2, 0, 0], // 21
  268. [2, 2, 3, 1, 1, 2, 0, 0], // 22
  269. [3, 1, 2, 1, 3, 1, 0, 0], // 23
  270. [3, 1, 1, 2, 2, 2, 0, 0], // 24
  271. [3, 2, 1, 1, 2, 2, 0, 0], // 25
  272. [3, 2, 1, 2, 2, 1, 0, 0], // 26
  273. [3, 1, 2, 2, 1, 2, 0, 0], // 27
  274. [3, 2, 2, 1, 1, 2, 0, 0], // 28
  275. [3, 2, 2, 2, 1, 1, 0, 0], // 29
  276. [2, 1, 2, 1, 2, 3, 0, 0], // 30
  277. [2, 1, 2, 3, 2, 1, 0, 0], // 31
  278. [2, 3, 2, 1, 2, 1, 0, 0], // 32
  279. [1, 1, 1, 3, 2, 3, 0, 0], // 33
  280. [1, 3, 1, 1, 2, 3, 0, 0], // 34
  281. [1, 3, 1, 3, 2, 1, 0, 0], // 35
  282. [1, 1, 2, 3, 1, 3, 0, 0], // 36
  283. [1, 3, 2, 1, 1, 3, 0, 0], // 37
  284. [1, 3, 2, 3, 1, 1, 0, 0], // 38
  285. [2, 1, 1, 3, 1, 3, 0, 0], // 39
  286. [2, 3, 1, 1, 1, 3, 0, 0], // 40
  287. [2, 3, 1, 3, 1, 1, 0, 0], // 41
  288. [1, 1, 2, 1, 3, 3, 0, 0], // 42
  289. [1, 1, 2, 3, 3, 1, 0, 0], // 43
  290. [1, 3, 2, 1, 3, 1, 0, 0], // 44
  291. [1, 1, 3, 1, 2, 3, 0, 0], // 45
  292. [1, 1, 3, 3, 2, 1, 0, 0], // 46
  293. [1, 3, 3, 1, 2, 1, 0, 0], // 47
  294. [3, 1, 3, 1, 2, 1, 0, 0], // 48
  295. [2, 1, 1, 3, 3, 1, 0, 0], // 49
  296. [2, 3, 1, 1, 3, 1, 0, 0], // 50
  297. [2, 1, 3, 1, 1, 3, 0, 0], // 51
  298. [2, 1, 3, 3, 1, 1, 0, 0], // 52
  299. [2, 1, 3, 1, 3, 1, 0, 0], // 53
  300. [3, 1, 1, 1, 2, 3, 0, 0], // 54
  301. [3, 1, 1, 3, 2, 1, 0, 0], // 55
  302. [3, 3, 1, 1, 2, 1, 0, 0], // 56
  303. [3, 1, 2, 1, 1, 3, 0, 0], // 57
  304. [3, 1, 2, 3, 1, 1, 0, 0], // 58
  305. [3, 3, 2, 1, 1, 1, 0, 0], // 59
  306. [3, 1, 4, 1, 1, 1, 0, 0], // 60
  307. [2, 2, 1, 4, 1, 1, 0, 0], // 61
  308. [4, 3, 1, 1, 1, 1, 0, 0], // 62
  309. [1, 1, 1, 2, 2, 4, 0, 0], // 63
  310. [1, 1, 1, 4, 2, 2, 0, 0], // 64
  311. [1, 2, 1, 1, 2, 4, 0, 0], // 65
  312. [1, 2, 1, 4, 2, 1, 0, 0], // 66
  313. [1, 4, 1, 1, 2, 2, 0, 0], // 67
  314. [1, 4, 1, 2, 2, 1, 0, 0], // 68
  315. [1, 1, 2, 2, 1, 4, 0, 0], // 69
  316. [1, 1, 2, 4, 1, 2, 0, 0], // 70
  317. [1, 2, 2, 1, 1, 4, 0, 0], // 71
  318. [1, 2, 2, 4, 1, 1, 0, 0], // 72
  319. [1, 4, 2, 1, 1, 2, 0, 0], // 73
  320. [1, 4, 2, 2, 1, 1, 0, 0], // 74
  321. [2, 4, 1, 2, 1, 1, 0, 0], // 75
  322. [2, 2, 1, 1, 1, 4, 0, 0], // 76
  323. [4, 1, 3, 1, 1, 1, 0, 0], // 77
  324. [2, 4, 1, 1, 1, 2, 0, 0], // 78
  325. [1, 3, 4, 1, 1, 1, 0, 0], // 79
  326. [1, 1, 1, 2, 4, 2, 0, 0], // 80
  327. [1, 2, 1, 1, 4, 2, 0, 0], // 81
  328. [1, 2, 1, 2, 4, 1, 0, 0], // 82
  329. [1, 1, 4, 2, 1, 2, 0, 0], // 83
  330. [1, 2, 4, 1, 1, 2, 0, 0], // 84
  331. [1, 2, 4, 2, 1, 1, 0, 0], // 85
  332. [4, 1, 1, 2, 1, 2, 0, 0], // 86
  333. [4, 2, 1, 1, 1, 2, 0, 0], // 87
  334. [4, 2, 1, 2, 1, 1, 0, 0], // 88
  335. [2, 1, 2, 1, 4, 1, 0, 0], // 89
  336. [2, 1, 4, 1, 2, 1, 0, 0], // 90
  337. [4, 1, 2, 1, 2, 1, 0, 0], // 91
  338. [1, 1, 1, 1, 4, 3, 0, 0], // 92
  339. [1, 1, 1, 3, 4, 1, 0, 0], // 93
  340. [1, 3, 1, 1, 4, 1, 0, 0], // 94
  341. [1, 1, 4, 1, 1, 3, 0, 0], // 95
  342. [1, 1, 4, 3, 1, 1, 0, 0], // 96
  343. [4, 1, 1, 1, 1, 3, 0, 0], // 97
  344. [4, 1, 1, 3, 1, 1, 0, 0], // 98
  345. [1, 1, 3, 1, 4, 1, 0, 0], // 99
  346. [1, 1, 4, 1, 3, 1, 0, 0], // 100
  347. [3, 1, 1, 1, 4, 1, 0, 0], // 101
  348. [4, 1, 1, 1, 3, 1, 0, 0], // 102
  349. [2, 1, 1, 4, 1, 2, 0, 0], // 103
  350. [2, 1, 1, 2, 1, 4, 0, 0], // 104
  351. [2, 1, 1, 2, 3, 2, 0, 0], // 105
  352. [2, 3, 3, 1, 1, 1, 2, 0] // 106
  353. ]

 

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

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/正经夜光杯/article/detail/905441
推荐阅读
相关标签