QRCodeJS

二维码生成库

This script should not be not be installed directly. It is a library for other scripts to include with the meta directive // @require https://update.greatest.deepsurf.us/scripts/497907/1413262/QRCodeJS.js

  1. /**
  2. * @fileoverview
  3. * - Using the 'QRCode for Javascript library'
  4. * - Fixed dataset of 'QRCode for Javascript library' for support full-spec.
  5. * - this library has no dependencies.
  6. * -
  7. *
  8. * @author davidshimjs
  9. * @see <a href="http://www.d-project.com/" target="_blank">http://www.d-project.com/</a>
  10. * @see <a href="http://jeromeetienne.github.com/jquery-qrcode/" target="_blank">http://jeromeetienne.github.com/jquery-qrcode/</a>
  11. */
  12.  
  13. (function (global, factory) {
  14. typeof exports === "object" && typeof module !== "undefined"
  15. ? (module.exports = factory())
  16. : typeof define === "function" && define.amd
  17. ? define(factory)
  18. : ((global =
  19. typeof globalThis !== "undefined" ? globalThis : global || self),
  20. (global.QRCode = factory()));
  21. })(this, function () {
  22. //---------------------------------------------------------------------
  23. // QRCode for JavaScript
  24. //
  25. // Copyright (c) 2009 Kazuhiko Arase
  26. //
  27. // URL: http://www.d-project.com/
  28. //
  29. // Licensed under the MIT license:
  30. // http://www.opensource.org/licenses/mit-license.php
  31. //
  32. // The word "QR Code" is registered trademark of
  33. // DENSO WAVE INCORPORATED
  34. // http://www.denso-wave.com/qrcode/faqpatent-e.html
  35. //
  36. //---------------------------------------------------------------------
  37. function QR8bitByte(data) {
  38. this.mode = QRMode.MODE_8BIT_BYTE;
  39. this.data = data;
  40. this.parsedData = [];
  41.  
  42. // Added to support UTF-8 Characters
  43. for (var i = 0, l = this.data.length; i < l; i++) {
  44. var byteArray = [];
  45. var code = this.data.charCodeAt(i);
  46.  
  47. if (code > 0x10000) {
  48. byteArray[0] = 0xf0 | ((code & 0x1c0000) >>> 18);
  49. byteArray[1] = 0x80 | ((code & 0x3f000) >>> 12);
  50. byteArray[2] = 0x80 | ((code & 0xfc0) >>> 6);
  51. byteArray[3] = 0x80 | (code & 0x3f);
  52. } else if (code > 0x800) {
  53. byteArray[0] = 0xe0 | ((code & 0xf000) >>> 12);
  54. byteArray[1] = 0x80 | ((code & 0xfc0) >>> 6);
  55. byteArray[2] = 0x80 | (code & 0x3f);
  56. } else if (code > 0x80) {
  57. byteArray[0] = 0xc0 | ((code & 0x7c0) >>> 6);
  58. byteArray[1] = 0x80 | (code & 0x3f);
  59. } else {
  60. byteArray[0] = code;
  61. }
  62.  
  63. this.parsedData.push(byteArray);
  64. }
  65.  
  66. this.parsedData = Array.prototype.concat.apply([], this.parsedData);
  67.  
  68. if (this.parsedData.length != this.data.length) {
  69. this.parsedData.unshift(191);
  70. this.parsedData.unshift(187);
  71. this.parsedData.unshift(239);
  72. }
  73. }
  74.  
  75. QR8bitByte.prototype = {
  76. getLength: function (buffer) {
  77. return this.parsedData.length;
  78. },
  79. write: function (buffer) {
  80. for (var i = 0, l = this.parsedData.length; i < l; i++) {
  81. buffer.put(this.parsedData[i], 8);
  82. }
  83. },
  84. };
  85.  
  86. function QRCodeModel(typeNumber, errorCorrectLevel) {
  87. this.typeNumber = typeNumber;
  88. this.errorCorrectLevel = errorCorrectLevel;
  89. this.modules = null;
  90. this.moduleCount = 0;
  91. this.dataCache = null;
  92. this.dataList = [];
  93. }
  94.  
  95. QRCodeModel.prototype = {
  96. addData: function (data) {
  97. var newData = new QR8bitByte(data);
  98. this.dataList.push(newData);
  99. this.dataCache = null;
  100. },
  101. isDark: function (row, col) {
  102. if (
  103. row < 0 ||
  104. this.moduleCount <= row ||
  105. col < 0 ||
  106. this.moduleCount <= col
  107. ) {
  108. throw new Error(row + "," + col);
  109. }
  110. return this.modules[row][col];
  111. },
  112. getModuleCount: function () {
  113. return this.moduleCount;
  114. },
  115. make: function () {
  116. this.makeImpl(false, this.getBestMaskPattern());
  117. },
  118. makeImpl: function (test, maskPattern) {
  119. this.moduleCount = this.typeNumber * 4 + 17;
  120. this.modules = new Array(this.moduleCount);
  121. for (var row = 0; row < this.moduleCount; row++) {
  122. this.modules[row] = new Array(this.moduleCount);
  123. for (var col = 0; col < this.moduleCount; col++) {
  124. this.modules[row][col] = null;
  125. }
  126. }
  127. this.setupPositionProbePattern(0, 0);
  128. this.setupPositionProbePattern(this.moduleCount - 7, 0);
  129. this.setupPositionProbePattern(0, this.moduleCount - 7);
  130. this.setupPositionAdjustPattern();
  131. this.setupTimingPattern();
  132. this.setupTypeInfo(test, maskPattern);
  133. if (this.typeNumber >= 7) {
  134. this.setupTypeNumber(test);
  135. }
  136. if (this.dataCache == null) {
  137. this.dataCache = QRCodeModel.createData(
  138. this.typeNumber,
  139. this.errorCorrectLevel,
  140. this.dataList
  141. );
  142. }
  143. this.mapData(this.dataCache, maskPattern);
  144. },
  145. setupPositionProbePattern: function (row, col) {
  146. for (var r = -1; r <= 7; r++) {
  147. if (row + r <= -1 || this.moduleCount <= row + r) continue;
  148. for (var c = -1; c <= 7; c++) {
  149. if (col + c <= -1 || this.moduleCount <= col + c) continue;
  150. if (
  151. (0 <= r && r <= 6 && (c == 0 || c == 6)) ||
  152. (0 <= c && c <= 6 && (r == 0 || r == 6)) ||
  153. (2 <= r && r <= 4 && 2 <= c && c <= 4)
  154. ) {
  155. this.modules[row + r][col + c] = true;
  156. } else {
  157. this.modules[row + r][col + c] = false;
  158. }
  159. }
  160. }
  161. },
  162. getBestMaskPattern: function () {
  163. var minLostPoint = 0;
  164. var pattern = 0;
  165. for (var i = 0; i < 8; i++) {
  166. this.makeImpl(true, i);
  167. var lostPoint = QRUtil.getLostPoint(this);
  168. if (i == 0 || minLostPoint > lostPoint) {
  169. minLostPoint = lostPoint;
  170. pattern = i;
  171. }
  172. }
  173. return pattern;
  174. },
  175. createMovieClip: function (target_mc, instance_name, depth) {
  176. var qr_mc = target_mc.createEmptyMovieClip(instance_name, depth);
  177. var cs = 1;
  178. this.make();
  179. for (var row = 0; row < this.modules.length; row++) {
  180. var y = row * cs;
  181. for (var col = 0; col < this.modules[row].length; col++) {
  182. var x = col * cs;
  183. var dark = this.modules[row][col];
  184. if (dark) {
  185. qr_mc.beginFill(0, 100);
  186. qr_mc.moveTo(x, y);
  187. qr_mc.lineTo(x + cs, y);
  188. qr_mc.lineTo(x + cs, y + cs);
  189. qr_mc.lineTo(x, y + cs);
  190. qr_mc.endFill();
  191. }
  192. }
  193. }
  194. return qr_mc;
  195. },
  196. setupTimingPattern: function () {
  197. for (var r = 8; r < this.moduleCount - 8; r++) {
  198. if (this.modules[r][6] != null) {
  199. continue;
  200. }
  201. this.modules[r][6] = r % 2 == 0;
  202. }
  203. for (var c = 8; c < this.moduleCount - 8; c++) {
  204. if (this.modules[6][c] != null) {
  205. continue;
  206. }
  207. this.modules[6][c] = c % 2 == 0;
  208. }
  209. },
  210. setupPositionAdjustPattern: function () {
  211. var pos = QRUtil.getPatternPosition(this.typeNumber);
  212. for (var i = 0; i < pos.length; i++) {
  213. for (var j = 0; j < pos.length; j++) {
  214. var row = pos[i];
  215. var col = pos[j];
  216. if (this.modules[row][col] != null) {
  217. continue;
  218. }
  219. for (var r = -2; r <= 2; r++) {
  220. for (var c = -2; c <= 2; c++) {
  221. if (
  222. r == -2 ||
  223. r == 2 ||
  224. c == -2 ||
  225. c == 2 ||
  226. (r == 0 && c == 0)
  227. ) {
  228. this.modules[row + r][col + c] = true;
  229. } else {
  230. this.modules[row + r][col + c] = false;
  231. }
  232. }
  233. }
  234. }
  235. }
  236. },
  237. setupTypeNumber: function (test) {
  238. var bits = QRUtil.getBCHTypeNumber(this.typeNumber);
  239. for (var i = 0; i < 18; i++) {
  240. var mod = !test && ((bits >> i) & 1) == 1;
  241. this.modules[Math.floor(i / 3)][(i % 3) + this.moduleCount - 8 - 3] =
  242. mod;
  243. }
  244. for (var i = 0; i < 18; i++) {
  245. var mod = !test && ((bits >> i) & 1) == 1;
  246. this.modules[(i % 3) + this.moduleCount - 8 - 3][Math.floor(i / 3)] =
  247. mod;
  248. }
  249. },
  250. setupTypeInfo: function (test, maskPattern) {
  251. var data = (this.errorCorrectLevel << 3) | maskPattern;
  252. var bits = QRUtil.getBCHTypeInfo(data);
  253. for (var i = 0; i < 15; i++) {
  254. var mod = !test && ((bits >> i) & 1) == 1;
  255. if (i < 6) {
  256. this.modules[i][8] = mod;
  257. } else if (i < 8) {
  258. this.modules[i + 1][8] = mod;
  259. } else {
  260. this.modules[this.moduleCount - 15 + i][8] = mod;
  261. }
  262. }
  263. for (var i = 0; i < 15; i++) {
  264. var mod = !test && ((bits >> i) & 1) == 1;
  265. if (i < 8) {
  266. this.modules[8][this.moduleCount - i - 1] = mod;
  267. } else if (i < 9) {
  268. this.modules[8][15 - i - 1 + 1] = mod;
  269. } else {
  270. this.modules[8][15 - i - 1] = mod;
  271. }
  272. }
  273. this.modules[this.moduleCount - 8][8] = !test;
  274. },
  275. mapData: function (data, maskPattern) {
  276. var inc = -1;
  277. var row = this.moduleCount - 1;
  278. var bitIndex = 7;
  279. var byteIndex = 0;
  280. for (var col = this.moduleCount - 1; col > 0; col -= 2) {
  281. if (col == 6) col--;
  282. while (true) {
  283. for (var c = 0; c < 2; c++) {
  284. if (this.modules[row][col - c] == null) {
  285. var dark = false;
  286. if (byteIndex < data.length) {
  287. dark = ((data[byteIndex] >>> bitIndex) & 1) == 1;
  288. }
  289. var mask = QRUtil.getMask(maskPattern, row, col - c);
  290. if (mask) {
  291. dark = !dark;
  292. }
  293. this.modules[row][col - c] = dark;
  294. bitIndex--;
  295. if (bitIndex == -1) {
  296. byteIndex++;
  297. bitIndex = 7;
  298. }
  299. }
  300. }
  301. row += inc;
  302. if (row < 0 || this.moduleCount <= row) {
  303. row -= inc;
  304. inc = -inc;
  305. break;
  306. }
  307. }
  308. }
  309. },
  310. };
  311. QRCodeModel.PAD0 = 0xec;
  312. QRCodeModel.PAD1 = 0x11;
  313. QRCodeModel.createData = function (typeNumber, errorCorrectLevel, dataList) {
  314. var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel);
  315. var buffer = new QRBitBuffer();
  316. for (var i = 0; i < dataList.length; i++) {
  317. var data = dataList[i];
  318. buffer.put(data.mode, 4);
  319. buffer.put(
  320. data.getLength(),
  321. QRUtil.getLengthInBits(data.mode, typeNumber)
  322. );
  323. data.write(buffer);
  324. }
  325. var totalDataCount = 0;
  326. for (var i = 0; i < rsBlocks.length; i++) {
  327. totalDataCount += rsBlocks[i].dataCount;
  328. }
  329. if (buffer.getLengthInBits() > totalDataCount * 8) {
  330. throw new Error(
  331. "code length overflow. (" +
  332. buffer.getLengthInBits() +
  333. ">" +
  334. totalDataCount * 8 +
  335. ")"
  336. );
  337. }
  338. if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {
  339. buffer.put(0, 4);
  340. }
  341. while (buffer.getLengthInBits() % 8 != 0) {
  342. buffer.putBit(false);
  343. }
  344. while (true) {
  345. if (buffer.getLengthInBits() >= totalDataCount * 8) {
  346. break;
  347. }
  348. buffer.put(QRCodeModel.PAD0, 8);
  349. if (buffer.getLengthInBits() >= totalDataCount * 8) {
  350. break;
  351. }
  352. buffer.put(QRCodeModel.PAD1, 8);
  353. }
  354. return QRCodeModel.createBytes(buffer, rsBlocks);
  355. };
  356. QRCodeModel.createBytes = function (buffer, rsBlocks) {
  357. var offset = 0;
  358. var maxDcCount = 0;
  359. var maxEcCount = 0;
  360. var dcdata = new Array(rsBlocks.length);
  361. var ecdata = new Array(rsBlocks.length);
  362. for (var r = 0; r < rsBlocks.length; r++) {
  363. var dcCount = rsBlocks[r].dataCount;
  364. var ecCount = rsBlocks[r].totalCount - dcCount;
  365. maxDcCount = Math.max(maxDcCount, dcCount);
  366. maxEcCount = Math.max(maxEcCount, ecCount);
  367. dcdata[r] = new Array(dcCount);
  368. for (var i = 0; i < dcdata[r].length; i++) {
  369. dcdata[r][i] = 0xff & buffer.buffer[i + offset];
  370. }
  371. offset += dcCount;
  372. var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
  373. var rawPoly = new QRPolynomial(dcdata[r], rsPoly.getLength() - 1);
  374. var modPoly = rawPoly.mod(rsPoly);
  375. ecdata[r] = new Array(rsPoly.getLength() - 1);
  376. for (var i = 0; i < ecdata[r].length; i++) {
  377. var modIndex = i + modPoly.getLength() - ecdata[r].length;
  378. ecdata[r][i] = modIndex >= 0 ? modPoly.get(modIndex) : 0;
  379. }
  380. }
  381. var totalCodeCount = 0;
  382. for (var i = 0; i < rsBlocks.length; i++) {
  383. totalCodeCount += rsBlocks[i].totalCount;
  384. }
  385. var data = new Array(totalCodeCount);
  386. var index = 0;
  387. for (var i = 0; i < maxDcCount; i++) {
  388. for (var r = 0; r < rsBlocks.length; r++) {
  389. if (i < dcdata[r].length) {
  390. data[index++] = dcdata[r][i];
  391. }
  392. }
  393. }
  394. for (var i = 0; i < maxEcCount; i++) {
  395. for (var r = 0; r < rsBlocks.length; r++) {
  396. if (i < ecdata[r].length) {
  397. data[index++] = ecdata[r][i];
  398. }
  399. }
  400. }
  401. return data;
  402. };
  403. var QRMode = {
  404. MODE_NUMBER: 1 << 0,
  405. MODE_ALPHA_NUM: 1 << 1,
  406. MODE_8BIT_BYTE: 1 << 2,
  407. MODE_KANJI: 1 << 3,
  408. };
  409. var QRErrorCorrectLevel = { L: 1, M: 0, Q: 3, H: 2 };
  410. var QRMaskPattern = {
  411. PATTERN000: 0,
  412. PATTERN001: 1,
  413. PATTERN010: 2,
  414. PATTERN011: 3,
  415. PATTERN100: 4,
  416. PATTERN101: 5,
  417. PATTERN110: 6,
  418. PATTERN111: 7,
  419. };
  420. var QRUtil = {
  421. PATTERN_POSITION_TABLE: [
  422. [],
  423. [6, 18],
  424. [6, 22],
  425. [6, 26],
  426. [6, 30],
  427. [6, 34],
  428. [6, 22, 38],
  429. [6, 24, 42],
  430. [6, 26, 46],
  431. [6, 28, 50],
  432. [6, 30, 54],
  433. [6, 32, 58],
  434. [6, 34, 62],
  435. [6, 26, 46, 66],
  436. [6, 26, 48, 70],
  437. [6, 26, 50, 74],
  438. [6, 30, 54, 78],
  439. [6, 30, 56, 82],
  440. [6, 30, 58, 86],
  441. [6, 34, 62, 90],
  442. [6, 28, 50, 72, 94],
  443. [6, 26, 50, 74, 98],
  444. [6, 30, 54, 78, 102],
  445. [6, 28, 54, 80, 106],
  446. [6, 32, 58, 84, 110],
  447. [6, 30, 58, 86, 114],
  448. [6, 34, 62, 90, 118],
  449. [6, 26, 50, 74, 98, 122],
  450. [6, 30, 54, 78, 102, 126],
  451. [6, 26, 52, 78, 104, 130],
  452. [6, 30, 56, 82, 108, 134],
  453. [6, 34, 60, 86, 112, 138],
  454. [6, 30, 58, 86, 114, 142],
  455. [6, 34, 62, 90, 118, 146],
  456. [6, 30, 54, 78, 102, 126, 150],
  457. [6, 24, 50, 76, 102, 128, 154],
  458. [6, 28, 54, 80, 106, 132, 158],
  459. [6, 32, 58, 84, 110, 136, 162],
  460. [6, 26, 54, 82, 110, 138, 166],
  461. [6, 30, 58, 86, 114, 142, 170],
  462. ],
  463. G15:
  464. (1 << 10) |
  465. (1 << 8) |
  466. (1 << 5) |
  467. (1 << 4) |
  468. (1 << 2) |
  469. (1 << 1) |
  470. (1 << 0),
  471. G18:
  472. (1 << 12) |
  473. (1 << 11) |
  474. (1 << 10) |
  475. (1 << 9) |
  476. (1 << 8) |
  477. (1 << 5) |
  478. (1 << 2) |
  479. (1 << 0),
  480. G15_MASK: (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1),
  481. getBCHTypeInfo: function (data) {
  482. var d = data << 10;
  483. while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0) {
  484. d ^=
  485. QRUtil.G15 <<
  486. (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15));
  487. }
  488. return ((data << 10) | d) ^ QRUtil.G15_MASK;
  489. },
  490. getBCHTypeNumber: function (data) {
  491. var d = data << 12;
  492. while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0) {
  493. d ^=
  494. QRUtil.G18 <<
  495. (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18));
  496. }
  497. return (data << 12) | d;
  498. },
  499. getBCHDigit: function (data) {
  500. var digit = 0;
  501. while (data != 0) {
  502. digit++;
  503. data >>>= 1;
  504. }
  505. return digit;
  506. },
  507. getPatternPosition: function (typeNumber) {
  508. return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1];
  509. },
  510. getMask: function (maskPattern, i, j) {
  511. switch (maskPattern) {
  512. case QRMaskPattern.PATTERN000:
  513. return (i + j) % 2 == 0;
  514. case QRMaskPattern.PATTERN001:
  515. return i % 2 == 0;
  516. case QRMaskPattern.PATTERN010:
  517. return j % 3 == 0;
  518. case QRMaskPattern.PATTERN011:
  519. return (i + j) % 3 == 0;
  520. case QRMaskPattern.PATTERN100:
  521. return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 == 0;
  522. case QRMaskPattern.PATTERN101:
  523. return ((i * j) % 2) + ((i * j) % 3) == 0;
  524. case QRMaskPattern.PATTERN110:
  525. return (((i * j) % 2) + ((i * j) % 3)) % 2 == 0;
  526. case QRMaskPattern.PATTERN111:
  527. return (((i * j) % 3) + ((i + j) % 2)) % 2 == 0;
  528. default:
  529. throw new Error("bad maskPattern:" + maskPattern);
  530. }
  531. },
  532. getErrorCorrectPolynomial: function (errorCorrectLength) {
  533. var a = new QRPolynomial([1], 0);
  534. for (var i = 0; i < errorCorrectLength; i++) {
  535. a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0));
  536. }
  537. return a;
  538. },
  539. getLengthInBits: function (mode, type) {
  540. if (1 <= type && type < 10) {
  541. switch (mode) {
  542. case QRMode.MODE_NUMBER:
  543. return 10;
  544. case QRMode.MODE_ALPHA_NUM:
  545. return 9;
  546. case QRMode.MODE_8BIT_BYTE:
  547. return 8;
  548. case QRMode.MODE_KANJI:
  549. return 8;
  550. default:
  551. throw new Error("mode:" + mode);
  552. }
  553. } else if (type < 27) {
  554. switch (mode) {
  555. case QRMode.MODE_NUMBER:
  556. return 12;
  557. case QRMode.MODE_ALPHA_NUM:
  558. return 11;
  559. case QRMode.MODE_8BIT_BYTE:
  560. return 16;
  561. case QRMode.MODE_KANJI:
  562. return 10;
  563. default:
  564. throw new Error("mode:" + mode);
  565. }
  566. } else if (type < 41) {
  567. switch (mode) {
  568. case QRMode.MODE_NUMBER:
  569. return 14;
  570. case QRMode.MODE_ALPHA_NUM:
  571. return 13;
  572. case QRMode.MODE_8BIT_BYTE:
  573. return 16;
  574. case QRMode.MODE_KANJI:
  575. return 12;
  576. default:
  577. throw new Error("mode:" + mode);
  578. }
  579. } else {
  580. throw new Error("type:" + type);
  581. }
  582. },
  583. getLostPoint: function (qrCode) {
  584. var moduleCount = qrCode.getModuleCount();
  585. var lostPoint = 0;
  586. for (var row = 0; row < moduleCount; row++) {
  587. for (var col = 0; col < moduleCount; col++) {
  588. var sameCount = 0;
  589. var dark = qrCode.isDark(row, col);
  590. for (var r = -1; r <= 1; r++) {
  591. if (row + r < 0 || moduleCount <= row + r) {
  592. continue;
  593. }
  594. for (var c = -1; c <= 1; c++) {
  595. if (col + c < 0 || moduleCount <= col + c) {
  596. continue;
  597. }
  598. if (r == 0 && c == 0) {
  599. continue;
  600. }
  601. if (dark == qrCode.isDark(row + r, col + c)) {
  602. sameCount++;
  603. }
  604. }
  605. }
  606. if (sameCount > 5) {
  607. lostPoint += 3 + sameCount - 5;
  608. }
  609. }
  610. }
  611. for (var row = 0; row < moduleCount - 1; row++) {
  612. for (var col = 0; col < moduleCount - 1; col++) {
  613. var count = 0;
  614. if (qrCode.isDark(row, col)) count++;
  615. if (qrCode.isDark(row + 1, col)) count++;
  616. if (qrCode.isDark(row, col + 1)) count++;
  617. if (qrCode.isDark(row + 1, col + 1)) count++;
  618. if (count == 0 || count == 4) {
  619. lostPoint += 3;
  620. }
  621. }
  622. }
  623. for (var row = 0; row < moduleCount; row++) {
  624. for (var col = 0; col < moduleCount - 6; col++) {
  625. if (
  626. qrCode.isDark(row, col) &&
  627. !qrCode.isDark(row, col + 1) &&
  628. qrCode.isDark(row, col + 2) &&
  629. qrCode.isDark(row, col + 3) &&
  630. qrCode.isDark(row, col + 4) &&
  631. !qrCode.isDark(row, col + 5) &&
  632. qrCode.isDark(row, col + 6)
  633. ) {
  634. lostPoint += 40;
  635. }
  636. }
  637. }
  638. for (var col = 0; col < moduleCount; col++) {
  639. for (var row = 0; row < moduleCount - 6; row++) {
  640. if (
  641. qrCode.isDark(row, col) &&
  642. !qrCode.isDark(row + 1, col) &&
  643. qrCode.isDark(row + 2, col) &&
  644. qrCode.isDark(row + 3, col) &&
  645. qrCode.isDark(row + 4, col) &&
  646. !qrCode.isDark(row + 5, col) &&
  647. qrCode.isDark(row + 6, col)
  648. ) {
  649. lostPoint += 40;
  650. }
  651. }
  652. }
  653. var darkCount = 0;
  654. for (var col = 0; col < moduleCount; col++) {
  655. for (var row = 0; row < moduleCount; row++) {
  656. if (qrCode.isDark(row, col)) {
  657. darkCount++;
  658. }
  659. }
  660. }
  661. var ratio =
  662. Math.abs((100 * darkCount) / moduleCount / moduleCount - 50) / 5;
  663. lostPoint += ratio * 10;
  664. return lostPoint;
  665. },
  666. };
  667. var QRMath = {
  668. glog: function (n) {
  669. if (n < 1) {
  670. throw new Error("glog(" + n + ")");
  671. }
  672. return QRMath.LOG_TABLE[n];
  673. },
  674. gexp: function (n) {
  675. while (n < 0) {
  676. n += 255;
  677. }
  678. while (n >= 256) {
  679. n -= 255;
  680. }
  681. return QRMath.EXP_TABLE[n];
  682. },
  683. EXP_TABLE: new Array(256),
  684. LOG_TABLE: new Array(256),
  685. };
  686. for (var i = 0; i < 8; i++) {
  687. QRMath.EXP_TABLE[i] = 1 << i;
  688. }
  689. for (var i = 8; i < 256; i++) {
  690. QRMath.EXP_TABLE[i] =
  691. QRMath.EXP_TABLE[i - 4] ^
  692. QRMath.EXP_TABLE[i - 5] ^
  693. QRMath.EXP_TABLE[i - 6] ^
  694. QRMath.EXP_TABLE[i - 8];
  695. }
  696. for (var i = 0; i < 255; i++) {
  697. QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]] = i;
  698. }
  699. function QRPolynomial(num, shift) {
  700. if (num.length == undefined) {
  701. throw new Error(num.length + "/" + shift);
  702. }
  703. var offset = 0;
  704. while (offset < num.length && num[offset] == 0) {
  705. offset++;
  706. }
  707. this.num = new Array(num.length - offset + shift);
  708. for (var i = 0; i < num.length - offset; i++) {
  709. this.num[i] = num[i + offset];
  710. }
  711. }
  712. QRPolynomial.prototype = {
  713. get: function (index) {
  714. return this.num[index];
  715. },
  716. getLength: function () {
  717. return this.num.length;
  718. },
  719. multiply: function (e) {
  720. var num = new Array(this.getLength() + e.getLength() - 1);
  721. for (var i = 0; i < this.getLength(); i++) {
  722. for (var j = 0; j < e.getLength(); j++) {
  723. num[i + j] ^= QRMath.gexp(
  724. QRMath.glog(this.get(i)) + QRMath.glog(e.get(j))
  725. );
  726. }
  727. }
  728. return new QRPolynomial(num, 0);
  729. },
  730. mod: function (e) {
  731. if (this.getLength() - e.getLength() < 0) {
  732. return this;
  733. }
  734. var ratio = QRMath.glog(this.get(0)) - QRMath.glog(e.get(0));
  735. var num = new Array(this.getLength());
  736. for (var i = 0; i < this.getLength(); i++) {
  737. num[i] = this.get(i);
  738. }
  739. for (var i = 0; i < e.getLength(); i++) {
  740. num[i] ^= QRMath.gexp(QRMath.glog(e.get(i)) + ratio);
  741. }
  742. return new QRPolynomial(num, 0).mod(e);
  743. },
  744. };
  745. function QRRSBlock(totalCount, dataCount) {
  746. this.totalCount = totalCount;
  747. this.dataCount = dataCount;
  748. }
  749. QRRSBlock.RS_BLOCK_TABLE = [
  750. [1, 26, 19],
  751. [1, 26, 16],
  752. [1, 26, 13],
  753. [1, 26, 9],
  754. [1, 44, 34],
  755. [1, 44, 28],
  756. [1, 44, 22],
  757. [1, 44, 16],
  758. [1, 70, 55],
  759. [1, 70, 44],
  760. [2, 35, 17],
  761. [2, 35, 13],
  762. [1, 100, 80],
  763. [2, 50, 32],
  764. [2, 50, 24],
  765. [4, 25, 9],
  766. [1, 134, 108],
  767. [2, 67, 43],
  768. [2, 33, 15, 2, 34, 16],
  769. [2, 33, 11, 2, 34, 12],
  770. [2, 86, 68],
  771. [4, 43, 27],
  772. [4, 43, 19],
  773. [4, 43, 15],
  774. [2, 98, 78],
  775. [4, 49, 31],
  776. [2, 32, 14, 4, 33, 15],
  777. [4, 39, 13, 1, 40, 14],
  778. [2, 121, 97],
  779. [2, 60, 38, 2, 61, 39],
  780. [4, 40, 18, 2, 41, 19],
  781. [4, 40, 14, 2, 41, 15],
  782. [2, 146, 116],
  783. [3, 58, 36, 2, 59, 37],
  784. [4, 36, 16, 4, 37, 17],
  785. [4, 36, 12, 4, 37, 13],
  786. [2, 86, 68, 2, 87, 69],
  787. [4, 69, 43, 1, 70, 44],
  788. [6, 43, 19, 2, 44, 20],
  789. [6, 43, 15, 2, 44, 16],
  790. [4, 101, 81],
  791. [1, 80, 50, 4, 81, 51],
  792. [4, 50, 22, 4, 51, 23],
  793. [3, 36, 12, 8, 37, 13],
  794. [2, 116, 92, 2, 117, 93],
  795. [6, 58, 36, 2, 59, 37],
  796. [4, 46, 20, 6, 47, 21],
  797. [7, 42, 14, 4, 43, 15],
  798. [4, 133, 107],
  799. [8, 59, 37, 1, 60, 38],
  800. [8, 44, 20, 4, 45, 21],
  801. [12, 33, 11, 4, 34, 12],
  802. [3, 145, 115, 1, 146, 116],
  803. [4, 64, 40, 5, 65, 41],
  804. [11, 36, 16, 5, 37, 17],
  805. [11, 36, 12, 5, 37, 13],
  806. [5, 109, 87, 1, 110, 88],
  807. [5, 65, 41, 5, 66, 42],
  808. [5, 54, 24, 7, 55, 25],
  809. [11, 36, 12],
  810. [5, 122, 98, 1, 123, 99],
  811. [7, 73, 45, 3, 74, 46],
  812. [15, 43, 19, 2, 44, 20],
  813. [3, 45, 15, 13, 46, 16],
  814. [1, 135, 107, 5, 136, 108],
  815. [10, 74, 46, 1, 75, 47],
  816. [1, 50, 22, 15, 51, 23],
  817. [2, 42, 14, 17, 43, 15],
  818. [5, 150, 120, 1, 151, 121],
  819. [9, 69, 43, 4, 70, 44],
  820. [17, 50, 22, 1, 51, 23],
  821. [2, 42, 14, 19, 43, 15],
  822. [3, 141, 113, 4, 142, 114],
  823. [3, 70, 44, 11, 71, 45],
  824. [17, 47, 21, 4, 48, 22],
  825. [9, 39, 13, 16, 40, 14],
  826. [3, 135, 107, 5, 136, 108],
  827. [3, 67, 41, 13, 68, 42],
  828. [15, 54, 24, 5, 55, 25],
  829. [15, 43, 15, 10, 44, 16],
  830. [4, 144, 116, 4, 145, 117],
  831. [17, 68, 42],
  832. [17, 50, 22, 6, 51, 23],
  833. [19, 46, 16, 6, 47, 17],
  834. [2, 139, 111, 7, 140, 112],
  835. [17, 74, 46],
  836. [7, 54, 24, 16, 55, 25],
  837. [34, 37, 13],
  838. [4, 151, 121, 5, 152, 122],
  839. [4, 75, 47, 14, 76, 48],
  840. [11, 54, 24, 14, 55, 25],
  841. [16, 45, 15, 14, 46, 16],
  842. [6, 147, 117, 4, 148, 118],
  843. [6, 73, 45, 14, 74, 46],
  844. [11, 54, 24, 16, 55, 25],
  845. [30, 46, 16, 2, 47, 17],
  846. [8, 132, 106, 4, 133, 107],
  847. [8, 75, 47, 13, 76, 48],
  848. [7, 54, 24, 22, 55, 25],
  849. [22, 45, 15, 13, 46, 16],
  850. [10, 142, 114, 2, 143, 115],
  851. [19, 74, 46, 4, 75, 47],
  852. [28, 50, 22, 6, 51, 23],
  853. [33, 46, 16, 4, 47, 17],
  854. [8, 152, 122, 4, 153, 123],
  855. [22, 73, 45, 3, 74, 46],
  856. [8, 53, 23, 26, 54, 24],
  857. [12, 45, 15, 28, 46, 16],
  858. [3, 147, 117, 10, 148, 118],
  859. [3, 73, 45, 23, 74, 46],
  860. [4, 54, 24, 31, 55, 25],
  861. [11, 45, 15, 31, 46, 16],
  862. [7, 146, 116, 7, 147, 117],
  863. [21, 73, 45, 7, 74, 46],
  864. [1, 53, 23, 37, 54, 24],
  865. [19, 45, 15, 26, 46, 16],
  866. [5, 145, 115, 10, 146, 116],
  867. [19, 75, 47, 10, 76, 48],
  868. [15, 54, 24, 25, 55, 25],
  869. [23, 45, 15, 25, 46, 16],
  870. [13, 145, 115, 3, 146, 116],
  871. [2, 74, 46, 29, 75, 47],
  872. [42, 54, 24, 1, 55, 25],
  873. [23, 45, 15, 28, 46, 16],
  874. [17, 145, 115],
  875. [10, 74, 46, 23, 75, 47],
  876. [10, 54, 24, 35, 55, 25],
  877. [19, 45, 15, 35, 46, 16],
  878. [17, 145, 115, 1, 146, 116],
  879. [14, 74, 46, 21, 75, 47],
  880. [29, 54, 24, 19, 55, 25],
  881. [11, 45, 15, 46, 46, 16],
  882. [13, 145, 115, 6, 146, 116],
  883. [14, 74, 46, 23, 75, 47],
  884. [44, 54, 24, 7, 55, 25],
  885. [59, 46, 16, 1, 47, 17],
  886. [12, 151, 121, 7, 152, 122],
  887. [12, 75, 47, 26, 76, 48],
  888. [39, 54, 24, 14, 55, 25],
  889. [22, 45, 15, 41, 46, 16],
  890. [6, 151, 121, 14, 152, 122],
  891. [6, 75, 47, 34, 76, 48],
  892. [46, 54, 24, 10, 55, 25],
  893. [2, 45, 15, 64, 46, 16],
  894. [17, 152, 122, 4, 153, 123],
  895. [29, 74, 46, 14, 75, 47],
  896. [49, 54, 24, 10, 55, 25],
  897. [24, 45, 15, 46, 46, 16],
  898. [4, 152, 122, 18, 153, 123],
  899. [13, 74, 46, 32, 75, 47],
  900. [48, 54, 24, 14, 55, 25],
  901. [42, 45, 15, 32, 46, 16],
  902. [20, 147, 117, 4, 148, 118],
  903. [40, 75, 47, 7, 76, 48],
  904. [43, 54, 24, 22, 55, 25],
  905. [10, 45, 15, 67, 46, 16],
  906. [19, 148, 118, 6, 149, 119],
  907. [18, 75, 47, 31, 76, 48],
  908. [34, 54, 24, 34, 55, 25],
  909. [20, 45, 15, 61, 46, 16],
  910. ];
  911. QRRSBlock.getRSBlocks = function (typeNumber, errorCorrectLevel) {
  912. var rsBlock = QRRSBlock.getRsBlockTable(typeNumber, errorCorrectLevel);
  913. if (rsBlock == undefined) {
  914. throw new Error(
  915. "bad rs block @ typeNumber:" +
  916. typeNumber +
  917. "/errorCorrectLevel:" +
  918. errorCorrectLevel
  919. );
  920. }
  921. var length = rsBlock.length / 3;
  922. var list = [];
  923. for (var i = 0; i < length; i++) {
  924. var count = rsBlock[i * 3 + 0];
  925. var totalCount = rsBlock[i * 3 + 1];
  926. var dataCount = rsBlock[i * 3 + 2];
  927. for (var j = 0; j < count; j++) {
  928. list.push(new QRRSBlock(totalCount, dataCount));
  929. }
  930. }
  931. return list;
  932. };
  933. QRRSBlock.getRsBlockTable = function (typeNumber, errorCorrectLevel) {
  934. switch (errorCorrectLevel) {
  935. case QRErrorCorrectLevel.L:
  936. return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];
  937. case QRErrorCorrectLevel.M:
  938. return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];
  939. case QRErrorCorrectLevel.Q:
  940. return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];
  941. case QRErrorCorrectLevel.H:
  942. return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];
  943. default:
  944. return undefined;
  945. }
  946. };
  947. function QRBitBuffer() {
  948. this.buffer = [];
  949. this.length = 0;
  950. }
  951. QRBitBuffer.prototype = {
  952. get: function (index) {
  953. var bufIndex = Math.floor(index / 8);
  954. return ((this.buffer[bufIndex] >>> (7 - (index % 8))) & 1) == 1;
  955. },
  956. put: function (num, length) {
  957. for (var i = 0; i < length; i++) {
  958. this.putBit(((num >>> (length - i - 1)) & 1) == 1);
  959. }
  960. },
  961. getLengthInBits: function () {
  962. return this.length;
  963. },
  964. putBit: function (bit) {
  965. var bufIndex = Math.floor(this.length / 8);
  966. if (this.buffer.length <= bufIndex) {
  967. this.buffer.push(0);
  968. }
  969. if (bit) {
  970. this.buffer[bufIndex] |= 0x80 >>> this.length % 8;
  971. }
  972. this.length++;
  973. },
  974. };
  975. var QRCodeLimitLength = [
  976. [17, 14, 11, 7],
  977. [32, 26, 20, 14],
  978. [53, 42, 32, 24],
  979. [78, 62, 46, 34],
  980. [106, 84, 60, 44],
  981. [134, 106, 74, 58],
  982. [154, 122, 86, 64],
  983. [192, 152, 108, 84],
  984. [230, 180, 130, 98],
  985. [271, 213, 151, 119],
  986. [321, 251, 177, 137],
  987. [367, 287, 203, 155],
  988. [425, 331, 241, 177],
  989. [458, 362, 258, 194],
  990. [520, 412, 292, 220],
  991. [586, 450, 322, 250],
  992. [644, 504, 364, 280],
  993. [718, 560, 394, 310],
  994. [792, 624, 442, 338],
  995. [858, 666, 482, 382],
  996. [929, 711, 509, 403],
  997. [1003, 779, 565, 439],
  998. [1091, 857, 611, 461],
  999. [1171, 911, 661, 511],
  1000. [1273, 997, 715, 535],
  1001. [1367, 1059, 751, 593],
  1002. [1465, 1125, 805, 625],
  1003. [1528, 1190, 868, 658],
  1004. [1628, 1264, 908, 698],
  1005. [1732, 1370, 982, 742],
  1006. [1840, 1452, 1030, 790],
  1007. [1952, 1538, 1112, 842],
  1008. [2068, 1628, 1168, 898],
  1009. [2188, 1722, 1228, 958],
  1010. [2303, 1809, 1283, 983],
  1011. [2431, 1911, 1351, 1051],
  1012. [2563, 1989, 1423, 1093],
  1013. [2699, 2099, 1499, 1139],
  1014. [2809, 2213, 1579, 1219],
  1015. [2953, 2331, 1663, 1273],
  1016. ];
  1017.  
  1018. function _isSupportCanvas() {
  1019. return typeof CanvasRenderingContext2D != "undefined";
  1020. }
  1021.  
  1022. // android 2.x doesn't support Data-URI spec
  1023. function _getAndroid() {
  1024. var android = false;
  1025. var sAgent = navigator.userAgent;
  1026.  
  1027. if (/android/i.test(sAgent)) {
  1028. // android
  1029. android = true;
  1030. var aMat = sAgent.toString().match(/android ([0-9]\.[0-9])/i);
  1031.  
  1032. if (aMat && aMat[1]) {
  1033. android = parseFloat(aMat[1]);
  1034. }
  1035. }
  1036.  
  1037. return android;
  1038. }
  1039.  
  1040. var svgDrawer = (function () {
  1041. var Drawing = function (el, htOption) {
  1042. this._el = el;
  1043. this._htOption = htOption;
  1044. };
  1045.  
  1046. Drawing.prototype.draw = function (oQRCode) {
  1047. var _htOption = this._htOption;
  1048. var _el = this._el;
  1049. var nCount = oQRCode.getModuleCount();
  1050. var nWidth = Math.floor(_htOption.width / nCount);
  1051. var nHeight = Math.floor(_htOption.height / nCount);
  1052.  
  1053. this.clear();
  1054.  
  1055. function makeSVG(tag, attrs) {
  1056. var el = document.createElementNS("http://www.w3.org/2000/svg", tag);
  1057. for (var k in attrs)
  1058. if (attrs.hasOwnProperty(k)) el.setAttribute(k, attrs[k]);
  1059. return el;
  1060. }
  1061.  
  1062. var svg = makeSVG("svg", {
  1063. viewBox: "0 0 " + String(nCount) + " " + String(nCount),
  1064. width: "100%",
  1065. height: "100%",
  1066. fill: _htOption.colorLight,
  1067. });
  1068. svg.setAttributeNS(
  1069. "http://www.w3.org/2000/xmlns/",
  1070. "xmlns:xlink",
  1071. "http://www.w3.org/1999/xlink"
  1072. );
  1073. _el.appendChild(svg);
  1074.  
  1075. svg.appendChild(
  1076. makeSVG("rect", {
  1077. fill: _htOption.colorLight,
  1078. width: "100%",
  1079. height: "100%",
  1080. })
  1081. );
  1082. svg.appendChild(
  1083. makeSVG("rect", {
  1084. fill: _htOption.colorDark,
  1085. width: "1",
  1086. height: "1",
  1087. id: "template",
  1088. })
  1089. );
  1090.  
  1091. for (var row = 0; row < nCount; row++) {
  1092. for (var col = 0; col < nCount; col++) {
  1093. if (oQRCode.isDark(row, col)) {
  1094. var child = makeSVG("use", { x: String(col), y: String(row) });
  1095. child.setAttributeNS(
  1096. "http://www.w3.org/1999/xlink",
  1097. "href",
  1098. "#template"
  1099. );
  1100. svg.appendChild(child);
  1101. }
  1102. }
  1103. }
  1104. };
  1105. Drawing.prototype.clear = function () {
  1106. while (this._el.hasChildNodes()) this._el.removeChild(this._el.lastChild);
  1107. };
  1108. return Drawing;
  1109. })();
  1110.  
  1111. var useSVG = document.documentElement.tagName.toLowerCase() === "svg";
  1112.  
  1113. // Drawing in DOM by using Table tag
  1114. var Drawing = useSVG
  1115. ? svgDrawer
  1116. : !_isSupportCanvas()
  1117. ? (function () {
  1118. var Drawing = function (el, htOption) {
  1119. this._el = el;
  1120. this._htOption = htOption;
  1121. };
  1122.  
  1123. /**
  1124. * Draw the QRCode
  1125. *
  1126. * @param {QRCode} oQRCode
  1127. */
  1128. Drawing.prototype.draw = function (oQRCode) {
  1129. var _htOption = this._htOption;
  1130. var _el = this._el;
  1131. var nCount = oQRCode.getModuleCount();
  1132. var nWidth = Math.floor(_htOption.width / nCount);
  1133. var nHeight = Math.floor(_htOption.height / nCount);
  1134. var aHTML = ['<table style="border:0;border-collapse:collapse;">'];
  1135.  
  1136. for (var row = 0; row < nCount; row++) {
  1137. aHTML.push("<tr>");
  1138.  
  1139. for (var col = 0; col < nCount; col++) {
  1140. aHTML.push(
  1141. '<td style="border:0;border-collapse:collapse;padding:0;margin:0;width:' +
  1142. nWidth +
  1143. "px;height:" +
  1144. nHeight +
  1145. "px;background-color:" +
  1146. (oQRCode.isDark(row, col)
  1147. ? _htOption.colorDark
  1148. : _htOption.colorLight) +
  1149. ';"></td>'
  1150. );
  1151. }
  1152.  
  1153. aHTML.push("</tr>");
  1154. }
  1155.  
  1156. aHTML.push("</table>");
  1157. _el.innerHTML = aHTML.join("");
  1158.  
  1159. // Fix the margin values as real size.
  1160. var elTable = _el.childNodes[0];
  1161. var nLeftMarginTable = (_htOption.width - elTable.offsetWidth) / 2;
  1162. var nTopMarginTable = (_htOption.height - elTable.offsetHeight) / 2;
  1163.  
  1164. if (nLeftMarginTable > 0 && nTopMarginTable > 0) {
  1165. elTable.style.margin =
  1166. nTopMarginTable + "px " + nLeftMarginTable + "px";
  1167. }
  1168. };
  1169.  
  1170. /**
  1171. * Clear the QRCode
  1172. */
  1173. Drawing.prototype.clear = function () {
  1174. this._el.innerHTML = "";
  1175. };
  1176.  
  1177. return Drawing;
  1178. })()
  1179. : (function () {
  1180. // Drawing in Canvas
  1181. function _onMakeImage() {
  1182. this._elImage.src = this._elCanvas.toDataURL("image/png");
  1183. this._elImage.style.display = "block";
  1184. this._elCanvas.style.display = "none";
  1185. }
  1186.  
  1187. // Android 2.1 bug workaround
  1188. // http://code.google.com/p/android/issues/detail?id=5141
  1189. if (this && this._android && this._android <= 2.1) {
  1190. var factor = 1 / window.devicePixelRatio;
  1191. var drawImage = CanvasRenderingContext2D.prototype.drawImage;
  1192. CanvasRenderingContext2D.prototype.drawImage = function (
  1193. image,
  1194. sx,
  1195. sy,
  1196. sw,
  1197. sh,
  1198. dx,
  1199. dy,
  1200. dw,
  1201. dh
  1202. ) {
  1203. if ("nodeName" in image && /img/i.test(image.nodeName)) {
  1204. for (var i = arguments.length - 1; i >= 1; i--) {
  1205. arguments[i] = arguments[i] * factor;
  1206. }
  1207. } else if (typeof dw == "undefined") {
  1208. arguments[1] *= factor;
  1209. arguments[2] *= factor;
  1210. arguments[3] *= factor;
  1211. arguments[4] *= factor;
  1212. }
  1213.  
  1214. drawImage.apply(this, arguments);
  1215. };
  1216. }
  1217.  
  1218. /**
  1219. * Check whether the user's browser supports Data URI or not
  1220. *
  1221. * @private
  1222. * @param {Function} fSuccess Occurs if it supports Data URI
  1223. * @param {Function} fFail Occurs if it doesn't support Data URI
  1224. */
  1225. function _safeSetDataURI(fSuccess, fFail) {
  1226. var self = this;
  1227. self._fFail = fFail;
  1228. self._fSuccess = fSuccess;
  1229.  
  1230. // Check it just once
  1231. if (self._bSupportDataURI === null) {
  1232. var el = document.createElement("img");
  1233. var fOnError = function () {
  1234. self._bSupportDataURI = false;
  1235.  
  1236. if (self._fFail) {
  1237. self._fFail.call(self);
  1238. }
  1239. };
  1240. var fOnSuccess = function () {
  1241. self._bSupportDataURI = true;
  1242.  
  1243. if (self._fSuccess) {
  1244. self._fSuccess.call(self);
  1245. }
  1246. };
  1247.  
  1248. el.onabort = fOnError;
  1249. el.onerror = fOnError;
  1250. el.onload = fOnSuccess;
  1251. el.src =
  1252. "data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="; // the Image contains 1px data.
  1253. return;
  1254. } else if (self._bSupportDataURI === true && self._fSuccess) {
  1255. self._fSuccess.call(self);
  1256. } else if (self._bSupportDataURI === false && self._fFail) {
  1257. self._fFail.call(self);
  1258. }
  1259. }
  1260.  
  1261. /**
  1262. * Drawing QRCode by using canvas
  1263. *
  1264. * @constructor
  1265. * @param {HTMLElement} el
  1266. * @param {Object} htOption QRCode Options
  1267. */
  1268. var Drawing = function (el, htOption) {
  1269. this._bIsPainted = false;
  1270. this._android = _getAndroid();
  1271.  
  1272. this._htOption = htOption;
  1273. this._elCanvas = document.createElement("canvas");
  1274. this._elCanvas.width = htOption.width;
  1275. this._elCanvas.height = htOption.height;
  1276. el.appendChild(this._elCanvas);
  1277. this._el = el;
  1278. this._oContext = this._elCanvas.getContext("2d");
  1279. this._bIsPainted = false;
  1280. this._elImage = document.createElement("img");
  1281. this._elImage.alt = "Scan me!";
  1282. this._elImage.style.display = "none";
  1283. this._el.appendChild(this._elImage);
  1284. this._bSupportDataURI = null;
  1285. };
  1286.  
  1287. /**
  1288. * Draw the QRCode
  1289. *
  1290. * @param {QRCode} oQRCode
  1291. */
  1292. Drawing.prototype.draw = function (oQRCode) {
  1293. var _elImage = this._elImage;
  1294. var _oContext = this._oContext;
  1295. var _htOption = this._htOption;
  1296.  
  1297. var nCount = oQRCode.getModuleCount();
  1298. var nWidth = _htOption.width / nCount;
  1299. var nHeight = _htOption.height / nCount;
  1300. var nRoundedWidth = Math.round(nWidth);
  1301. var nRoundedHeight = Math.round(nHeight);
  1302.  
  1303. _elImage.style.display = "none";
  1304. this.clear();
  1305.  
  1306. for (var row = 0; row < nCount; row++) {
  1307. for (var col = 0; col < nCount; col++) {
  1308. var bIsDark = oQRCode.isDark(row, col);
  1309. var nLeft = col * nWidth;
  1310. var nTop = row * nHeight;
  1311. _oContext.strokeStyle = bIsDark
  1312. ? _htOption.colorDark
  1313. : _htOption.colorLight;
  1314. _oContext.lineWidth = 1;
  1315. _oContext.fillStyle = bIsDark
  1316. ? _htOption.colorDark
  1317. : _htOption.colorLight;
  1318. _oContext.fillRect(nLeft, nTop, nWidth, nHeight);
  1319.  
  1320. // 안티 앨리어싱 방지 처리
  1321. _oContext.strokeRect(
  1322. Math.floor(nLeft) + 0.5,
  1323. Math.floor(nTop) + 0.5,
  1324. nRoundedWidth,
  1325. nRoundedHeight
  1326. );
  1327.  
  1328. _oContext.strokeRect(
  1329. Math.ceil(nLeft) - 0.5,
  1330. Math.ceil(nTop) - 0.5,
  1331. nRoundedWidth,
  1332. nRoundedHeight
  1333. );
  1334. }
  1335. }
  1336.  
  1337. this._bIsPainted = true;
  1338. };
  1339.  
  1340. /**
  1341. * Make the image from Canvas if the browser supports Data URI.
  1342. */
  1343. Drawing.prototype.makeImage = function () {
  1344. if (this._bIsPainted) {
  1345. _safeSetDataURI.call(this, _onMakeImage);
  1346. }
  1347. };
  1348.  
  1349. /**
  1350. * Return whether the QRCode is painted or not
  1351. *
  1352. * @return {Boolean}
  1353. */
  1354. Drawing.prototype.isPainted = function () {
  1355. return this._bIsPainted;
  1356. };
  1357.  
  1358. /**
  1359. * Clear the QRCode
  1360. */
  1361. Drawing.prototype.clear = function () {
  1362. this._oContext.clearRect(
  1363. 0,
  1364. 0,
  1365. this._elCanvas.width,
  1366. this._elCanvas.height
  1367. );
  1368. this._bIsPainted = false;
  1369. };
  1370.  
  1371. /**
  1372. * @private
  1373. * @param {Number} nNumber
  1374. */
  1375. Drawing.prototype.round = function (nNumber) {
  1376. if (!nNumber) {
  1377. return nNumber;
  1378. }
  1379.  
  1380. return Math.floor(nNumber * 1000) / 1000;
  1381. };
  1382.  
  1383. return Drawing;
  1384. })();
  1385.  
  1386. /**
  1387. * Get the type by string length
  1388. *
  1389. * @private
  1390. * @param {String} sText
  1391. * @param {Number} nCorrectLevel
  1392. * @return {Number} type
  1393. */
  1394. function _getTypeNumber(sText, nCorrectLevel) {
  1395. var nType = 1;
  1396. var length = _getUTF8Length(sText);
  1397.  
  1398. for (var i = 0, len = QRCodeLimitLength.length; i < len; i++) {
  1399. var nLimit = 0;
  1400.  
  1401. switch (nCorrectLevel) {
  1402. case QRErrorCorrectLevel.L:
  1403. nLimit = QRCodeLimitLength[i][0];
  1404. break;
  1405. case QRErrorCorrectLevel.M:
  1406. nLimit = QRCodeLimitLength[i][1];
  1407. break;
  1408. case QRErrorCorrectLevel.Q:
  1409. nLimit = QRCodeLimitLength[i][2];
  1410. break;
  1411. case QRErrorCorrectLevel.H:
  1412. nLimit = QRCodeLimitLength[i][3];
  1413. break;
  1414. }
  1415.  
  1416. if (length <= nLimit) {
  1417. break;
  1418. } else {
  1419. nType++;
  1420. }
  1421. }
  1422.  
  1423. if (nType > QRCodeLimitLength.length) {
  1424. throw new Error("Too long data");
  1425. }
  1426.  
  1427. return nType;
  1428. }
  1429.  
  1430. function _getUTF8Length(sText) {
  1431. var replacedText = encodeURI(sText)
  1432. .toString()
  1433. .replace(/\%[0-9a-fA-F]{2}/g, "a");
  1434. return replacedText.length + (replacedText.length != sText ? 3 : 0);
  1435. }
  1436.  
  1437. /**
  1438. * @class QRCode
  1439. * @constructor
  1440. * @example
  1441. * new QRCode(document.getElementById("test"), "http://jindo.dev.naver.com/collie");
  1442. *
  1443. * @example
  1444. * var oQRCode = new QRCode("test", {
  1445. * text : "http://naver.com",
  1446. * width : 128,
  1447. * height : 128
  1448. * });
  1449. *
  1450. * oQRCode.clear(); // Clear the QRCode.
  1451. * oQRCode.makeCode("http://map.naver.com"); // Re-create the QRCode.
  1452. *
  1453. * @param {HTMLElement|String} el target element or 'id' attribute of element.
  1454. * @param {Object|String} vOption
  1455. * @param {String} vOption.text QRCode link data
  1456. * @param {Number} [vOption.width=256]
  1457. * @param {Number} [vOption.height=256]
  1458. * @param {String} [vOption.colorDark="#000000"]
  1459. * @param {String} [vOption.colorLight="#ffffff"]
  1460. * @param {QRCode.CorrectLevel} [vOption.correctLevel=QRCode.CorrectLevel.H] [L|M|Q|H]
  1461. */
  1462. var QRCode = function (el, vOption) {
  1463. this._htOption = {
  1464. width: 256,
  1465. height: 256,
  1466. typeNumber: 4,
  1467. colorDark: "#000000",
  1468. colorLight: "#ffffff",
  1469. correctLevel: QRErrorCorrectLevel.H,
  1470. };
  1471.  
  1472. if (typeof vOption === "string") {
  1473. vOption = {
  1474. text: vOption,
  1475. };
  1476. }
  1477.  
  1478. // Overwrites options
  1479. if (vOption) {
  1480. for (var i in vOption) {
  1481. this._htOption[i] = vOption[i];
  1482. }
  1483. }
  1484.  
  1485. if (typeof el == "string") {
  1486. el = document.getElementById(el);
  1487. }
  1488.  
  1489. if (this._htOption.useSVG) {
  1490. Drawing = svgDrawer;
  1491. }
  1492.  
  1493. this._android = _getAndroid();
  1494. this._el = el;
  1495. this._oQRCode = null;
  1496. this._oDrawing = new Drawing(this._el, this._htOption);
  1497.  
  1498. if (this._htOption.text) {
  1499. this.makeCode(this._htOption.text);
  1500. }
  1501. };
  1502.  
  1503. /**
  1504. * Make the QRCode
  1505. *
  1506. * @param {String} sText link data
  1507. */
  1508. QRCode.prototype.makeCode = function (sText) {
  1509. this._oQRCode = new QRCodeModel(
  1510. _getTypeNumber(sText, this._htOption.correctLevel),
  1511. this._htOption.correctLevel
  1512. );
  1513. this._oQRCode.addData(sText);
  1514. this._oQRCode.make();
  1515. this._el.title = sText;
  1516. this._oDrawing.draw(this._oQRCode);
  1517. this.makeImage();
  1518. };
  1519.  
  1520. /**
  1521. * Make the Image from Canvas element
  1522. * - It occurs automatically
  1523. * - Android below 3 doesn't support Data-URI spec.
  1524. *
  1525. * @private
  1526. */
  1527. QRCode.prototype.makeImage = function () {
  1528. if (
  1529. typeof this._oDrawing.makeImage == "function" &&
  1530. (!this._android || this._android >= 3)
  1531. ) {
  1532. this._oDrawing.makeImage();
  1533. }
  1534. };
  1535.  
  1536. /**
  1537. * Clear the QRCode
  1538. */
  1539. QRCode.prototype.clear = function () {
  1540. this._oDrawing.clear();
  1541. };
  1542.  
  1543. /**
  1544. * @name QRCode.CorrectLevel
  1545. */
  1546. QRCode.CorrectLevel = QRErrorCorrectLevel;
  1547.  
  1548. return QRCode;
  1549. });