qrcode.js 39 KB

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