weapp-qrcode.js 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077
  1. /**
  2. * weapp.qrcode.js v1.0.0 (https://github.com/yingye/weapp-qrcode#readme)
  3. */
  4. (function (global, factory) {
  5. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : global.drawQrcode = factory();
  6. })(this, function () {
  7. 'use strict';
  8. var hasOwn = Object.prototype.hasOwnProperty;
  9. var toStr = Object.prototype.toString;
  10. var defineProperty = Object.defineProperty;
  11. var gOPD = Object.getOwnPropertyDescriptor;
  12. var isArray = function isArray(arr) {
  13. if (typeof Array.isArray === 'function') {
  14. return Array.isArray(arr);
  15. }
  16. return toStr.call(arr) === '[object Array]';
  17. };
  18. var isPlainObject = function isPlainObject(obj) {
  19. if (!obj || toStr.call(obj) !== '[object Object]') {
  20. return false;
  21. }
  22. var hasOwnConstructor = hasOwn.call(obj, 'constructor');
  23. var hasIsPrototypeOf = obj.constructor && obj.constructor.prototype && hasOwn.call(obj.constructor.prototype, 'isPrototypeOf');
  24. // Not own constructor property must be Object
  25. if (obj.constructor && !hasOwnConstructor && !hasIsPrototypeOf) {
  26. return false;
  27. }
  28. // Own properties are enumerated firstly, so to speed up,
  29. // if last one is own, then all properties are own.
  30. var key;
  31. for (key in obj) {
  32. /**/
  33. }
  34. return typeof key === 'undefined' || hasOwn.call(obj, key);
  35. };
  36. // If name is '__proto__', and Object.defineProperty is available, define __proto__ as an own property on target
  37. var setProperty = function setProperty(target, options) {
  38. if (defineProperty && options.name === '__proto__') {
  39. defineProperty(target, options.name, {
  40. enumerable: true,
  41. configurable: true,
  42. value: options.newValue,
  43. writable: true
  44. });
  45. } else {
  46. target[options.name] = options.newValue;
  47. }
  48. };
  49. // Return undefined instead of __proto__ if '__proto__' is not an own property
  50. var getProperty = function getProperty(obj, name) {
  51. if (name === '__proto__') {
  52. if (!hasOwn.call(obj, name)) {
  53. return void 0;
  54. } else if (gOPD) {
  55. // In early versions of node, obj['__proto__'] is buggy when obj has
  56. // __proto__ as an own property. Object.getOwnPropertyDescriptor() works.
  57. return gOPD(obj, name).value;
  58. }
  59. }
  60. return obj[name];
  61. };
  62. var extend = function extend() {
  63. var options, name, src, copy, copyIsArray, clone;
  64. var target = arguments[0];
  65. var i = 1;
  66. var length = arguments.length;
  67. var deep = false;
  68. // Handle a deep copy situation
  69. if (typeof target === 'boolean') {
  70. deep = target;
  71. target = arguments[1] || {};
  72. // skip the boolean and the target
  73. i = 2;
  74. }
  75. if (target == null || typeof target !== 'object' && typeof target !== 'function') {
  76. target = {};
  77. }
  78. for (; i < length; ++i) {
  79. options = arguments[i];
  80. // Only deal with non-null/undefined values
  81. if (options != null) {
  82. // Extend the base object
  83. for (name in options) {
  84. src = getProperty(target, name);
  85. copy = getProperty(options, name);
  86. // Prevent never-ending loop
  87. if (target !== copy) {
  88. // Recurse if we're merging plain objects or arrays
  89. if (deep && copy && (isPlainObject(copy) || (copyIsArray = isArray(copy)))) {
  90. if (copyIsArray) {
  91. copyIsArray = false;
  92. clone = src && isArray(src) ? src : [];
  93. } else {
  94. clone = src && isPlainObject(src) ? src : {};
  95. }
  96. // Never move original objects, clone them
  97. setProperty(target, {
  98. name: name,
  99. newValue: extend(deep, clone, copy)
  100. });
  101. // Don't bring in undefined values
  102. } else if (typeof copy !== 'undefined') {
  103. setProperty(target, {
  104. name: name,
  105. newValue: copy
  106. });
  107. }
  108. }
  109. }
  110. }
  111. }
  112. // Return the modified object
  113. return target;
  114. };
  115. //---------------------------------------------------------------------
  116. // QRCode for JavaScript
  117. //
  118. // Copyright (c) 2009 Kazuhiko Arase
  119. //
  120. // URL: http://www.d-project.com/
  121. //
  122. // Licensed under the MIT license:
  123. // http://www.opensource.org/licenses/mit-license.php
  124. //
  125. // The word "QR Code" is registered trademark of
  126. // DENSO WAVE INCORPORATED
  127. // http://www.denso-wave.com/qrcode/faqpatent-e.html
  128. //
  129. //---------------------------------------------------------------------
  130. //---------------------------------------------------------------------
  131. // QR8bitByte
  132. //---------------------------------------------------------------------
  133. function QR8bitByte(data) {
  134. this.mode = QRMode.MODE_8BIT_BYTE;
  135. this.data = data;
  136. }
  137. QR8bitByte.prototype = {
  138. getLength: function (buffer) {
  139. return this.data.length;
  140. },
  141. write: function (buffer) {
  142. for (var i = 0; i < this.data.length; i++) {
  143. // not JIS ...
  144. buffer.put(this.data.charCodeAt(i), 8);
  145. }
  146. }
  147. };
  148. //---------------------------------------------------------------------
  149. // QRCode
  150. //---------------------------------------------------------------------
  151. function QRCode(typeNumber, errorCorrectLevel) {
  152. this.typeNumber = typeNumber;
  153. this.errorCorrectLevel = errorCorrectLevel;
  154. this.modules = null;
  155. this.moduleCount = 0;
  156. this.dataCache = null;
  157. this.dataList = new Array();
  158. }
  159. QRCode.prototype = {
  160. addData: function (data) {
  161. var newData = new QR8bitByte(data);
  162. this.dataList.push(newData);
  163. this.dataCache = null;
  164. },
  165. isDark: function (row, col) {
  166. if (row < 0 || this.moduleCount <= row || col < 0 || this.moduleCount <= col) {
  167. throw new Error(row + "," + col);
  168. }
  169. return this.modules[row][col];
  170. },
  171. getModuleCount: function () {
  172. return this.moduleCount;
  173. },
  174. make: function () {
  175. // Calculate automatically typeNumber if provided is < 1
  176. if (this.typeNumber < 1) {
  177. var typeNumber = 1;
  178. for (typeNumber = 1; typeNumber < 40; typeNumber++) {
  179. var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, this.errorCorrectLevel);
  180. var buffer = new QRBitBuffer();
  181. var totalDataCount = 0;
  182. for (var i = 0; i < rsBlocks.length; i++) {
  183. totalDataCount += rsBlocks[i].dataCount;
  184. }
  185. for (var i = 0; i < this.dataList.length; i++) {
  186. var data = this.dataList[i];
  187. buffer.put(data.mode, 4);
  188. buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber));
  189. data.write(buffer);
  190. }
  191. if (buffer.getLengthInBits() <= totalDataCount * 8) break;
  192. }
  193. this.typeNumber = typeNumber;
  194. }
  195. this.makeImpl(false, this.getBestMaskPattern());
  196. },
  197. makeImpl: function (test, maskPattern) {
  198. this.moduleCount = this.typeNumber * 4 + 17;
  199. this.modules = new Array(this.moduleCount);
  200. for (var row = 0; row < this.moduleCount; row++) {
  201. this.modules[row] = new Array(this.moduleCount);
  202. for (var col = 0; col < this.moduleCount; col++) {
  203. this.modules[row][col] = null; //(col + row) % 3;
  204. }
  205. }
  206. this.setupPositionProbePattern(0, 0);
  207. this.setupPositionProbePattern(this.moduleCount - 7, 0);
  208. this.setupPositionProbePattern(0, this.moduleCount - 7);
  209. this.setupPositionAdjustPattern();
  210. this.setupTimingPattern();
  211. this.setupTypeInfo(test, maskPattern);
  212. if (this.typeNumber >= 7) {
  213. this.setupTypeNumber(test);
  214. }
  215. if (this.dataCache == null) {
  216. this.dataCache = QRCode.createData(this.typeNumber, this.errorCorrectLevel, this.dataList);
  217. }
  218. this.mapData(this.dataCache, maskPattern);
  219. },
  220. setupPositionProbePattern: function (row, col) {
  221. for (var r = -1; r <= 7; r++) {
  222. if (row + r <= -1 || this.moduleCount <= row + r) continue;
  223. for (var c = -1; c <= 7; c++) {
  224. if (col + c <= -1 || this.moduleCount <= col + c) continue;
  225. if (0 <= r && r <= 6 && (c == 0 || c == 6) || 0 <= c && c <= 6 && (r == 0 || r == 6) || 2 <= r && r <= 4 && 2 <= c && c <= 4) {
  226. this.modules[row + r][col + c] = true;
  227. } else {
  228. this.modules[row + r][col + c] = false;
  229. }
  230. }
  231. }
  232. },
  233. getBestMaskPattern: function () {
  234. var minLostPoint = 0;
  235. var pattern = 0;
  236. for (var i = 0; i < 8; i++) {
  237. this.makeImpl(true, i);
  238. var lostPoint = QRUtil.getLostPoint(this);
  239. if (i == 0 || minLostPoint > lostPoint) {
  240. minLostPoint = lostPoint;
  241. pattern = i;
  242. }
  243. }
  244. return pattern;
  245. },
  246. createMovieClip: function (target_mc, instance_name, depth) {
  247. var qr_mc = target_mc.createEmptyMovieClip(instance_name, depth);
  248. var cs = 1;
  249. this.make();
  250. for (var row = 0; row < this.modules.length; row++) {
  251. var y = row * cs;
  252. for (var col = 0; col < this.modules[row].length; col++) {
  253. var x = col * cs;
  254. var dark = this.modules[row][col];
  255. if (dark) {
  256. qr_mc.beginFill(0, 100);
  257. qr_mc.moveTo(x, y);
  258. qr_mc.lineTo(x + cs, y);
  259. qr_mc.lineTo(x + cs, y + cs);
  260. qr_mc.lineTo(x, y + cs);
  261. qr_mc.endFill();
  262. }
  263. }
  264. }
  265. return qr_mc;
  266. },
  267. setupTimingPattern: function () {
  268. for (var r = 8; r < this.moduleCount - 8; r++) {
  269. if (this.modules[r][6] != null) {
  270. continue;
  271. }
  272. this.modules[r][6] = r % 2 == 0;
  273. }
  274. for (var c = 8; c < this.moduleCount - 8; c++) {
  275. if (this.modules[6][c] != null) {
  276. continue;
  277. }
  278. this.modules[6][c] = c % 2 == 0;
  279. }
  280. },
  281. setupPositionAdjustPattern: function () {
  282. var pos = QRUtil.getPatternPosition(this.typeNumber);
  283. for (var i = 0; i < pos.length; i++) {
  284. for (var j = 0; j < pos.length; j++) {
  285. var row = pos[i];
  286. var col = pos[j];
  287. if (this.modules[row][col] != null) {
  288. continue;
  289. }
  290. for (var r = -2; r <= 2; r++) {
  291. for (var c = -2; c <= 2; c++) {
  292. if (r == -2 || r == 2 || c == -2 || c == 2 || r == 0 && c == 0) {
  293. this.modules[row + r][col + c] = true;
  294. } else {
  295. this.modules[row + r][col + c] = false;
  296. }
  297. }
  298. }
  299. }
  300. }
  301. },
  302. setupTypeNumber: function (test) {
  303. var bits = QRUtil.getBCHTypeNumber(this.typeNumber);
  304. for (var i = 0; i < 18; i++) {
  305. var mod = !test && (bits >> i & 1) == 1;
  306. this.modules[Math.floor(i / 3)][i % 3 + this.moduleCount - 8 - 3] = mod;
  307. }
  308. for (var i = 0; i < 18; i++) {
  309. var mod = !test && (bits >> i & 1) == 1;
  310. this.modules[i % 3 + this.moduleCount - 8 - 3][Math.floor(i / 3)] = mod;
  311. }
  312. },
  313. setupTypeInfo: function (test, maskPattern) {
  314. var data = this.errorCorrectLevel << 3 | maskPattern;
  315. var bits = QRUtil.getBCHTypeInfo(data);
  316. // vertical
  317. for (var i = 0; i < 15; i++) {
  318. var mod = !test && (bits >> i & 1) == 1;
  319. if (i < 6) {
  320. this.modules[i][8] = mod;
  321. } else if (i < 8) {
  322. this.modules[i + 1][8] = mod;
  323. } else {
  324. this.modules[this.moduleCount - 15 + i][8] = mod;
  325. }
  326. }
  327. // horizontal
  328. for (var i = 0; i < 15; i++) {
  329. var mod = !test && (bits >> i & 1) == 1;
  330. if (i < 8) {
  331. this.modules[8][this.moduleCount - i - 1] = mod;
  332. } else if (i < 9) {
  333. this.modules[8][15 - i - 1 + 1] = mod;
  334. } else {
  335. this.modules[8][15 - i - 1] = mod;
  336. }
  337. }
  338. // fixed module
  339. this.modules[this.moduleCount - 8][8] = !test;
  340. },
  341. mapData: function (data, maskPattern) {
  342. var inc = -1;
  343. var row = this.moduleCount - 1;
  344. var bitIndex = 7;
  345. var byteIndex = 0;
  346. for (var col = this.moduleCount - 1; col > 0; col -= 2) {
  347. if (col == 6) col--;
  348. while (true) {
  349. for (var c = 0; c < 2; c++) {
  350. if (this.modules[row][col - c] == null) {
  351. var dark = false;
  352. if (byteIndex < data.length) {
  353. dark = (data[byteIndex] >>> bitIndex & 1) == 1;
  354. }
  355. var mask = QRUtil.getMask(maskPattern, row, col - c);
  356. if (mask) {
  357. dark = !dark;
  358. }
  359. this.modules[row][col - c] = dark;
  360. bitIndex--;
  361. if (bitIndex == -1) {
  362. byteIndex++;
  363. bitIndex = 7;
  364. }
  365. }
  366. }
  367. row += inc;
  368. if (row < 0 || this.moduleCount <= row) {
  369. row -= inc;
  370. inc = -inc;
  371. break;
  372. }
  373. }
  374. }
  375. }
  376. };
  377. QRCode.PAD0 = 0xEC;
  378. QRCode.PAD1 = 0x11;
  379. QRCode.createData = function (typeNumber, errorCorrectLevel, dataList) {
  380. var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel);
  381. var buffer = new QRBitBuffer();
  382. for (var i = 0; i < dataList.length; i++) {
  383. var data = dataList[i];
  384. buffer.put(data.mode, 4);
  385. buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber));
  386. data.write(buffer);
  387. }
  388. // calc num max data.
  389. var totalDataCount = 0;
  390. for (var i = 0; i < rsBlocks.length; i++) {
  391. totalDataCount += rsBlocks[i].dataCount;
  392. }
  393. if (buffer.getLengthInBits() > totalDataCount * 8) {
  394. throw new Error("code length overflow. (" + buffer.getLengthInBits() + ">" + totalDataCount * 8 + ")");
  395. }
  396. // end code
  397. if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {
  398. buffer.put(0, 4);
  399. }
  400. // padding
  401. while (buffer.getLengthInBits() % 8 != 0) {
  402. buffer.putBit(false);
  403. }
  404. // padding
  405. while (true) {
  406. if (buffer.getLengthInBits() >= totalDataCount * 8) {
  407. break;
  408. }
  409. buffer.put(QRCode.PAD0, 8);
  410. if (buffer.getLengthInBits() >= totalDataCount * 8) {
  411. break;
  412. }
  413. buffer.put(QRCode.PAD1, 8);
  414. }
  415. return QRCode.createBytes(buffer, rsBlocks);
  416. };
  417. QRCode.createBytes = function (buffer, rsBlocks) {
  418. var offset = 0;
  419. var maxDcCount = 0;
  420. var maxEcCount = 0;
  421. var dcdata = new Array(rsBlocks.length);
  422. var ecdata = new Array(rsBlocks.length);
  423. for (var r = 0; r < rsBlocks.length; r++) {
  424. var dcCount = rsBlocks[r].dataCount;
  425. var ecCount = rsBlocks[r].totalCount - dcCount;
  426. maxDcCount = Math.max(maxDcCount, dcCount);
  427. maxEcCount = Math.max(maxEcCount, ecCount);
  428. dcdata[r] = new Array(dcCount);
  429. for (var i = 0; i < dcdata[r].length; i++) {
  430. dcdata[r][i] = 0xff & buffer.buffer[i + offset];
  431. }
  432. offset += dcCount;
  433. var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
  434. var rawPoly = new QRPolynomial(dcdata[r], rsPoly.getLength() - 1);
  435. var modPoly = rawPoly.mod(rsPoly);
  436. ecdata[r] = new Array(rsPoly.getLength() - 1);
  437. for (var i = 0; i < ecdata[r].length; i++) {
  438. var modIndex = i + modPoly.getLength() - ecdata[r].length;
  439. ecdata[r][i] = modIndex >= 0 ? modPoly.get(modIndex) : 0;
  440. }
  441. }
  442. var totalCodeCount = 0;
  443. for (var i = 0; i < rsBlocks.length; i++) {
  444. totalCodeCount += rsBlocks[i].totalCount;
  445. }
  446. var data = new Array(totalCodeCount);
  447. var index = 0;
  448. for (var i = 0; i < maxDcCount; i++) {
  449. for (var r = 0; r < rsBlocks.length; r++) {
  450. if (i < dcdata[r].length) {
  451. data[index++] = dcdata[r][i];
  452. }
  453. }
  454. }
  455. for (var i = 0; i < maxEcCount; i++) {
  456. for (var r = 0; r < rsBlocks.length; r++) {
  457. if (i < ecdata[r].length) {
  458. data[index++] = ecdata[r][i];
  459. }
  460. }
  461. }
  462. return data;
  463. };
  464. //---------------------------------------------------------------------
  465. // QRMode
  466. //---------------------------------------------------------------------
  467. var QRMode = {
  468. MODE_NUMBER: 1 << 0,
  469. MODE_ALPHA_NUM: 1 << 1,
  470. MODE_8BIT_BYTE: 1 << 2,
  471. MODE_KANJI: 1 << 3
  472. };
  473. //---------------------------------------------------------------------
  474. // QRErrorCorrectLevel
  475. //---------------------------------------------------------------------
  476. var QRErrorCorrectLevel = {
  477. L: 1,
  478. M: 0,
  479. Q: 3,
  480. H: 2
  481. };
  482. //---------------------------------------------------------------------
  483. // QRMaskPattern
  484. //---------------------------------------------------------------------
  485. var QRMaskPattern = {
  486. PATTERN000: 0,
  487. PATTERN001: 1,
  488. PATTERN010: 2,
  489. PATTERN011: 3,
  490. PATTERN100: 4,
  491. PATTERN101: 5,
  492. PATTERN110: 6,
  493. PATTERN111: 7
  494. };
  495. //---------------------------------------------------------------------
  496. // QRUtil
  497. //---------------------------------------------------------------------
  498. var QRUtil = {
  499. PATTERN_POSITION_TABLE: [[], [6, 18], [6, 22], [6, 26], [6, 30], [6, 34], [6, 22, 38], [6, 24, 42], [6, 26, 46], [6, 28, 50], [6, 30, 54], [6, 32, 58], [6, 34, 62], [6, 26, 46, 66], [6, 26, 48, 70], [6, 26, 50, 74], [6, 30, 54, 78], [6, 30, 56, 82], [6, 30, 58, 86], [6, 34, 62, 90], [6, 28, 50, 72, 94], [6, 26, 50, 74, 98], [6, 30, 54, 78, 102], [6, 28, 54, 80, 106], [6, 32, 58, 84, 110], [6, 30, 58, 86, 114], [6, 34, 62, 90, 118], [6, 26, 50, 74, 98, 122], [6, 30, 54, 78, 102, 126], [6, 26, 52, 78, 104, 130], [6, 30, 56, 82, 108, 134], [6, 34, 60, 86, 112, 138], [6, 30, 58, 86, 114, 142], [6, 34, 62, 90, 118, 146], [6, 30, 54, 78, 102, 126, 150], [6, 24, 50, 76, 102, 128, 154], [6, 28, 54, 80, 106, 132, 158], [6, 32, 58, 84, 110, 136, 162], [6, 26, 54, 82, 110, 138, 166], [6, 30, 58, 86, 114, 142, 170]],
  500. G15: 1 << 10 | 1 << 8 | 1 << 5 | 1 << 4 | 1 << 2 | 1 << 1 | 1 << 0,
  501. G18: 1 << 12 | 1 << 11 | 1 << 10 | 1 << 9 | 1 << 8 | 1 << 5 | 1 << 2 | 1 << 0,
  502. G15_MASK: 1 << 14 | 1 << 12 | 1 << 10 | 1 << 4 | 1 << 1,
  503. getBCHTypeInfo: function (data) {
  504. var d = data << 10;
  505. while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0) {
  506. d ^= QRUtil.G15 << QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15);
  507. }
  508. return (data << 10 | d) ^ QRUtil.G15_MASK;
  509. },
  510. getBCHTypeNumber: function (data) {
  511. var d = data << 12;
  512. while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0) {
  513. d ^= QRUtil.G18 << QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18);
  514. }
  515. return data << 12 | d;
  516. },
  517. getBCHDigit: function (data) {
  518. var digit = 0;
  519. while (data != 0) {
  520. digit++;
  521. data >>>= 1;
  522. }
  523. return digit;
  524. },
  525. getPatternPosition: function (typeNumber) {
  526. return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1];
  527. },
  528. getMask: function (maskPattern, i, j) {
  529. switch (maskPattern) {
  530. case QRMaskPattern.PATTERN000:
  531. return (i + j) % 2 == 0;
  532. case QRMaskPattern.PATTERN001:
  533. return i % 2 == 0;
  534. case QRMaskPattern.PATTERN010:
  535. return j % 3 == 0;
  536. case QRMaskPattern.PATTERN011:
  537. return (i + j) % 3 == 0;
  538. case QRMaskPattern.PATTERN100:
  539. return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 == 0;
  540. case QRMaskPattern.PATTERN101:
  541. return i * j % 2 + i * j % 3 == 0;
  542. case QRMaskPattern.PATTERN110:
  543. return (i * j % 2 + i * j % 3) % 2 == 0;
  544. case QRMaskPattern.PATTERN111:
  545. return (i * j % 3 + (i + j) % 2) % 2 == 0;
  546. default:
  547. throw new Error("bad maskPattern:" + maskPattern);
  548. }
  549. },
  550. getErrorCorrectPolynomial: function (errorCorrectLength) {
  551. var a = new QRPolynomial([1], 0);
  552. for (var i = 0; i < errorCorrectLength; i++) {
  553. a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0));
  554. }
  555. return a;
  556. },
  557. getLengthInBits: function (mode, type) {
  558. if (1 <= type && type < 10) {
  559. // 1 - 9
  560. switch (mode) {
  561. case QRMode.MODE_NUMBER:
  562. return 10;
  563. case QRMode.MODE_ALPHA_NUM:
  564. return 9;
  565. case QRMode.MODE_8BIT_BYTE:
  566. return 8;
  567. case QRMode.MODE_KANJI:
  568. return 8;
  569. default:
  570. throw new Error("mode:" + mode);
  571. }
  572. } else if (type < 27) {
  573. // 10 - 26
  574. switch (mode) {
  575. case QRMode.MODE_NUMBER:
  576. return 12;
  577. case QRMode.MODE_ALPHA_NUM:
  578. return 11;
  579. case QRMode.MODE_8BIT_BYTE:
  580. return 16;
  581. case QRMode.MODE_KANJI:
  582. return 10;
  583. default:
  584. throw new Error("mode:" + mode);
  585. }
  586. } else if (type < 41) {
  587. // 27 - 40
  588. switch (mode) {
  589. case QRMode.MODE_NUMBER:
  590. return 14;
  591. case QRMode.MODE_ALPHA_NUM:
  592. return 13;
  593. case QRMode.MODE_8BIT_BYTE:
  594. return 16;
  595. case QRMode.MODE_KANJI:
  596. return 12;
  597. default:
  598. throw new Error("mode:" + mode);
  599. }
  600. } else {
  601. throw new Error("type:" + type);
  602. }
  603. },
  604. getLostPoint: function (qrCode) {
  605. var moduleCount = qrCode.getModuleCount();
  606. var lostPoint = 0;
  607. // LEVEL1
  608. for (var row = 0; row < moduleCount; row++) {
  609. for (var col = 0; col < moduleCount; col++) {
  610. var sameCount = 0;
  611. var dark = qrCode.isDark(row, col);
  612. for (var r = -1; r <= 1; r++) {
  613. if (row + r < 0 || moduleCount <= row + r) {
  614. continue;
  615. }
  616. for (var c = -1; c <= 1; c++) {
  617. if (col + c < 0 || moduleCount <= col + c) {
  618. continue;
  619. }
  620. if (r == 0 && c == 0) {
  621. continue;
  622. }
  623. if (dark == qrCode.isDark(row + r, col + c)) {
  624. sameCount++;
  625. }
  626. }
  627. }
  628. if (sameCount > 5) {
  629. lostPoint += 3 + sameCount - 5;
  630. }
  631. }
  632. }
  633. // LEVEL2
  634. for (var row = 0; row < moduleCount - 1; row++) {
  635. for (var col = 0; col < moduleCount - 1; col++) {
  636. var count = 0;
  637. if (qrCode.isDark(row, col)) count++;
  638. if (qrCode.isDark(row + 1, col)) count++;
  639. if (qrCode.isDark(row, col + 1)) count++;
  640. if (qrCode.isDark(row + 1, col + 1)) count++;
  641. if (count == 0 || count == 4) {
  642. lostPoint += 3;
  643. }
  644. }
  645. }
  646. // LEVEL3
  647. for (var row = 0; row < moduleCount; row++) {
  648. for (var col = 0; col < moduleCount - 6; col++) {
  649. if (qrCode.isDark(row, col) && !qrCode.isDark(row, col + 1) && qrCode.isDark(row, col + 2) && qrCode.isDark(row, col + 3) && qrCode.isDark(row, col + 4) && !qrCode.isDark(row, col + 5) && qrCode.isDark(row, col + 6)) {
  650. lostPoint += 40;
  651. }
  652. }
  653. }
  654. for (var col = 0; col < moduleCount; col++) {
  655. for (var row = 0; row < moduleCount - 6; row++) {
  656. if (qrCode.isDark(row, col) && !qrCode.isDark(row + 1, col) && qrCode.isDark(row + 2, col) && qrCode.isDark(row + 3, col) && qrCode.isDark(row + 4, col) && !qrCode.isDark(row + 5, col) && qrCode.isDark(row + 6, col)) {
  657. lostPoint += 40;
  658. }
  659. }
  660. }
  661. // LEVEL4
  662. var darkCount = 0;
  663. for (var col = 0; col < moduleCount; col++) {
  664. for (var row = 0; row < moduleCount; row++) {
  665. if (qrCode.isDark(row, col)) {
  666. darkCount++;
  667. }
  668. }
  669. }
  670. var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5;
  671. lostPoint += ratio * 10;
  672. return lostPoint;
  673. }
  674. };
  675. //---------------------------------------------------------------------
  676. // QRMath
  677. //---------------------------------------------------------------------
  678. var QRMath = {
  679. glog: function (n) {
  680. if (n < 1) {
  681. throw new Error("glog(" + n + ")");
  682. }
  683. return QRMath.LOG_TABLE[n];
  684. },
  685. gexp: function (n) {
  686. while (n < 0) {
  687. n += 255;
  688. }
  689. while (n >= 256) {
  690. n -= 255;
  691. }
  692. return QRMath.EXP_TABLE[n];
  693. },
  694. EXP_TABLE: new Array(256),
  695. LOG_TABLE: new Array(256)
  696. };
  697. for (var i = 0; i < 8; i++) {
  698. QRMath.EXP_TABLE[i] = 1 << i;
  699. }
  700. for (var i = 8; i < 256; i++) {
  701. QRMath.EXP_TABLE[i] = QRMath.EXP_TABLE[i - 4] ^ QRMath.EXP_TABLE[i - 5] ^ QRMath.EXP_TABLE[i - 6] ^ QRMath.EXP_TABLE[i - 8];
  702. }
  703. for (var i = 0; i < 255; i++) {
  704. QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]] = i;
  705. }
  706. //---------------------------------------------------------------------
  707. // QRPolynomial
  708. //---------------------------------------------------------------------
  709. function QRPolynomial(num, shift) {
  710. if (num.length == undefined) {
  711. throw new Error(num.length + "/" + shift);
  712. }
  713. var offset = 0;
  714. while (offset < num.length && num[offset] == 0) {
  715. offset++;
  716. }
  717. this.num = new Array(num.length - offset + shift);
  718. for (var i = 0; i < num.length - offset; i++) {
  719. this.num[i] = num[i + offset];
  720. }
  721. }
  722. QRPolynomial.prototype = {
  723. get: function (index) {
  724. return this.num[index];
  725. },
  726. getLength: function () {
  727. return this.num.length;
  728. },
  729. multiply: function (e) {
  730. var num = new Array(this.getLength() + e.getLength() - 1);
  731. for (var i = 0; i < this.getLength(); i++) {
  732. for (var j = 0; j < e.getLength(); j++) {
  733. num[i + j] ^= QRMath.gexp(QRMath.glog(this.get(i)) + QRMath.glog(e.get(j)));
  734. }
  735. }
  736. return new QRPolynomial(num, 0);
  737. },
  738. mod: function (e) {
  739. if (this.getLength() - e.getLength() < 0) {
  740. return this;
  741. }
  742. var ratio = QRMath.glog(this.get(0)) - QRMath.glog(e.get(0));
  743. var num = new Array(this.getLength());
  744. for (var i = 0; i < this.getLength(); i++) {
  745. num[i] = this.get(i);
  746. }
  747. for (var i = 0; i < e.getLength(); i++) {
  748. num[i] ^= QRMath.gexp(QRMath.glog(e.get(i)) + ratio);
  749. }
  750. // recursive call
  751. return new QRPolynomial(num, 0).mod(e);
  752. }
  753. };
  754. //---------------------------------------------------------------------
  755. // QRRSBlock
  756. //---------------------------------------------------------------------
  757. function QRRSBlock(totalCount, dataCount) {
  758. this.totalCount = totalCount;
  759. this.dataCount = dataCount;
  760. }
  761. QRRSBlock.RS_BLOCK_TABLE = [
  762. // L
  763. // M
  764. // Q
  765. // H
  766. // 1
  767. [1, 26, 19], [1, 26, 16], [1, 26, 13], [1, 26, 9],
  768. // 2
  769. [1, 44, 34], [1, 44, 28], [1, 44, 22], [1, 44, 16],
  770. // 3
  771. [1, 70, 55], [1, 70, 44], [2, 35, 17], [2, 35, 13],
  772. // 4
  773. [1, 100, 80], [2, 50, 32], [2, 50, 24], [4, 25, 9],
  774. // 5
  775. [1, 134, 108], [2, 67, 43], [2, 33, 15, 2, 34, 16], [2, 33, 11, 2, 34, 12],
  776. // 6
  777. [2, 86, 68], [4, 43, 27], [4, 43, 19], [4, 43, 15],
  778. // 7
  779. [2, 98, 78], [4, 49, 31], [2, 32, 14, 4, 33, 15], [4, 39, 13, 1, 40, 14],
  780. // 8
  781. [2, 121, 97], [2, 60, 38, 2, 61, 39], [4, 40, 18, 2, 41, 19], [4, 40, 14, 2, 41, 15],
  782. // 9
  783. [2, 146, 116], [3, 58, 36, 2, 59, 37], [4, 36, 16, 4, 37, 17], [4, 36, 12, 4, 37, 13],
  784. // 10
  785. [2, 86, 68, 2, 87, 69], [4, 69, 43, 1, 70, 44], [6, 43, 19, 2, 44, 20], [6, 43, 15, 2, 44, 16],
  786. // 11
  787. [4, 101, 81], [1, 80, 50, 4, 81, 51], [4, 50, 22, 4, 51, 23], [3, 36, 12, 8, 37, 13],
  788. // 12
  789. [2, 116, 92, 2, 117, 93], [6, 58, 36, 2, 59, 37], [4, 46, 20, 6, 47, 21], [7, 42, 14, 4, 43, 15],
  790. // 13
  791. [4, 133, 107], [8, 59, 37, 1, 60, 38], [8, 44, 20, 4, 45, 21], [12, 33, 11, 4, 34, 12],
  792. // 14
  793. [3, 145, 115, 1, 146, 116], [4, 64, 40, 5, 65, 41], [11, 36, 16, 5, 37, 17], [11, 36, 12, 5, 37, 13],
  794. // 15
  795. [5, 109, 87, 1, 110, 88], [5, 65, 41, 5, 66, 42], [5, 54, 24, 7, 55, 25], [11, 36, 12],
  796. // 16
  797. [5, 122, 98, 1, 123, 99], [7, 73, 45, 3, 74, 46], [15, 43, 19, 2, 44, 20], [3, 45, 15, 13, 46, 16],
  798. // 17
  799. [1, 135, 107, 5, 136, 108], [10, 74, 46, 1, 75, 47], [1, 50, 22, 15, 51, 23], [2, 42, 14, 17, 43, 15],
  800. // 18
  801. [5, 150, 120, 1, 151, 121], [9, 69, 43, 4, 70, 44], [17, 50, 22, 1, 51, 23], [2, 42, 14, 19, 43, 15],
  802. // 19
  803. [3, 141, 113, 4, 142, 114], [3, 70, 44, 11, 71, 45], [17, 47, 21, 4, 48, 22], [9, 39, 13, 16, 40, 14],
  804. // 20
  805. [3, 135, 107, 5, 136, 108], [3, 67, 41, 13, 68, 42], [15, 54, 24, 5, 55, 25], [15, 43, 15, 10, 44, 16],
  806. // 21
  807. [4, 144, 116, 4, 145, 117], [17, 68, 42], [17, 50, 22, 6, 51, 23], [19, 46, 16, 6, 47, 17],
  808. // 22
  809. [2, 139, 111, 7, 140, 112], [17, 74, 46], [7, 54, 24, 16, 55, 25], [34, 37, 13],
  810. // 23
  811. [4, 151, 121, 5, 152, 122], [4, 75, 47, 14, 76, 48], [11, 54, 24, 14, 55, 25], [16, 45, 15, 14, 46, 16],
  812. // 24
  813. [6, 147, 117, 4, 148, 118], [6, 73, 45, 14, 74, 46], [11, 54, 24, 16, 55, 25], [30, 46, 16, 2, 47, 17],
  814. // 25
  815. [8, 132, 106, 4, 133, 107], [8, 75, 47, 13, 76, 48], [7, 54, 24, 22, 55, 25], [22, 45, 15, 13, 46, 16],
  816. // 26
  817. [10, 142, 114, 2, 143, 115], [19, 74, 46, 4, 75, 47], [28, 50, 22, 6, 51, 23], [33, 46, 16, 4, 47, 17],
  818. // 27
  819. [8, 152, 122, 4, 153, 123], [22, 73, 45, 3, 74, 46], [8, 53, 23, 26, 54, 24], [12, 45, 15, 28, 46, 16],
  820. // 28
  821. [3, 147, 117, 10, 148, 118], [3, 73, 45, 23, 74, 46], [4, 54, 24, 31, 55, 25], [11, 45, 15, 31, 46, 16],
  822. // 29
  823. [7, 146, 116, 7, 147, 117], [21, 73, 45, 7, 74, 46], [1, 53, 23, 37, 54, 24], [19, 45, 15, 26, 46, 16],
  824. // 30
  825. [5, 145, 115, 10, 146, 116], [19, 75, 47, 10, 76, 48], [15, 54, 24, 25, 55, 25], [23, 45, 15, 25, 46, 16],
  826. // 31
  827. [13, 145, 115, 3, 146, 116], [2, 74, 46, 29, 75, 47], [42, 54, 24, 1, 55, 25], [23, 45, 15, 28, 46, 16],
  828. // 32
  829. [17, 145, 115], [10, 74, 46, 23, 75, 47], [10, 54, 24, 35, 55, 25], [19, 45, 15, 35, 46, 16],
  830. // 33
  831. [17, 145, 115, 1, 146, 116], [14, 74, 46, 21, 75, 47], [29, 54, 24, 19, 55, 25], [11, 45, 15, 46, 46, 16],
  832. // 34
  833. [13, 145, 115, 6, 146, 116], [14, 74, 46, 23, 75, 47], [44, 54, 24, 7, 55, 25], [59, 46, 16, 1, 47, 17],
  834. // 35
  835. [12, 151, 121, 7, 152, 122], [12, 75, 47, 26, 76, 48], [39, 54, 24, 14, 55, 25], [22, 45, 15, 41, 46, 16],
  836. // 36
  837. [6, 151, 121, 14, 152, 122], [6, 75, 47, 34, 76, 48], [46, 54, 24, 10, 55, 25], [2, 45, 15, 64, 46, 16],
  838. // 37
  839. [17, 152, 122, 4, 153, 123], [29, 74, 46, 14, 75, 47], [49, 54, 24, 10, 55, 25], [24, 45, 15, 46, 46, 16],
  840. // 38
  841. [4, 152, 122, 18, 153, 123], [13, 74, 46, 32, 75, 47], [48, 54, 24, 14, 55, 25], [42, 45, 15, 32, 46, 16],
  842. // 39
  843. [20, 147, 117, 4, 148, 118], [40, 75, 47, 7, 76, 48], [43, 54, 24, 22, 55, 25], [10, 45, 15, 67, 46, 16],
  844. // 40
  845. [19, 148, 118, 6, 149, 119], [18, 75, 47, 31, 76, 48], [34, 54, 24, 34, 55, 25], [20, 45, 15, 61, 46, 16]];
  846. QRRSBlock.getRSBlocks = function (typeNumber, errorCorrectLevel) {
  847. var rsBlock = QRRSBlock.getRsBlockTable(typeNumber, errorCorrectLevel);
  848. if (rsBlock == undefined) {
  849. throw new Error("bad rs block @ typeNumber:" + typeNumber + "/errorCorrectLevel:" + errorCorrectLevel);
  850. }
  851. var length = rsBlock.length / 3;
  852. var list = new Array();
  853. for (var i = 0; i < length; i++) {
  854. var count = rsBlock[i * 3 + 0];
  855. var totalCount = rsBlock[i * 3 + 1];
  856. var dataCount = rsBlock[i * 3 + 2];
  857. for (var j = 0; j < count; j++) {
  858. list.push(new QRRSBlock(totalCount, dataCount));
  859. }
  860. }
  861. return list;
  862. };
  863. QRRSBlock.getRsBlockTable = function (typeNumber, errorCorrectLevel) {
  864. switch (errorCorrectLevel) {
  865. case QRErrorCorrectLevel.L:
  866. return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];
  867. case QRErrorCorrectLevel.M:
  868. return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];
  869. case QRErrorCorrectLevel.Q:
  870. return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];
  871. case QRErrorCorrectLevel.H:
  872. return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];
  873. default:
  874. return undefined;
  875. }
  876. };
  877. //---------------------------------------------------------------------
  878. // QRBitBuffer
  879. //---------------------------------------------------------------------
  880. function QRBitBuffer() {
  881. this.buffer = new Array();
  882. this.length = 0;
  883. }
  884. QRBitBuffer.prototype = {
  885. get: function (index) {
  886. var bufIndex = Math.floor(index / 8);
  887. return (this.buffer[bufIndex] >>> 7 - index % 8 & 1) == 1;
  888. },
  889. put: function (num, length) {
  890. for (var i = 0; i < length; i++) {
  891. this.putBit((num >>> length - i - 1 & 1) == 1);
  892. }
  893. },
  894. getLengthInBits: function () {
  895. return this.length;
  896. },
  897. putBit: function (bit) {
  898. var bufIndex = Math.floor(this.length / 8);
  899. if (this.buffer.length <= bufIndex) {
  900. this.buffer.push(0);
  901. }
  902. if (bit) {
  903. this.buffer[bufIndex] |= 0x80 >>> this.length % 8;
  904. }
  905. this.length++;
  906. }
  907. };
  908. // support Chinese
  909. function utf16to8(str) {
  910. var out, i, len, c;
  911. out = '';
  912. len = str.length;
  913. for (i = 0; i < len; i++) {
  914. c = str.charCodeAt(i);
  915. if (c >= 0x0001 && c <= 0x007F) {
  916. out += str.charAt(i);
  917. } else if (c > 0x07FF) {
  918. out += String.fromCharCode(0xE0 | c >> 12 & 0x0F);
  919. out += String.fromCharCode(0x80 | c >> 6 & 0x3F);
  920. out += String.fromCharCode(0x80 | c >> 0 & 0x3F);
  921. } else {
  922. out += String.fromCharCode(0xC0 | c >> 6 & 0x1F);
  923. out += String.fromCharCode(0x80 | c >> 0 & 0x3F);
  924. }
  925. }
  926. return out;
  927. }
  928. function drawQrcode(options) {
  929. options = options || {};
  930. options = extend(true, {
  931. width: 256,
  932. height: 256,
  933. x: 0,
  934. y: 0,
  935. typeNumber: -1,
  936. correctLevel: QRErrorCorrectLevel.H,
  937. background: '#ffffff',
  938. foreground: '#000000',
  939. image: {
  940. imageResource: '',
  941. dx: 0,
  942. dy: 0,
  943. dWidth: 100,
  944. dHeight: 100
  945. }
  946. }, options);
  947. if (!options.canvasId && !options.ctx) {
  948. console.warn('please set canvasId or ctx!');
  949. return;
  950. }
  951. createCanvas();
  952. function createCanvas() {
  953. // create the qrcode itself
  954. var qrcode = new QRCode(options.typeNumber, options.correctLevel);
  955. qrcode.addData(utf16to8(options.text));
  956. qrcode.make();
  957. // get canvas context
  958. var ctx;
  959. if (options.ctx) {
  960. ctx = options.ctx;
  961. } else {
  962. ctx = options._this ? uni.createCanvasContext && uni.createCanvasContext(options.canvasId, options._this) : uni.createCanvasContext && uni.createCanvasContext(options.canvasId);
  963. }
  964. //背景填充白色,解决分享后背景色变成黑色的问题。
  965. ctx.save();
  966. ctx.setFillStyle('white'); //填充白色
  967. ctx.fillRect(0, 0, options.width + options.x * 2, options.width + options.y * 2); //画出矩形白色背景
  968. ctx.restore();
  969. // compute tileW/tileH based on options.width/options.height
  970. var tileW = options.width / qrcode.getModuleCount();
  971. var tileH = options.height / qrcode.getModuleCount();
  972. // draw in the canvas
  973. for (var row = 0; row < qrcode.getModuleCount(); row++) {
  974. for (var col = 0; col < qrcode.getModuleCount(); col++) {
  975. var style = qrcode.isDark(row, col) ? options.foreground : options.background;
  976. ctx.setFillStyle(style);
  977. var w = Math.ceil((col + 1) * tileW) - Math.floor(col * tileW);
  978. var h = Math.ceil((row + 1) * tileW) - Math.floor(row * tileW);
  979. ctx.fillRect(Math.round(col * tileW) + options.x, Math.round(row * tileH) + options.y, w, h);
  980. }
  981. }
  982. if (options.image.imageResource) {
  983. uni.getImageInfo({
  984. src: options.image.imageResource,
  985. success: function (res) {
  986. var d = options.image.dWidth;
  987. var cx = options.image.dx + options.image.dWidth / 2;
  988. var cy = options.image.dy + options.image.dWidth / 2;
  989. ctx.arc(cx, cy, options.image.dWidth / 2, 0, 2 * Math.PI);
  990. ctx.clip();
  991. ctx.drawImage(res.path, options.image.dx, options.image.dy, options.image.dWidth, options.image.dHeight);
  992. setTimeout(() => {
  993. ctx.draw(false, function (e) {
  994. setTimeout(() => {
  995. options.callback && options.callback(e);
  996. }, 200);
  997. });
  998. }, 100);
  999. },
  1000. fail: function () {
  1001. setTimeout(() => {
  1002. ctx.draw(false, function (e) {
  1003. setTimeout(() => {
  1004. options.callback && options.callback(e);
  1005. }, 200);
  1006. });
  1007. }, 100);
  1008. }
  1009. });
  1010. //ctx.drawImage(options.image.imageResource, options.image.dx, options.image.dy, options.image.dWidth, options.image.dHeight);
  1011. } else {
  1012. ctx.draw(false, function (e) {
  1013. setTimeout(() => {
  1014. options.callback && options.callback(e);
  1015. }, 200);
  1016. });
  1017. }
  1018. }
  1019. }
  1020. return drawQrcode;
  1021. });