QRCode.js 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131
  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. * @author davidshimjs
  8. * @see <a href="http://www.d-project.com/" target="_blank">http://www.d-project.com/</a>
  9. * @see <a href="http://jeromeetienne.github.com/jquery-qrcode/" target="_blank">http://jeromeetienne.github.com/jquery-qrcode/</a>
  10. */
  11. layui.define(function (exports) {
  12. var QRCode;
  13. function QR8bitByte(data) {
  14. this.mode = QRMode.MODE_8BIT_BYTE;
  15. this.data = data;
  16. this.parsedData = [];
  17. // Added to support UTF-8 Characters
  18. for (var i = 0, l = this.data.length; i < l; i++) {
  19. var byteArray = [];
  20. var code = this.data.charCodeAt(i);
  21. if (code > 0x10000) {
  22. byteArray[0] = 0xF0 | ((code & 0x1C0000) >>> 18);
  23. byteArray[1] = 0x80 | ((code & 0x3F000) >>> 12);
  24. byteArray[2] = 0x80 | ((code & 0xFC0) >>> 6);
  25. byteArray[3] = 0x80 | (code & 0x3F);
  26. } else if (code > 0x800) {
  27. byteArray[0] = 0xE0 | ((code & 0xF000) >>> 12);
  28. byteArray[1] = 0x80 | ((code & 0xFC0) >>> 6);
  29. byteArray[2] = 0x80 | (code & 0x3F);
  30. } else if (code > 0x80) {
  31. byteArray[0] = 0xC0 | ((code & 0x7C0) >>> 6);
  32. byteArray[1] = 0x80 | (code & 0x3F);
  33. } else {
  34. byteArray[0] = code;
  35. }
  36. this.parsedData.push(byteArray);
  37. }
  38. this.parsedData = Array.prototype.concat.apply([], this.parsedData);
  39. if (this.parsedData.length != this.data.length) {
  40. this.parsedData.unshift(191);
  41. this.parsedData.unshift(187);
  42. this.parsedData.unshift(239);
  43. }
  44. }
  45. QR8bitByte.prototype = {
  46. getLength: function (buffer) {
  47. return this.parsedData.length;
  48. },
  49. write: function (buffer) {
  50. for (var i = 0, l = this.parsedData.length; i < l; i++) {
  51. buffer.put(this.parsedData[i], 8);
  52. }
  53. }
  54. };
  55. function QRCodeModel(typeNumber, errorCorrectLevel) {
  56. this.typeNumber = typeNumber;
  57. this.errorCorrectLevel = errorCorrectLevel;
  58. this.modules = null;
  59. this.moduleCount = 0;
  60. this.dataCache = null;
  61. this.dataList = [];
  62. }
  63. QRCodeModel.prototype = {
  64. addData: function (data) {
  65. var newData = new QR8bitByte(data);
  66. this.dataList.push(newData);
  67. this.dataCache = null;
  68. }, isDark: function (row, col) {
  69. if (row < 0 || this.moduleCount <= row || col < 0 || this.moduleCount <= col) {
  70. throw new Error(row + "," + col);
  71. }
  72. return this.modules[row][col];
  73. }, getModuleCount: function () {
  74. return this.moduleCount;
  75. }, make: function () {
  76. this.makeImpl(false, this.getBestMaskPattern());
  77. }, makeImpl: function (test, maskPattern) {
  78. this.moduleCount = this.typeNumber * 4 + 17;
  79. this.modules = new Array(this.moduleCount);
  80. for (var row = 0; row < this.moduleCount; row++) {
  81. this.modules[row] = new Array(this.moduleCount);
  82. for (var col = 0; col < this.moduleCount; col++) {
  83. this.modules[row][col] = null;
  84. }
  85. }
  86. this.setupPositionProbePattern(0, 0);
  87. this.setupPositionProbePattern(this.moduleCount - 7, 0);
  88. this.setupPositionProbePattern(0, this.moduleCount - 7);
  89. this.setupPositionAdjustPattern();
  90. this.setupTimingPattern();
  91. this.setupTypeInfo(test, maskPattern);
  92. if (this.typeNumber >= 7) {
  93. this.setupTypeNumber(test);
  94. }
  95. if (this.dataCache == null) {
  96. this.dataCache = QRCodeModel.createData(this.typeNumber, this.errorCorrectLevel, this.dataList);
  97. }
  98. this.mapData(this.dataCache, maskPattern);
  99. }, setupPositionProbePattern: function (row, col) {
  100. for (var r = -1; r <= 7; r++) {
  101. if (row + r <= -1 || this.moduleCount <= row + r) continue;
  102. for (var c = -1; c <= 7; c++) {
  103. if (col + c <= -1 || this.moduleCount <= col + c) continue;
  104. 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)) {
  105. this.modules[row + r][col + c] = true;
  106. } else {
  107. this.modules[row + r][col + c] = false;
  108. }
  109. }
  110. }
  111. }, getBestMaskPattern: function () {
  112. var minLostPoint = 0;
  113. var pattern = 0;
  114. for (var i = 0; i < 8; i++) {
  115. this.makeImpl(true, i);
  116. var lostPoint = QRUtil.getLostPoint(this);
  117. if (i == 0 || minLostPoint > lostPoint) {
  118. minLostPoint = lostPoint;
  119. pattern = i;
  120. }
  121. }
  122. return pattern;
  123. }, createMovieClip: function (target_mc, instance_name, depth) {
  124. var qr_mc = target_mc.createEmptyMovieClip(instance_name, depth);
  125. var cs = 1;
  126. this.make();
  127. for (var row = 0; row < this.modules.length; row++) {
  128. var y = row * cs;
  129. for (var col = 0; col < this.modules[row].length; col++) {
  130. var x = col * cs;
  131. var dark = this.modules[row][col];
  132. if (dark) {
  133. qr_mc.beginFill(0, 100);
  134. qr_mc.moveTo(x, y);
  135. qr_mc.lineTo(x + cs, y);
  136. qr_mc.lineTo(x + cs, y + cs);
  137. qr_mc.lineTo(x, y + cs);
  138. qr_mc.endFill();
  139. }
  140. }
  141. }
  142. return qr_mc;
  143. }, setupTimingPattern: function () {
  144. for (var r = 8; r < this.moduleCount - 8; r++) {
  145. if (this.modules[r][6] != null) {
  146. continue;
  147. }
  148. this.modules[r][6] = (r % 2 == 0);
  149. }
  150. for (var c = 8; c < this.moduleCount - 8; c++) {
  151. if (this.modules[6][c] != null) {
  152. continue;
  153. }
  154. this.modules[6][c] = (c % 2 == 0);
  155. }
  156. }, setupPositionAdjustPattern: function () {
  157. var pos = QRUtil.getPatternPosition(this.typeNumber);
  158. for (var i = 0; i < pos.length; i++) {
  159. for (var j = 0; j < pos.length; j++) {
  160. var row = pos[i];
  161. var col = pos[j];
  162. if (this.modules[row][col] != null) {
  163. continue;
  164. }
  165. for (var r = -2; r <= 2; r++) {
  166. for (var c = -2; c <= 2; c++) {
  167. if (r == -2 || r == 2 || c == -2 || c == 2 || (r == 0 && c == 0)) {
  168. this.modules[row + r][col + c] = true;
  169. } else {
  170. this.modules[row + r][col + c] = false;
  171. }
  172. }
  173. }
  174. }
  175. }
  176. }, setupTypeNumber: function (test) {
  177. var bits = QRUtil.getBCHTypeNumber(this.typeNumber);
  178. for (var i = 0; i < 18; i++) {
  179. var mod = (!test && ((bits >> i) & 1) == 1);
  180. this.modules[Math.floor(i / 3)][i % 3 + this.moduleCount - 8 - 3] = mod;
  181. }
  182. for (var i = 0; i < 18; i++) {
  183. var mod = (!test && ((bits >> i) & 1) == 1);
  184. this.modules[i % 3 + this.moduleCount - 8 - 3][Math.floor(i / 3)] = mod;
  185. }
  186. }, setupTypeInfo: function (test, maskPattern) {
  187. var data = (this.errorCorrectLevel << 3) | maskPattern;
  188. var bits = QRUtil.getBCHTypeInfo(data);
  189. for (var i = 0; i < 15; i++) {
  190. var mod = (!test && ((bits >> i) & 1) == 1);
  191. if (i < 6) {
  192. this.modules[i][8] = mod;
  193. } else if (i < 8) {
  194. this.modules[i + 1][8] = mod;
  195. } else {
  196. this.modules[this.moduleCount - 15 + i][8] = mod;
  197. }
  198. }
  199. for (var i = 0; i < 15; i++) {
  200. var mod = (!test && ((bits >> i) & 1) == 1);
  201. if (i < 8) {
  202. this.modules[8][this.moduleCount - i - 1] = mod;
  203. } else if (i < 9) {
  204. this.modules[8][15 - i - 1 + 1] = mod;
  205. } else {
  206. this.modules[8][15 - i - 1] = mod;
  207. }
  208. }
  209. this.modules[this.moduleCount - 8][8] = (!test);
  210. }, mapData: function (data, maskPattern) {
  211. var inc = -1;
  212. var row = this.moduleCount - 1;
  213. var bitIndex = 7;
  214. var byteIndex = 0;
  215. for (var col = this.moduleCount - 1; col > 0; col -= 2) {
  216. if (col == 6) col--;
  217. while (true) {
  218. for (var c = 0; c < 2; c++) {
  219. if (this.modules[row][col - c] == null) {
  220. var dark = false;
  221. if (byteIndex < data.length) {
  222. dark = (((data[byteIndex] >>> bitIndex) & 1) == 1);
  223. }
  224. var mask = QRUtil.getMask(maskPattern, row, col - c);
  225. if (mask) {
  226. dark = !dark;
  227. }
  228. this.modules[row][col - c] = dark;
  229. bitIndex--;
  230. if (bitIndex == -1) {
  231. byteIndex++;
  232. bitIndex = 7;
  233. }
  234. }
  235. }
  236. row += inc;
  237. if (row < 0 || this.moduleCount <= row) {
  238. row -= inc;
  239. inc = -inc;
  240. break;
  241. }
  242. }
  243. }
  244. }
  245. };
  246. QRCodeModel.PAD0 = 0xEC;
  247. QRCodeModel.PAD1 = 0x11;
  248. QRCodeModel.createData = function (typeNumber, errorCorrectLevel, dataList) {
  249. var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel);
  250. var buffer = new QRBitBuffer();
  251. for (var i = 0; i < dataList.length; i++) {
  252. var data = dataList[i];
  253. buffer.put(data.mode, 4);
  254. buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber));
  255. data.write(buffer);
  256. }
  257. var totalDataCount = 0;
  258. for (var i = 0; i < rsBlocks.length; i++) {
  259. totalDataCount += rsBlocks[i].dataCount;
  260. }
  261. if (buffer.getLengthInBits() > totalDataCount * 8) {
  262. throw new Error("code length overflow. ("
  263. + buffer.getLengthInBits()
  264. + ">"
  265. + totalDataCount * 8
  266. + ")");
  267. }
  268. if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {
  269. buffer.put(0, 4);
  270. }
  271. while (buffer.getLengthInBits() % 8 != 0) {
  272. buffer.putBit(false);
  273. }
  274. while (true) {
  275. if (buffer.getLengthInBits() >= totalDataCount * 8) {
  276. break;
  277. }
  278. buffer.put(QRCodeModel.PAD0, 8);
  279. if (buffer.getLengthInBits() >= totalDataCount * 8) {
  280. break;
  281. }
  282. buffer.put(QRCodeModel.PAD1, 8);
  283. }
  284. return QRCodeModel.createBytes(buffer, rsBlocks);
  285. };
  286. QRCodeModel.createBytes = function (buffer, rsBlocks) {
  287. var offset = 0;
  288. var maxDcCount = 0;
  289. var maxEcCount = 0;
  290. var dcdata = new Array(rsBlocks.length);
  291. var ecdata = new Array(rsBlocks.length);
  292. for (var r = 0; r < rsBlocks.length; r++) {
  293. var dcCount = rsBlocks[r].dataCount;
  294. var ecCount = rsBlocks[r].totalCount - dcCount;
  295. maxDcCount = Math.max(maxDcCount, dcCount);
  296. maxEcCount = Math.max(maxEcCount, ecCount);
  297. dcdata[r] = new Array(dcCount);
  298. for (var i = 0; i < dcdata[r].length; i++) {
  299. dcdata[r][i] = 0xff & buffer.buffer[i + offset];
  300. }
  301. offset += dcCount;
  302. var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
  303. var rawPoly = new QRPolynomial(dcdata[r], rsPoly.getLength() - 1);
  304. var modPoly = rawPoly.mod(rsPoly);
  305. ecdata[r] = new Array(rsPoly.getLength() - 1);
  306. for (var i = 0; i < ecdata[r].length; i++) {
  307. var modIndex = i + modPoly.getLength() - ecdata[r].length;
  308. ecdata[r][i] = (modIndex >= 0) ? modPoly.get(modIndex) : 0;
  309. }
  310. }
  311. var totalCodeCount = 0;
  312. for (var i = 0; i < rsBlocks.length; i++) {
  313. totalCodeCount += rsBlocks[i].totalCount;
  314. }
  315. var data = new Array(totalCodeCount);
  316. var index = 0;
  317. for (var i = 0; i < maxDcCount; i++) {
  318. for (var r = 0; r < rsBlocks.length; r++) {
  319. if (i < dcdata[r].length) {
  320. data[index++] = dcdata[r][i];
  321. }
  322. }
  323. }
  324. for (var i = 0; i < maxEcCount; i++) {
  325. for (var r = 0; r < rsBlocks.length; r++) {
  326. if (i < ecdata[r].length) {
  327. data[index++] = ecdata[r][i];
  328. }
  329. }
  330. }
  331. return data;
  332. };
  333. var QRMode = {MODE_NUMBER: 1 << 0, MODE_ALPHA_NUM: 1 << 1, MODE_8BIT_BYTE: 1 << 2, MODE_KANJI: 1 << 3};
  334. var QRErrorCorrectLevel = {L: 1, M: 0, Q: 3, H: 2};
  335. var QRMaskPattern = {
  336. PATTERN000: 0,
  337. PATTERN001: 1,
  338. PATTERN010: 2,
  339. PATTERN011: 3,
  340. PATTERN100: 4,
  341. PATTERN101: 5,
  342. PATTERN110: 6,
  343. PATTERN111: 7
  344. };
  345. var QRUtil = {
  346. 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]],
  347. G15: (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0),
  348. G18: (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0),
  349. G15_MASK: (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1),
  350. getBCHTypeInfo: function (data) {
  351. var d = data << 10;
  352. while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0) {
  353. d ^= (QRUtil.G15 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15)));
  354. }
  355. return ((data << 10) | d) ^ QRUtil.G15_MASK;
  356. },
  357. getBCHTypeNumber: function (data) {
  358. var d = data << 12;
  359. while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0) {
  360. d ^= (QRUtil.G18 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18)));
  361. }
  362. return (data << 12) | d;
  363. },
  364. getBCHDigit: function (data) {
  365. var digit = 0;
  366. while (data != 0) {
  367. digit++;
  368. data >>>= 1;
  369. }
  370. return digit;
  371. },
  372. getPatternPosition: function (typeNumber) {
  373. return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1];
  374. },
  375. getMask: function (maskPattern, i, j) {
  376. switch (maskPattern) {
  377. case QRMaskPattern.PATTERN000:
  378. return (i + j) % 2 == 0;
  379. case QRMaskPattern.PATTERN001:
  380. return i % 2 == 0;
  381. case QRMaskPattern.PATTERN010:
  382. return j % 3 == 0;
  383. case QRMaskPattern.PATTERN011:
  384. return (i + j) % 3 == 0;
  385. case QRMaskPattern.PATTERN100:
  386. return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 == 0;
  387. case QRMaskPattern.PATTERN101:
  388. return (i * j) % 2 + (i * j) % 3 == 0;
  389. case QRMaskPattern.PATTERN110:
  390. return ((i * j) % 2 + (i * j) % 3) % 2 == 0;
  391. case QRMaskPattern.PATTERN111:
  392. return ((i * j) % 3 + (i + j) % 2) % 2 == 0;
  393. default:
  394. throw new Error("bad maskPattern:" + maskPattern);
  395. }
  396. },
  397. getErrorCorrectPolynomial: function (errorCorrectLength) {
  398. var a = new QRPolynomial([1], 0);
  399. for (var i = 0; i < errorCorrectLength; i++) {
  400. a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0));
  401. }
  402. return a;
  403. },
  404. getLengthInBits: function (mode, type) {
  405. if (1 <= type && type < 10) {
  406. switch (mode) {
  407. case QRMode.MODE_NUMBER:
  408. return 10;
  409. case QRMode.MODE_ALPHA_NUM:
  410. return 9;
  411. case QRMode.MODE_8BIT_BYTE:
  412. return 8;
  413. case QRMode.MODE_KANJI:
  414. return 8;
  415. default:
  416. throw new Error("mode:" + mode);
  417. }
  418. } else if (type < 27) {
  419. switch (mode) {
  420. case QRMode.MODE_NUMBER:
  421. return 12;
  422. case QRMode.MODE_ALPHA_NUM:
  423. return 11;
  424. case QRMode.MODE_8BIT_BYTE:
  425. return 16;
  426. case QRMode.MODE_KANJI:
  427. return 10;
  428. default:
  429. throw new Error("mode:" + mode);
  430. }
  431. } else if (type < 41) {
  432. switch (mode) {
  433. case QRMode.MODE_NUMBER:
  434. return 14;
  435. case QRMode.MODE_ALPHA_NUM:
  436. return 13;
  437. case QRMode.MODE_8BIT_BYTE:
  438. return 16;
  439. case QRMode.MODE_KANJI:
  440. return 12;
  441. default:
  442. throw new Error("mode:" + mode);
  443. }
  444. } else {
  445. throw new Error("type:" + type);
  446. }
  447. },
  448. getLostPoint: function (qrCode) {
  449. var moduleCount = qrCode.getModuleCount();
  450. var lostPoint = 0;
  451. for (var row = 0; row < moduleCount; row++) {
  452. for (var col = 0; col < moduleCount; col++) {
  453. var sameCount = 0;
  454. var dark = qrCode.isDark(row, col);
  455. for (var r = -1; r <= 1; r++) {
  456. if (row + r < 0 || moduleCount <= row + r) {
  457. continue;
  458. }
  459. for (var c = -1; c <= 1; c++) {
  460. if (col + c < 0 || moduleCount <= col + c) {
  461. continue;
  462. }
  463. if (r == 0 && c == 0) {
  464. continue;
  465. }
  466. if (dark == qrCode.isDark(row + r, col + c)) {
  467. sameCount++;
  468. }
  469. }
  470. }
  471. if (sameCount > 5) {
  472. lostPoint += (3 + sameCount - 5);
  473. }
  474. }
  475. }
  476. for (var row = 0; row < moduleCount - 1; row++) {
  477. for (var col = 0; col < moduleCount - 1; col++) {
  478. var count = 0;
  479. if (qrCode.isDark(row, col)) count++;
  480. if (qrCode.isDark(row + 1, col)) count++;
  481. if (qrCode.isDark(row, col + 1)) count++;
  482. if (qrCode.isDark(row + 1, col + 1)) count++;
  483. if (count == 0 || count == 4) {
  484. lostPoint += 3;
  485. }
  486. }
  487. }
  488. for (var row = 0; row < moduleCount; row++) {
  489. for (var col = 0; col < moduleCount - 6; col++) {
  490. 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)) {
  491. lostPoint += 40;
  492. }
  493. }
  494. }
  495. for (var col = 0; col < moduleCount; col++) {
  496. for (var row = 0; row < moduleCount - 6; row++) {
  497. 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)) {
  498. lostPoint += 40;
  499. }
  500. }
  501. }
  502. var darkCount = 0;
  503. for (var col = 0; col < moduleCount; col++) {
  504. for (var row = 0; row < moduleCount; row++) {
  505. if (qrCode.isDark(row, col)) {
  506. darkCount++;
  507. }
  508. }
  509. }
  510. var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5;
  511. lostPoint += ratio * 10;
  512. return lostPoint;
  513. }
  514. };
  515. var QRMath = {
  516. glog: function (n) {
  517. if (n < 1) {
  518. throw new Error("glog(" + n + ")");
  519. }
  520. return QRMath.LOG_TABLE[n];
  521. }, gexp: function (n) {
  522. while (n < 0) {
  523. n += 255;
  524. }
  525. while (n >= 256) {
  526. n -= 255;
  527. }
  528. return QRMath.EXP_TABLE[n];
  529. }, EXP_TABLE: new Array(256), LOG_TABLE: new Array(256)
  530. };
  531. for (var i = 0; i < 8; i++) {
  532. QRMath.EXP_TABLE[i] = 1 << i;
  533. }
  534. for (var i = 8; i < 256; i++) {
  535. QRMath.EXP_TABLE[i] = QRMath.EXP_TABLE[i - 4] ^ QRMath.EXP_TABLE[i - 5] ^ QRMath.EXP_TABLE[i - 6] ^ QRMath.EXP_TABLE[i - 8];
  536. }
  537. for (var i = 0; i < 255; i++) {
  538. QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]] = i;
  539. }
  540. function QRPolynomial(num, shift) {
  541. if (num.length == undefined) {
  542. throw new Error(num.length + "/" + shift);
  543. }
  544. var offset = 0;
  545. while (offset < num.length && num[offset] == 0) {
  546. offset++;
  547. }
  548. this.num = new Array(num.length - offset + shift);
  549. for (var i = 0; i < num.length - offset; i++) {
  550. this.num[i] = num[i + offset];
  551. }
  552. }
  553. QRPolynomial.prototype = {
  554. get: function (index) {
  555. return this.num[index];
  556. }, getLength: function () {
  557. return this.num.length;
  558. }, multiply: function (e) {
  559. var num = new Array(this.getLength() + e.getLength() - 1);
  560. for (var i = 0; i < this.getLength(); i++) {
  561. for (var j = 0; j < e.getLength(); j++) {
  562. num[i + j] ^= QRMath.gexp(QRMath.glog(this.get(i)) + QRMath.glog(e.get(j)));
  563. }
  564. }
  565. return new QRPolynomial(num, 0);
  566. }, mod: function (e) {
  567. if (this.getLength() - e.getLength() < 0) {
  568. return this;
  569. }
  570. var ratio = QRMath.glog(this.get(0)) - QRMath.glog(e.get(0));
  571. var num = new Array(this.getLength());
  572. for (var i = 0; i < this.getLength(); i++) {
  573. num[i] = this.get(i);
  574. }
  575. for (var i = 0; i < e.getLength(); i++) {
  576. num[i] ^= QRMath.gexp(QRMath.glog(e.get(i)) + ratio);
  577. }
  578. return new QRPolynomial(num, 0).mod(e);
  579. }
  580. };
  581. function QRRSBlock(totalCount, dataCount) {
  582. this.totalCount = totalCount;
  583. this.dataCount = dataCount;
  584. }
  585. QRRSBlock.RS_BLOCK_TABLE = [[1, 26, 19], [1, 26, 16], [1, 26, 13], [1, 26, 9], [1, 44, 34], [1, 44, 28], [1, 44, 22], [1, 44, 16], [1, 70, 55], [1, 70, 44], [2, 35, 17], [2, 35, 13], [1, 100, 80], [2, 50, 32], [2, 50, 24], [4, 25, 9], [1, 134, 108], [2, 67, 43], [2, 33, 15, 2, 34, 16], [2, 33, 11, 2, 34, 12], [2, 86, 68], [4, 43, 27], [4, 43, 19], [4, 43, 15], [2, 98, 78], [4, 49, 31], [2, 32, 14, 4, 33, 15], [4, 39, 13, 1, 40, 14], [2, 121, 97], [2, 60, 38, 2, 61, 39], [4, 40, 18, 2, 41, 19], [4, 40, 14, 2, 41, 15], [2, 146, 116], [3, 58, 36, 2, 59, 37], [4, 36, 16, 4, 37, 17], [4, 36, 12, 4, 37, 13], [2, 86, 68, 2, 87, 69], [4, 69, 43, 1, 70, 44], [6, 43, 19, 2, 44, 20], [6, 43, 15, 2, 44, 16], [4, 101, 81], [1, 80, 50, 4, 81, 51], [4, 50, 22, 4, 51, 23], [3, 36, 12, 8, 37, 13], [2, 116, 92, 2, 117, 93], [6, 58, 36, 2, 59, 37], [4, 46, 20, 6, 47, 21], [7, 42, 14, 4, 43, 15], [4, 133, 107], [8, 59, 37, 1, 60, 38], [8, 44, 20, 4, 45, 21], [12, 33, 11, 4, 34, 12], [3, 145, 115, 1, 146, 116], [4, 64, 40, 5, 65, 41], [11, 36, 16, 5, 37, 17], [11, 36, 12, 5, 37, 13], [5, 109, 87, 1, 110, 88], [5, 65, 41, 5, 66, 42], [5, 54, 24, 7, 55, 25], [11, 36, 12], [5, 122, 98, 1, 123, 99], [7, 73, 45, 3, 74, 46], [15, 43, 19, 2, 44, 20], [3, 45, 15, 13, 46, 16], [1, 135, 107, 5, 136, 108], [10, 74, 46, 1, 75, 47], [1, 50, 22, 15, 51, 23], [2, 42, 14, 17, 43, 15], [5, 150, 120, 1, 151, 121], [9, 69, 43, 4, 70, 44], [17, 50, 22, 1, 51, 23], [2, 42, 14, 19, 43, 15], [3, 141, 113, 4, 142, 114], [3, 70, 44, 11, 71, 45], [17, 47, 21, 4, 48, 22], [9, 39, 13, 16, 40, 14], [3, 135, 107, 5, 136, 108], [3, 67, 41, 13, 68, 42], [15, 54, 24, 5, 55, 25], [15, 43, 15, 10, 44, 16], [4, 144, 116, 4, 145, 117], [17, 68, 42], [17, 50, 22, 6, 51, 23], [19, 46, 16, 6, 47, 17], [2, 139, 111, 7, 140, 112], [17, 74, 46], [7, 54, 24, 16, 55, 25], [34, 37, 13], [4, 151, 121, 5, 152, 122], [4, 75, 47, 14, 76, 48], [11, 54, 24, 14, 55, 25], [16, 45, 15, 14, 46, 16], [6, 147, 117, 4, 148, 118], [6, 73, 45, 14, 74, 46], [11, 54, 24, 16, 55, 25], [30, 46, 16, 2, 47, 17], [8, 132, 106, 4, 133, 107], [8, 75, 47, 13, 76, 48], [7, 54, 24, 22, 55, 25], [22, 45, 15, 13, 46, 16], [10, 142, 114, 2, 143, 115], [19, 74, 46, 4, 75, 47], [28, 50, 22, 6, 51, 23], [33, 46, 16, 4, 47, 17], [8, 152, 122, 4, 153, 123], [22, 73, 45, 3, 74, 46], [8, 53, 23, 26, 54, 24], [12, 45, 15, 28, 46, 16], [3, 147, 117, 10, 148, 118], [3, 73, 45, 23, 74, 46], [4, 54, 24, 31, 55, 25], [11, 45, 15, 31, 46, 16], [7, 146, 116, 7, 147, 117], [21, 73, 45, 7, 74, 46], [1, 53, 23, 37, 54, 24], [19, 45, 15, 26, 46, 16], [5, 145, 115, 10, 146, 116], [19, 75, 47, 10, 76, 48], [15, 54, 24, 25, 55, 25], [23, 45, 15, 25, 46, 16], [13, 145, 115, 3, 146, 116], [2, 74, 46, 29, 75, 47], [42, 54, 24, 1, 55, 25], [23, 45, 15, 28, 46, 16], [17, 145, 115], [10, 74, 46, 23, 75, 47], [10, 54, 24, 35, 55, 25], [19, 45, 15, 35, 46, 16], [17, 145, 115, 1, 146, 116], [14, 74, 46, 21, 75, 47], [29, 54, 24, 19, 55, 25], [11, 45, 15, 46, 46, 16], [13, 145, 115, 6, 146, 116], [14, 74, 46, 23, 75, 47], [44, 54, 24, 7, 55, 25], [59, 46, 16, 1, 47, 17], [12, 151, 121, 7, 152, 122], [12, 75, 47, 26, 76, 48], [39, 54, 24, 14, 55, 25], [22, 45, 15, 41, 46, 16], [6, 151, 121, 14, 152, 122], [6, 75, 47, 34, 76, 48], [46, 54, 24, 10, 55, 25], [2, 45, 15, 64, 46, 16], [17, 152, 122, 4, 153, 123], [29, 74, 46, 14, 75, 47], [49, 54, 24, 10, 55, 25], [24, 45, 15, 46, 46, 16], [4, 152, 122, 18, 153, 123], [13, 74, 46, 32, 75, 47], [48, 54, 24, 14, 55, 25], [42, 45, 15, 32, 46, 16], [20, 147, 117, 4, 148, 118], [40, 75, 47, 7, 76, 48], [43, 54, 24, 22, 55, 25], [10, 45, 15, 67, 46, 16], [19, 148, 118, 6, 149, 119], [18, 75, 47, 31, 76, 48], [34, 54, 24, 34, 55, 25], [20, 45, 15, 61, 46, 16]];
  586. QRRSBlock.getRSBlocks = function (typeNumber, errorCorrectLevel) {
  587. var rsBlock = QRRSBlock.getRsBlockTable(typeNumber, errorCorrectLevel);
  588. if (rsBlock == undefined) {
  589. throw new Error("bad rs block @ typeNumber:" + typeNumber + "/errorCorrectLevel:" + errorCorrectLevel);
  590. }
  591. var length = rsBlock.length / 3;
  592. var list = [];
  593. for (var i = 0; i < length; i++) {
  594. var count = rsBlock[i * 3 + 0];
  595. var totalCount = rsBlock[i * 3 + 1];
  596. var dataCount = rsBlock[i * 3 + 2];
  597. for (var j = 0; j < count; j++) {
  598. list.push(new QRRSBlock(totalCount, dataCount));
  599. }
  600. }
  601. return list;
  602. };
  603. QRRSBlock.getRsBlockTable = function (typeNumber, errorCorrectLevel) {
  604. switch (errorCorrectLevel) {
  605. case QRErrorCorrectLevel.L:
  606. return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];
  607. case QRErrorCorrectLevel.M:
  608. return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];
  609. case QRErrorCorrectLevel.Q:
  610. return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];
  611. case QRErrorCorrectLevel.H:
  612. return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];
  613. default:
  614. return undefined;
  615. }
  616. };
  617. function QRBitBuffer() {
  618. this.buffer = [];
  619. this.length = 0;
  620. }
  621. QRBitBuffer.prototype = {
  622. get: function (index) {
  623. var bufIndex = Math.floor(index / 8);
  624. return ((this.buffer[bufIndex] >>> (7 - index % 8)) & 1) == 1;
  625. }, put: function (num, length) {
  626. for (var i = 0; i < length; i++) {
  627. this.putBit(((num >>> (length - i - 1)) & 1) == 1);
  628. }
  629. }, getLengthInBits: function () {
  630. return this.length;
  631. }, putBit: function (bit) {
  632. var bufIndex = Math.floor(this.length / 8);
  633. if (this.buffer.length <= bufIndex) {
  634. this.buffer.push(0);
  635. }
  636. if (bit) {
  637. this.buffer[bufIndex] |= (0x80 >>> (this.length % 8));
  638. }
  639. this.length++;
  640. }
  641. };
  642. var QRCodeLimitLength = [[17, 14, 11, 7], [32, 26, 20, 14], [53, 42, 32, 24], [78, 62, 46, 34], [106, 84, 60, 44], [134, 106, 74, 58], [154, 122, 86, 64], [192, 152, 108, 84], [230, 180, 130, 98], [271, 213, 151, 119], [321, 251, 177, 137], [367, 287, 203, 155], [425, 331, 241, 177], [458, 362, 258, 194], [520, 412, 292, 220], [586, 450, 322, 250], [644, 504, 364, 280], [718, 560, 394, 310], [792, 624, 442, 338], [858, 666, 482, 382], [929, 711, 509, 403], [1003, 779, 565, 439], [1091, 857, 611, 461], [1171, 911, 661, 511], [1273, 997, 715, 535], [1367, 1059, 751, 593], [1465, 1125, 805, 625], [1528, 1190, 868, 658], [1628, 1264, 908, 698], [1732, 1370, 982, 742], [1840, 1452, 1030, 790], [1952, 1538, 1112, 842], [2068, 1628, 1168, 898], [2188, 1722, 1228, 958], [2303, 1809, 1283, 983], [2431, 1911, 1351, 1051], [2563, 1989, 1423, 1093], [2699, 2099, 1499, 1139], [2809, 2213, 1579, 1219], [2953, 2331, 1663, 1273]];
  643. function _isSupportCanvas() {
  644. return typeof CanvasRenderingContext2D != "undefined";
  645. }
  646. // android 2.x doesn't support Data-URI spec
  647. function _getAndroid() {
  648. var android = false;
  649. var sAgent = navigator.userAgent;
  650. if (/android/i.test(sAgent)) { // android
  651. android = true;
  652. var aMat = sAgent.toString().match(/android ([0-9]\.[0-9])/i);
  653. if (aMat && aMat[1]) {
  654. android = parseFloat(aMat[1]);
  655. }
  656. }
  657. return android;
  658. }
  659. var svgDrawer = (function () {
  660. var Drawing = function (el, htOption) {
  661. this._el = el;
  662. this._htOption = htOption;
  663. };
  664. Drawing.prototype.draw = function (oQRCode) {
  665. var _htOption = this._htOption;
  666. var _el = this._el;
  667. var nCount = oQRCode.getModuleCount();
  668. var nWidth = Math.floor(_htOption.width / nCount);
  669. var nHeight = Math.floor(_htOption.height / nCount);
  670. this.clear();
  671. function makeSVG(tag, attrs) {
  672. var el = document.createElementNS('http://www.w3.org/2000/svg', tag);
  673. for (var k in attrs)
  674. if (attrs.hasOwnProperty(k)) el.setAttribute(k, attrs[k]);
  675. return el;
  676. }
  677. var svg = makeSVG("svg", {
  678. 'viewBox': '0 0 ' + String(nCount) + " " + String(nCount),
  679. 'width': '100%',
  680. 'height': '100%',
  681. 'fill': _htOption.colorLight
  682. });
  683. svg.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xlink", "http://www.w3.org/1999/xlink");
  684. _el.appendChild(svg);
  685. svg.appendChild(makeSVG("rect", {"fill": _htOption.colorLight, "width": "100%", "height": "100%"}));
  686. svg.appendChild(makeSVG("rect", {
  687. "fill": _htOption.colorDark,
  688. "width": "1",
  689. "height": "1",
  690. "id": "template"
  691. }));
  692. for (var row = 0; row < nCount; row++) {
  693. for (var col = 0; col < nCount; col++) {
  694. if (oQRCode.isDark(row, col)) {
  695. var child = makeSVG("use", {"x": String(col), "y": String(row)});
  696. child.setAttributeNS("http://www.w3.org/1999/xlink", "href", "#template")
  697. svg.appendChild(child);
  698. }
  699. }
  700. }
  701. };
  702. Drawing.prototype.clear = function () {
  703. while (this._el.hasChildNodes())
  704. this._el.removeChild(this._el.lastChild);
  705. };
  706. return Drawing;
  707. })();
  708. var useSVG = document.documentElement.tagName.toLowerCase() === "svg";
  709. // Drawing in DOM by using Table tag
  710. var Drawing = useSVG ? svgDrawer : !_isSupportCanvas() ? (function () {
  711. var Drawing = function (el, htOption) {
  712. this._el = el;
  713. this._htOption = htOption;
  714. };
  715. /**
  716. * Draw the QRCode
  717. *
  718. * @param {QRCode} oQRCode
  719. */
  720. Drawing.prototype.draw = function (oQRCode) {
  721. var _htOption = this._htOption;
  722. var _el = this._el;
  723. var nCount = oQRCode.getModuleCount();
  724. var nWidth = Math.floor(_htOption.width / nCount);
  725. var nHeight = Math.floor(_htOption.height / nCount);
  726. var aHTML = ['<table style="border:0;border-collapse:collapse;">'];
  727. for (var row = 0; row < nCount; row++) {
  728. aHTML.push('<tr>');
  729. for (var col = 0; col < nCount; col++) {
  730. aHTML.push('<td style="border:0;border-collapse:collapse;padding:0;margin:0;width:' + nWidth + 'px;height:' + nHeight + 'px;background-color:' + (oQRCode.isDark(row, col) ? _htOption.colorDark : _htOption.colorLight) + ';"></td>');
  731. }
  732. aHTML.push('</tr>');
  733. }
  734. aHTML.push('</table>');
  735. _el.innerHTML = aHTML.join('');
  736. // Fix the margin values as real size.
  737. var elTable = _el.childNodes[0];
  738. var nLeftMarginTable = (_htOption.width - elTable.offsetWidth) / 2;
  739. var nTopMarginTable = (_htOption.height - elTable.offsetHeight) / 2;
  740. if (nLeftMarginTable > 0 && nTopMarginTable > 0) {
  741. elTable.style.margin = nTopMarginTable + "px " + nLeftMarginTable + "px";
  742. }
  743. };
  744. /**
  745. * Clear the QRCode
  746. */
  747. Drawing.prototype.clear = function () {
  748. this._el.innerHTML = '';
  749. };
  750. return Drawing;
  751. })() : (function () { // Drawing in Canvas
  752. function _onMakeImage() {
  753. this._elImage.src = this._elCanvas.toDataURL("image/png");
  754. this._elImage.style.display = "block";
  755. this._elCanvas.style.display = "none";
  756. }
  757. // Android 2.1 bug workaround
  758. // http://code.google.com/p/android/issues/detail?id=5141
  759. if (this._android && this._android <= 2.1) {
  760. var factor = 1 / window.devicePixelRatio;
  761. var drawImage = CanvasRenderingContext2D.prototype.drawImage;
  762. CanvasRenderingContext2D.prototype.drawImage = function (image, sx, sy, sw, sh, dx, dy, dw, dh) {
  763. if (("nodeName" in image) && /img/i.test(image.nodeName)) {
  764. for (var i = arguments.length - 1; i >= 1; i--) {
  765. arguments[i] = arguments[i] * factor;
  766. }
  767. } else if (typeof dw == "undefined") {
  768. arguments[1] *= factor;
  769. arguments[2] *= factor;
  770. arguments[3] *= factor;
  771. arguments[4] *= factor;
  772. }
  773. drawImage.apply(this, arguments);
  774. };
  775. }
  776. /**
  777. * Check whether the user's browser supports Data URI or not
  778. *
  779. * @private
  780. * @param {Function} fSuccess Occurs if it supports Data URI
  781. * @param {Function} fFail Occurs if it doesn't support Data URI
  782. */
  783. function _safeSetDataURI(fSuccess, fFail) {
  784. var self = this;
  785. self._fFail = fFail;
  786. self._fSuccess = fSuccess;
  787. // Check it just once
  788. if (self._bSupportDataURI === null) {
  789. var el = document.createElement("img");
  790. var fOnError = function () {
  791. self._bSupportDataURI = false;
  792. if (self._fFail) {
  793. self._fFail.call(self);
  794. }
  795. };
  796. var fOnSuccess = function () {
  797. self._bSupportDataURI = true;
  798. if (self._fSuccess) {
  799. self._fSuccess.call(self);
  800. }
  801. };
  802. el.onabort = fOnError;
  803. el.onerror = fOnError;
  804. el.onload = fOnSuccess;
  805. el.src = "data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="; // the Image contains 1px data.
  806. return;
  807. } else if (self._bSupportDataURI === true && self._fSuccess) {
  808. self._fSuccess.call(self);
  809. } else if (self._bSupportDataURI === false && self._fFail) {
  810. self._fFail.call(self);
  811. }
  812. };
  813. /**
  814. * Drawing QRCode by using canvas
  815. *
  816. * @constructor
  817. * @param {HTMLElement} el
  818. * @param {Object} htOption QRCode Options
  819. */
  820. var Drawing = function (el, htOption) {
  821. this._bIsPainted = false;
  822. this._android = _getAndroid();
  823. this._htOption = htOption;
  824. this._elCanvas = document.createElement("canvas");
  825. this._elCanvas.width = htOption.width;
  826. this._elCanvas.height = htOption.height;
  827. el.appendChild(this._elCanvas);
  828. this._el = el;
  829. this._oContext = this._elCanvas.getContext("2d");
  830. this._bIsPainted = false;
  831. this._elImage = document.createElement("img");
  832. this._elImage.alt = "Scan me!";
  833. this._elImage.style.display = "none";
  834. this._el.appendChild(this._elImage);
  835. this._bSupportDataURI = null;
  836. };
  837. /**
  838. * Draw the QRCode
  839. *
  840. * @param {QRCode} oQRCode
  841. */
  842. Drawing.prototype.draw = function (oQRCode) {
  843. var _elImage = this._elImage;
  844. var _oContext = this._oContext;
  845. var _htOption = this._htOption;
  846. var nCount = oQRCode.getModuleCount();
  847. var nWidth = _htOption.width / nCount;
  848. var nHeight = _htOption.height / nCount;
  849. var nRoundedWidth = Math.round(nWidth);
  850. var nRoundedHeight = Math.round(nHeight);
  851. _elImage.style.display = "none";
  852. this.clear();
  853. for (var row = 0; row < nCount; row++) {
  854. for (var col = 0; col < nCount; col++) {
  855. var bIsDark = oQRCode.isDark(row, col);
  856. var nLeft = col * nWidth;
  857. var nTop = row * nHeight;
  858. _oContext.strokeStyle = bIsDark ? _htOption.colorDark : _htOption.colorLight;
  859. _oContext.lineWidth = 1;
  860. _oContext.fillStyle = bIsDark ? _htOption.colorDark : _htOption.colorLight;
  861. _oContext.fillRect(nLeft, nTop, nWidth, nHeight);
  862. // 안티 앨리어싱 방지 처리
  863. _oContext.strokeRect(
  864. Math.floor(nLeft) + 0.5,
  865. Math.floor(nTop) + 0.5,
  866. nRoundedWidth,
  867. nRoundedHeight
  868. );
  869. _oContext.strokeRect(
  870. Math.ceil(nLeft) - 0.5,
  871. Math.ceil(nTop) - 0.5,
  872. nRoundedWidth,
  873. nRoundedHeight
  874. );
  875. }
  876. }
  877. this._bIsPainted = true;
  878. };
  879. /**
  880. * Make the image from Canvas if the browser supports Data URI.
  881. */
  882. Drawing.prototype.makeImage = function () {
  883. if (this._bIsPainted) {
  884. _safeSetDataURI.call(this, _onMakeImage);
  885. }
  886. };
  887. /**
  888. * Return whether the QRCode is painted or not
  889. *
  890. * @return {Boolean}
  891. */
  892. Drawing.prototype.isPainted = function () {
  893. return this._bIsPainted;
  894. };
  895. /**
  896. * Clear the QRCode
  897. */
  898. Drawing.prototype.clear = function () {
  899. this._oContext.clearRect(0, 0, this._elCanvas.width, this._elCanvas.height);
  900. this._bIsPainted = false;
  901. };
  902. /**
  903. * @private
  904. * @param {Number} nNumber
  905. */
  906. Drawing.prototype.round = function (nNumber) {
  907. if (!nNumber) {
  908. return nNumber;
  909. }
  910. return Math.floor(nNumber * 1000) / 1000;
  911. };
  912. return Drawing;
  913. })();
  914. /**
  915. * Get the type by string length
  916. *
  917. * @private
  918. * @param {String} sText
  919. * @param {Number} nCorrectLevel
  920. * @return {Number} type
  921. */
  922. function _getTypeNumber(sText, nCorrectLevel) {
  923. var nType = 1;
  924. var length = _getUTF8Length(sText);
  925. for (var i = 0, len = QRCodeLimitLength.length; i <= len; i++) {
  926. var nLimit = 0;
  927. switch (nCorrectLevel) {
  928. case QRErrorCorrectLevel.L :
  929. nLimit = QRCodeLimitLength[i][0];
  930. break;
  931. case QRErrorCorrectLevel.M :
  932. nLimit = QRCodeLimitLength[i][1];
  933. break;
  934. case QRErrorCorrectLevel.Q :
  935. nLimit = QRCodeLimitLength[i][2];
  936. break;
  937. case QRErrorCorrectLevel.H :
  938. nLimit = QRCodeLimitLength[i][3];
  939. break;
  940. }
  941. if (length <= nLimit) {
  942. break;
  943. } else {
  944. nType++;
  945. }
  946. }
  947. if (nType > QRCodeLimitLength.length) {
  948. throw new Error("Too long data");
  949. }
  950. return nType;
  951. }
  952. function _getUTF8Length(sText) {
  953. var replacedText = encodeURI(sText).toString().replace(/\%[0-9a-fA-F]{2}/g, 'a');
  954. return replacedText.length + (replacedText.length != sText ? 3 : 0);
  955. }
  956. /**
  957. * @class QRCode
  958. * @constructor
  959. * @example
  960. * new QRCode(document.getElementById("test"), "http://jindo.dev.naver.com/collie");
  961. *
  962. * @example
  963. * var oQRCode = new QRCode("test", {
  964. * text : "http://naver.com",
  965. * width : 128,
  966. * height : 128
  967. * });
  968. *
  969. * oQRCode.clear(); // Clear the QRCode.
  970. * oQRCode.makeCode("http://map.naver.com"); // Re-create the QRCode.
  971. *
  972. * @param {HTMLElement|String} el target element or 'id' attribute of element.
  973. * @param {Object|String} vOption
  974. * @param {String} vOption.text QRCode link data
  975. * @param {Number} [vOption.width=256]
  976. * @param {Number} [vOption.height=256]
  977. * @param {String} [vOption.colorDark="#000000"]
  978. * @param {String} [vOption.colorLight="#ffffff"]
  979. * @param {QRCode.CorrectLevel} [vOption.correctLevel=QRCode.CorrectLevel.H] [L|M|Q|H]
  980. */
  981. QRCode = function (el, vOption) {
  982. this._htOption = {
  983. width: 256,
  984. height: 256,
  985. typeNumber: 4,
  986. colorDark: "#000000",
  987. colorLight: "#ffffff",
  988. correctLevel: QRErrorCorrectLevel.H
  989. };
  990. if (typeof vOption === 'string') {
  991. vOption = {
  992. text: vOption
  993. };
  994. }
  995. // Overwrites options
  996. if (vOption) {
  997. for (var i in vOption) {
  998. this._htOption[i] = vOption[i];
  999. }
  1000. }
  1001. if (typeof el == "string") {
  1002. el = document.getElementById(el);
  1003. }
  1004. if (this._htOption.useSVG) {
  1005. Drawing = svgDrawer;
  1006. }
  1007. this._android = _getAndroid();
  1008. this._el = el;
  1009. this._oQRCode = null;
  1010. this._oDrawing = new Drawing(this._el, this._htOption);
  1011. if (this._htOption.text) {
  1012. this.makeCode(this._htOption.text);
  1013. }
  1014. };
  1015. /**
  1016. * Make the QRCode
  1017. *
  1018. * @param {String} sText link data
  1019. */
  1020. QRCode.prototype.makeCode = function (sText) {
  1021. this._oQRCode = new QRCodeModel(_getTypeNumber(sText, this._htOption.correctLevel), this._htOption.correctLevel);
  1022. this._oQRCode.addData(sText);
  1023. this._oQRCode.make();
  1024. this._el.title = sText;
  1025. this._oDrawing.draw(this._oQRCode);
  1026. this.makeImage();
  1027. };
  1028. /**
  1029. * Make the Image from Canvas element
  1030. * - It occurs automatically
  1031. * - Android below 3 doesn't support Data-URI spec.
  1032. *
  1033. * @private
  1034. */
  1035. QRCode.prototype.makeImage = function () {
  1036. if (typeof this._oDrawing.makeImage == "function" && (!this._android || this._android >= 3)) {
  1037. this._oDrawing.makeImage();
  1038. }
  1039. };
  1040. /**
  1041. * Clear the QRCode
  1042. */
  1043. QRCode.prototype.clear = function () {
  1044. this._oDrawing.clear();
  1045. };
  1046. /**
  1047. * @name QRCode.CorrectLevel
  1048. */
  1049. QRCode.CorrectLevel = QRErrorCorrectLevel;
  1050. exports('QRCode', QRCode);
  1051. });