├── README
├── html5-qrcode.js
├── html5.html
└── qrcode.js
/README:
--------------------------------------------------------------------------------
1 | This example shows how you can create a QR Code PNG using Javascript and HTML5.
2 |
3 | Notes:
4 | ---
5 | This is the heart of my Tab Transmit Safari Extension.
6 |
7 | You can downloaded it from:
8 | http://ticklespace.com/tab-transmit-safari-extension
9 | or
10 | https://extensions.apple.com/
11 | Tab Transmit is listed under Productivity.
12 |
13 |
14 | Author:
15 | ---
16 | Amanuel Tewolde / TickleSpace - www.ticklespace.com
17 |
18 | Copyright (c) 2011 Amanuel Tewolde
19 |
20 | License:
21 | ---
22 | MIT
23 |
24 | Other Projects:
25 | ---
26 | QRCode.js Copyright (c) 2009 Kazuhiko Arase
27 |
--------------------------------------------------------------------------------
/html5-qrcode.js:
--------------------------------------------------------------------------------
1 | //---------------------------------------------------------------------
2 | // JavaScript-HTML5 QRCode Generator
3 | //
4 | // Copyright (c) 2011 Amanuel Tewolde
5 | //
6 | // Licensed under the MIT license:
7 | // http://www.opensource.org/licenses/mit-license.php
8 | //
9 | //---------------------------------------------------------------------
10 |
11 | // Generates a QRCode of text provided.
12 | // First QRCode is rendered to a canvas.
13 | // The canvas is then turned to an image PNG
14 | // before being returned as an
tag.
15 | function showQRCode(text) {
16 |
17 |
18 | var dotsize = 5; // size of box drawn on canvas
19 | var padding = 10; // (white area around your QRCode)
20 | var black = "rgb(0,0,0)";
21 | var white = "rgb(255,255,255)";
22 | var QRCodeVersion = 15; // 1-40 see http://www.denso-wave.com/qrcode/qrgene2-e.html
23 |
24 | var canvas=document.createElement('canvas');
25 | var qrCanvasContext = canvas.getContext('2d');
26 | try {
27 | // QR Code Error Correction Capability
28 | // Higher levels improves error correction capability while decreasing the amount of data QR Code size.
29 | // QRErrorCorrectLevel.L (5%) QRErrorCorrectLevel.M (15%) QRErrorCorrectLevel.Q (25%) QRErrorCorrectLevel.H (30%)
30 | // eg. L can survive approx 5% damage...etc.
31 | var qr = new QRCode(QRCodeVersion, QRErrorCorrectLevel.L);
32 | qr.addData(text);
33 | qr.make();
34 | }
35 | catch(err) {
36 | var errorChild = document.createElement("p");
37 | var errorMSG = document.createTextNode("QR Code FAIL! " + err);
38 | errorChild.appendChild(errorMSG);
39 | return errorChild;
40 | }
41 |
42 | var qrsize = qr.getModuleCount();
43 | canvas.setAttribute('height',(qrsize * dotsize) + padding);
44 | canvas.setAttribute('width',(qrsize * dotsize) + padding);
45 | var shiftForPadding = padding/2;
46 | if (canvas.getContext){
47 | for (var r = 0; r < qrsize; r++) {
48 | for (var c = 0; c < qrsize; c++) {
49 | if (qr.isDark(r, c))
50 | qrCanvasContext.fillStyle = black;
51 | else
52 | qrCanvasContext.fillStyle = white;
53 | qrCanvasContext.fillRect ((c*dotsize) +shiftForPadding,(r*dotsize) + shiftForPadding,dotsize,dotsize); // x, y, w, h
54 | }
55 | }
56 | }
57 |
58 | var imgElement = document.createElement("img");
59 | imgElement.src = canvas.toDataURL("image/png");
60 |
61 | return imgElement;
62 |
63 | }
64 |
65 |
--------------------------------------------------------------------------------
/html5.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
7 |
9 |
10 | QRCode Generator Example
11 |
12 |
15 |
16 |
17 |
18 | QRCode Generator Example
19 |
20 |
23 |
24 |
25 |
26 |
27 |
42 | Project Homepage
43 | TickleSpace
44 |
45 |
46 |
--------------------------------------------------------------------------------
/qrcode.js:
--------------------------------------------------------------------------------
1 | //---------------------------------------------------------------------
2 | // QRCode for JavaScript
3 | //
4 | // Copyright (c) 2009 Kazuhiko Arase
5 | //
6 | // URL: http://www.d-project.com/
7 | //
8 | // Licensed under the MIT license:
9 | // http://www.opensource.org/licenses/mit-license.php
10 | //
11 | // The word "QR Code" is registered trademark of
12 | // DENSO WAVE INCORPORATED
13 | // http://www.denso-wave.com/qrcode/faqpatent-e.html
14 | //
15 | //---------------------------------------------------------------------
16 |
17 | //---------------------------------------------------------------------
18 | // QR8bitByte
19 | //---------------------------------------------------------------------
20 |
21 | function QR8bitByte(data) {
22 | this.mode = QRMode.MODE_8BIT_BYTE;
23 | this.data = data;
24 | }
25 |
26 | QR8bitByte.prototype = {
27 |
28 | getLength : function(buffer) {
29 | return this.data.length;
30 | },
31 |
32 | write : function(buffer) {
33 | for (var i = 0; i < this.data.length; i++) {
34 | // not JIS ...
35 | buffer.put(this.data.charCodeAt(i), 8);
36 | }
37 | }
38 | };
39 |
40 | //---------------------------------------------------------------------
41 | // QRCode
42 | //---------------------------------------------------------------------
43 |
44 | function QRCode(typeNumber, errorCorrectLevel) {
45 | this.typeNumber = typeNumber;
46 | this.errorCorrectLevel = errorCorrectLevel;
47 | this.modules = null;
48 | this.moduleCount = 0;
49 | this.dataCache = null;
50 | this.dataList = new Array();
51 | }
52 |
53 | QRCode.prototype = {
54 |
55 | addData : function(data) {
56 | var newData = new QR8bitByte(data);
57 | this.dataList.push(newData);
58 | this.dataCache = null;
59 | },
60 |
61 | isDark : function(row, col) {
62 | if (row < 0 || this.moduleCount <= row || col < 0 || this.moduleCount <= col) {
63 | throw new Error(row + "," + col);
64 | }
65 | return this.modules[row][col];
66 | },
67 |
68 | getModuleCount : function() {
69 | return this.moduleCount;
70 | },
71 |
72 | make : function() {
73 | this.makeImpl(false, this.getBestMaskPattern() );
74 | },
75 |
76 | makeImpl : function(test, maskPattern) {
77 |
78 | this.moduleCount = this.typeNumber * 4 + 17;
79 | this.modules = new Array(this.moduleCount);
80 |
81 | for (var row = 0; row < this.moduleCount; row++) {
82 |
83 | this.modules[row] = new Array(this.moduleCount);
84 |
85 | for (var col = 0; col < this.moduleCount; col++) {
86 | this.modules[row][col] = null;//(col + row) % 3;
87 | }
88 | }
89 |
90 | this.setupPositionProbePattern(0, 0);
91 | this.setupPositionProbePattern(this.moduleCount - 7, 0);
92 | this.setupPositionProbePattern(0, this.moduleCount - 7);
93 | this.setupPositionAdjustPattern();
94 | this.setupTimingPattern();
95 | this.setupTypeInfo(test, maskPattern);
96 |
97 | if (this.typeNumber >= 7) {
98 | this.setupTypeNumber(test);
99 | }
100 |
101 | if (this.dataCache == null) {
102 | this.dataCache = QRCode.createData(this.typeNumber, this.errorCorrectLevel, this.dataList);
103 | }
104 |
105 | this.mapData(this.dataCache, maskPattern);
106 | },
107 |
108 | setupPositionProbePattern : function(row, col) {
109 |
110 | for (var r = -1; r <= 7; r++) {
111 |
112 | if (row + r <= -1 || this.moduleCount <= row + r) continue;
113 |
114 | for (var c = -1; c <= 7; c++) {
115 |
116 | if (col + c <= -1 || this.moduleCount <= col + c) continue;
117 |
118 | if ( (0 <= r && r <= 6 && (c == 0 || c == 6) )
119 | || (0 <= c && c <= 6 && (r == 0 || r == 6) )
120 | || (2 <= r && r <= 4 && 2 <= c && c <= 4) ) {
121 | this.modules[row + r][col + c] = true;
122 | } else {
123 | this.modules[row + r][col + c] = false;
124 | }
125 | }
126 | }
127 | },
128 |
129 | getBestMaskPattern : function() {
130 |
131 | var minLostPoint = 0;
132 | var pattern = 0;
133 |
134 | for (var i = 0; i < 8; i++) {
135 |
136 | this.makeImpl(true, i);
137 |
138 | var lostPoint = QRUtil.getLostPoint(this);
139 |
140 | if (i == 0 || minLostPoint > lostPoint) {
141 | minLostPoint = lostPoint;
142 | pattern = i;
143 | }
144 | }
145 |
146 | return pattern;
147 | },
148 |
149 | createMovieClip : function(target_mc, instance_name, depth) {
150 |
151 | var qr_mc = target_mc.createEmptyMovieClip(instance_name, depth);
152 | var cs = 1;
153 |
154 | this.make();
155 |
156 | for (var row = 0; row < this.modules.length; row++) {
157 |
158 | var y = row * cs;
159 |
160 | for (var col = 0; col < this.modules[row].length; col++) {
161 |
162 | var x = col * cs;
163 | var dark = this.modules[row][col];
164 |
165 | if (dark) {
166 | qr_mc.beginFill(0, 100);
167 | qr_mc.moveTo(x, y);
168 | qr_mc.lineTo(x + cs, y);
169 | qr_mc.lineTo(x + cs, y + cs);
170 | qr_mc.lineTo(x, y + cs);
171 | qr_mc.endFill();
172 | }
173 | }
174 | }
175 |
176 | return qr_mc;
177 | },
178 |
179 | setupTimingPattern : function() {
180 |
181 | for (var r = 8; r < this.moduleCount - 8; r++) {
182 | if (this.modules[r][6] != null) {
183 | continue;
184 | }
185 | this.modules[r][6] = (r % 2 == 0);
186 | }
187 |
188 | for (var c = 8; c < this.moduleCount - 8; c++) {
189 | if (this.modules[6][c] != null) {
190 | continue;
191 | }
192 | this.modules[6][c] = (c % 2 == 0);
193 | }
194 | },
195 |
196 | setupPositionAdjustPattern : function() {
197 |
198 | var pos = QRUtil.getPatternPosition(this.typeNumber);
199 |
200 | for (var i = 0; i < pos.length; i++) {
201 |
202 | for (var j = 0; j < pos.length; j++) {
203 |
204 | var row = pos[i];
205 | var col = pos[j];
206 |
207 | if (this.modules[row][col] != null) {
208 | continue;
209 | }
210 |
211 | for (var r = -2; r <= 2; r++) {
212 |
213 | for (var c = -2; c <= 2; c++) {
214 |
215 | if (r == -2 || r == 2 || c == -2 || c == 2
216 | || (r == 0 && c == 0) ) {
217 | this.modules[row + r][col + c] = true;
218 | } else {
219 | this.modules[row + r][col + c] = false;
220 | }
221 | }
222 | }
223 | }
224 | }
225 | },
226 |
227 | setupTypeNumber : function(test) {
228 |
229 | var bits = QRUtil.getBCHTypeNumber(this.typeNumber);
230 |
231 | for (var i = 0; i < 18; i++) {
232 | var mod = (!test && ( (bits >> i) & 1) == 1);
233 | this.modules[Math.floor(i / 3)][i % 3 + this.moduleCount - 8 - 3] = mod;
234 | }
235 |
236 | for (var i = 0; i < 18; i++) {
237 | var mod = (!test && ( (bits >> i) & 1) == 1);
238 | this.modules[i % 3 + this.moduleCount - 8 - 3][Math.floor(i / 3)] = mod;
239 | }
240 | },
241 |
242 | setupTypeInfo : function(test, maskPattern) {
243 |
244 | var data = (this.errorCorrectLevel << 3) | maskPattern;
245 | var bits = QRUtil.getBCHTypeInfo(data);
246 |
247 | // vertical
248 | for (var i = 0; i < 15; i++) {
249 |
250 | var mod = (!test && ( (bits >> i) & 1) == 1);
251 |
252 | if (i < 6) {
253 | this.modules[i][8] = mod;
254 | } else if (i < 8) {
255 | this.modules[i + 1][8] = mod;
256 | } else {
257 | this.modules[this.moduleCount - 15 + i][8] = mod;
258 | }
259 | }
260 |
261 | // horizontal
262 | for (var i = 0; i < 15; i++) {
263 |
264 | var mod = (!test && ( (bits >> i) & 1) == 1);
265 |
266 | if (i < 8) {
267 | this.modules[8][this.moduleCount - i - 1] = mod;
268 | } else if (i < 9) {
269 | this.modules[8][15 - i - 1 + 1] = mod;
270 | } else {
271 | this.modules[8][15 - i - 1] = mod;
272 | }
273 | }
274 |
275 | // fixed module
276 | this.modules[this.moduleCount - 8][8] = (!test);
277 |
278 | },
279 |
280 | mapData : function(data, maskPattern) {
281 |
282 | var inc = -1;
283 | var row = this.moduleCount - 1;
284 | var bitIndex = 7;
285 | var byteIndex = 0;
286 |
287 | for (var col = this.moduleCount - 1; col > 0; col -= 2) {
288 |
289 | if (col == 6) col--;
290 |
291 | while (true) {
292 |
293 | for (var c = 0; c < 2; c++) {
294 |
295 | if (this.modules[row][col - c] == null) {
296 |
297 | var dark = false;
298 |
299 | if (byteIndex < data.length) {
300 | dark = ( ( (data[byteIndex] >>> bitIndex) & 1) == 1);
301 | }
302 |
303 | var mask = QRUtil.getMask(maskPattern, row, col - c);
304 |
305 | if (mask) {
306 | dark = !dark;
307 | }
308 |
309 | this.modules[row][col - c] = dark;
310 | bitIndex--;
311 |
312 | if (bitIndex == -1) {
313 | byteIndex++;
314 | bitIndex = 7;
315 | }
316 | }
317 | }
318 |
319 | row += inc;
320 |
321 | if (row < 0 || this.moduleCount <= row) {
322 | row -= inc;
323 | inc = -inc;
324 | break;
325 | }
326 | }
327 | }
328 |
329 | }
330 |
331 | };
332 |
333 | QRCode.PAD0 = 0xEC;
334 | QRCode.PAD1 = 0x11;
335 |
336 | QRCode.createData = function(typeNumber, errorCorrectLevel, dataList) {
337 |
338 | var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel);
339 |
340 | var buffer = new QRBitBuffer();
341 |
342 | for (var i = 0; i < dataList.length; i++) {
343 | var data = dataList[i];
344 | buffer.put(data.mode, 4);
345 | buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber) );
346 | data.write(buffer);
347 | }
348 |
349 | // calc num max data.
350 | var totalDataCount = 0;
351 | for (var i = 0; i < rsBlocks.length; i++) {
352 | totalDataCount += rsBlocks[i].dataCount;
353 | }
354 |
355 | if (buffer.getLengthInBits() > totalDataCount * 8) {
356 | throw new Error("code length overflow. ("
357 | + buffer.getLengthInBits()
358 | + ">"
359 | + totalDataCount * 8
360 | + ")");
361 | }
362 |
363 | // end code
364 | if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {
365 | buffer.put(0, 4);
366 | }
367 |
368 | // padding
369 | while (buffer.getLengthInBits() % 8 != 0) {
370 | buffer.putBit(false);
371 | }
372 |
373 | // padding
374 | while (true) {
375 |
376 | if (buffer.getLengthInBits() >= totalDataCount * 8) {
377 | break;
378 | }
379 | buffer.put(QRCode.PAD0, 8);
380 |
381 | if (buffer.getLengthInBits() >= totalDataCount * 8) {
382 | break;
383 | }
384 | buffer.put(QRCode.PAD1, 8);
385 | }
386 |
387 | return QRCode.createBytes(buffer, rsBlocks);
388 | }
389 |
390 | QRCode.createBytes = function(buffer, rsBlocks) {
391 |
392 | var offset = 0;
393 |
394 | var maxDcCount = 0;
395 | var maxEcCount = 0;
396 |
397 | var dcdata = new Array(rsBlocks.length);
398 | var ecdata = new Array(rsBlocks.length);
399 |
400 | for (var r = 0; r < rsBlocks.length; r++) {
401 |
402 | var dcCount = rsBlocks[r].dataCount;
403 | var ecCount = rsBlocks[r].totalCount - dcCount;
404 |
405 | maxDcCount = Math.max(maxDcCount, dcCount);
406 | maxEcCount = Math.max(maxEcCount, ecCount);
407 |
408 | dcdata[r] = new Array(dcCount);
409 |
410 | for (var i = 0; i < dcdata[r].length; i++) {
411 | dcdata[r][i] = 0xff & buffer.buffer[i + offset];
412 | }
413 | offset += dcCount;
414 |
415 | var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
416 | var rawPoly = new QRPolynomial(dcdata[r], rsPoly.getLength() - 1);
417 |
418 | var modPoly = rawPoly.mod(rsPoly);
419 | ecdata[r] = new Array(rsPoly.getLength() - 1);
420 | for (var i = 0; i < ecdata[r].length; i++) {
421 | var modIndex = i + modPoly.getLength() - ecdata[r].length;
422 | ecdata[r][i] = (modIndex >= 0)? modPoly.get(modIndex) : 0;
423 | }
424 |
425 | }
426 |
427 | var totalCodeCount = 0;
428 | for (var i = 0; i < rsBlocks.length; i++) {
429 | totalCodeCount += rsBlocks[i].totalCount;
430 | }
431 |
432 | var data = new Array(totalCodeCount);
433 | var index = 0;
434 |
435 | for (var i = 0; i < maxDcCount; i++) {
436 | for (var r = 0; r < rsBlocks.length; r++) {
437 | if (i < dcdata[r].length) {
438 | data[index++] = dcdata[r][i];
439 | }
440 | }
441 | }
442 |
443 | for (var i = 0; i < maxEcCount; i++) {
444 | for (var r = 0; r < rsBlocks.length; r++) {
445 | if (i < ecdata[r].length) {
446 | data[index++] = ecdata[r][i];
447 | }
448 | }
449 | }
450 |
451 | return data;
452 |
453 | }
454 |
455 | //---------------------------------------------------------------------
456 | // QRMode
457 | //---------------------------------------------------------------------
458 |
459 | var QRMode = {
460 | MODE_NUMBER : 1 << 0,
461 | MODE_ALPHA_NUM : 1 << 1,
462 | MODE_8BIT_BYTE : 1 << 2,
463 | MODE_KANJI : 1 << 3
464 | };
465 |
466 | //---------------------------------------------------------------------
467 | // QRErrorCorrectLevel
468 | //---------------------------------------------------------------------
469 |
470 | var QRErrorCorrectLevel = {
471 | L : 1,
472 | M : 0,
473 | Q : 3,
474 | H : 2
475 | };
476 |
477 | //---------------------------------------------------------------------
478 | // QRMaskPattern
479 | //---------------------------------------------------------------------
480 |
481 | var QRMaskPattern = {
482 | PATTERN000 : 0,
483 | PATTERN001 : 1,
484 | PATTERN010 : 2,
485 | PATTERN011 : 3,
486 | PATTERN100 : 4,
487 | PATTERN101 : 5,
488 | PATTERN110 : 6,
489 | PATTERN111 : 7
490 | };
491 |
492 | //---------------------------------------------------------------------
493 | // QRUtil
494 | //---------------------------------------------------------------------
495 |
496 | var QRUtil = {
497 |
498 | PATTERN_POSITION_TABLE : [
499 | [],
500 | [6, 18],
501 | [6, 22],
502 | [6, 26],
503 | [6, 30],
504 | [6, 34],
505 | [6, 22, 38],
506 | [6, 24, 42],
507 | [6, 26, 46],
508 | [6, 28, 50],
509 | [6, 30, 54],
510 | [6, 32, 58],
511 | [6, 34, 62],
512 | [6, 26, 46, 66],
513 | [6, 26, 48, 70],
514 | [6, 26, 50, 74],
515 | [6, 30, 54, 78],
516 | [6, 30, 56, 82],
517 | [6, 30, 58, 86],
518 | [6, 34, 62, 90],
519 | [6, 28, 50, 72, 94],
520 | [6, 26, 50, 74, 98],
521 | [6, 30, 54, 78, 102],
522 | [6, 28, 54, 80, 106],
523 | [6, 32, 58, 84, 110],
524 | [6, 30, 58, 86, 114],
525 | [6, 34, 62, 90, 118],
526 | [6, 26, 50, 74, 98, 122],
527 | [6, 30, 54, 78, 102, 126],
528 | [6, 26, 52, 78, 104, 130],
529 | [6, 30, 56, 82, 108, 134],
530 | [6, 34, 60, 86, 112, 138],
531 | [6, 30, 58, 86, 114, 142],
532 | [6, 34, 62, 90, 118, 146],
533 | [6, 30, 54, 78, 102, 126, 150],
534 | [6, 24, 50, 76, 102, 128, 154],
535 | [6, 28, 54, 80, 106, 132, 158],
536 | [6, 32, 58, 84, 110, 136, 162],
537 | [6, 26, 54, 82, 110, 138, 166],
538 | [6, 30, 58, 86, 114, 142, 170]
539 | ],
540 |
541 | G15 : (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0),
542 | G18 : (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0),
543 | G15_MASK : (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1),
544 |
545 | getBCHTypeInfo : function(data) {
546 | var d = data << 10;
547 | while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0) {
548 | d ^= (QRUtil.G15 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) ) );
549 | }
550 | return ( (data << 10) | d) ^ QRUtil.G15_MASK;
551 | },
552 |
553 | getBCHTypeNumber : function(data) {
554 | var d = data << 12;
555 | while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0) {
556 | d ^= (QRUtil.G18 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) ) );
557 | }
558 | return (data << 12) | d;
559 | },
560 |
561 | getBCHDigit : function(data) {
562 |
563 | var digit = 0;
564 |
565 | while (data != 0) {
566 | digit++;
567 | data >>>= 1;
568 | }
569 |
570 | return digit;
571 | },
572 |
573 | getPatternPosition : function(typeNumber) {
574 | return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1];
575 | },
576 |
577 | getMask : function(maskPattern, i, j) {
578 |
579 | switch (maskPattern) {
580 |
581 | case QRMaskPattern.PATTERN000 : return (i + j) % 2 == 0;
582 | case QRMaskPattern.PATTERN001 : return i % 2 == 0;
583 | case QRMaskPattern.PATTERN010 : return j % 3 == 0;
584 | case QRMaskPattern.PATTERN011 : return (i + j) % 3 == 0;
585 | case QRMaskPattern.PATTERN100 : return (Math.floor(i / 2) + Math.floor(j / 3) ) % 2 == 0;
586 | case QRMaskPattern.PATTERN101 : return (i * j) % 2 + (i * j) % 3 == 0;
587 | case QRMaskPattern.PATTERN110 : return ( (i * j) % 2 + (i * j) % 3) % 2 == 0;
588 | case QRMaskPattern.PATTERN111 : return ( (i * j) % 3 + (i + j) % 2) % 2 == 0;
589 |
590 | default :
591 | throw new Error("bad maskPattern:" + maskPattern);
592 | }
593 | },
594 |
595 | getErrorCorrectPolynomial : function(errorCorrectLength) {
596 |
597 | var a = new QRPolynomial([1], 0);
598 |
599 | for (var i = 0; i < errorCorrectLength; i++) {
600 | a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0) );
601 | }
602 |
603 | return a;
604 | },
605 |
606 | getLengthInBits : function(mode, type) {
607 |
608 | if (1 <= type && type < 10) {
609 |
610 | // 1 - 9
611 |
612 | switch(mode) {
613 | case QRMode.MODE_NUMBER : return 10;
614 | case QRMode.MODE_ALPHA_NUM : return 9;
615 | case QRMode.MODE_8BIT_BYTE : return 8;
616 | case QRMode.MODE_KANJI : return 8;
617 | default :
618 | throw new Error("mode:" + mode);
619 | }
620 |
621 | } else if (type < 27) {
622 |
623 | // 10 - 26
624 |
625 | switch(mode) {
626 | case QRMode.MODE_NUMBER : return 12;
627 | case QRMode.MODE_ALPHA_NUM : return 11;
628 | case QRMode.MODE_8BIT_BYTE : return 16;
629 | case QRMode.MODE_KANJI : return 10;
630 | default :
631 | throw new Error("mode:" + mode);
632 | }
633 |
634 | } else if (type < 41) {
635 |
636 | // 27 - 40
637 |
638 | switch(mode) {
639 | case QRMode.MODE_NUMBER : return 14;
640 | case QRMode.MODE_ALPHA_NUM : return 13;
641 | case QRMode.MODE_8BIT_BYTE : return 16;
642 | case QRMode.MODE_KANJI : return 12;
643 | default :
644 | throw new Error("mode:" + mode);
645 | }
646 |
647 | } else {
648 | throw new Error("type:" + type);
649 | }
650 | },
651 |
652 | getLostPoint : function(qrCode) {
653 |
654 | var moduleCount = qrCode.getModuleCount();
655 |
656 | var lostPoint = 0;
657 |
658 | // LEVEL1
659 |
660 | for (var row = 0; row < moduleCount; row++) {
661 |
662 | for (var col = 0; col < moduleCount; col++) {
663 |
664 | var sameCount = 0;
665 | var dark = qrCode.isDark(row, col);
666 |
667 | for (var r = -1; r <= 1; r++) {
668 |
669 | if (row + r < 0 || moduleCount <= row + r) {
670 | continue;
671 | }
672 |
673 | for (var c = -1; c <= 1; c++) {
674 |
675 | if (col + c < 0 || moduleCount <= col + c) {
676 | continue;
677 | }
678 |
679 | if (r == 0 && c == 0) {
680 | continue;
681 | }
682 |
683 | if (dark == qrCode.isDark(row + r, col + c) ) {
684 | sameCount++;
685 | }
686 | }
687 | }
688 |
689 | if (sameCount > 5) {
690 | lostPoint += (3 + sameCount - 5);
691 | }
692 | }
693 | }
694 |
695 | // LEVEL2
696 |
697 | for (var row = 0; row < moduleCount - 1; row++) {
698 | for (var col = 0; col < moduleCount - 1; col++) {
699 | var count = 0;
700 | if (qrCode.isDark(row, col ) ) count++;
701 | if (qrCode.isDark(row + 1, col ) ) count++;
702 | if (qrCode.isDark(row, col + 1) ) count++;
703 | if (qrCode.isDark(row + 1, col + 1) ) count++;
704 | if (count == 0 || count == 4) {
705 | lostPoint += 3;
706 | }
707 | }
708 | }
709 |
710 | // LEVEL3
711 |
712 | for (var row = 0; row < moduleCount; row++) {
713 | for (var col = 0; col < moduleCount - 6; col++) {
714 | if (qrCode.isDark(row, col)
715 | && !qrCode.isDark(row, col + 1)
716 | && qrCode.isDark(row, col + 2)
717 | && qrCode.isDark(row, col + 3)
718 | && qrCode.isDark(row, col + 4)
719 | && !qrCode.isDark(row, col + 5)
720 | && qrCode.isDark(row, col + 6) ) {
721 | lostPoint += 40;
722 | }
723 | }
724 | }
725 |
726 | for (var col = 0; col < moduleCount; col++) {
727 | for (var row = 0; row < moduleCount - 6; row++) {
728 | if (qrCode.isDark(row, col)
729 | && !qrCode.isDark(row + 1, col)
730 | && qrCode.isDark(row + 2, col)
731 | && qrCode.isDark(row + 3, col)
732 | && qrCode.isDark(row + 4, col)
733 | && !qrCode.isDark(row + 5, col)
734 | && qrCode.isDark(row + 6, col) ) {
735 | lostPoint += 40;
736 | }
737 | }
738 | }
739 |
740 | // LEVEL4
741 |
742 | var darkCount = 0;
743 |
744 | for (var col = 0; col < moduleCount; col++) {
745 | for (var row = 0; row < moduleCount; row++) {
746 | if (qrCode.isDark(row, col) ) {
747 | darkCount++;
748 | }
749 | }
750 | }
751 |
752 | var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5;
753 | lostPoint += ratio * 10;
754 |
755 | return lostPoint;
756 | }
757 |
758 | };
759 |
760 |
761 | //---------------------------------------------------------------------
762 | // QRMath
763 | //---------------------------------------------------------------------
764 |
765 | var QRMath = {
766 |
767 | glog : function(n) {
768 |
769 | if (n < 1) {
770 | throw new Error("glog(" + n + ")");
771 | }
772 |
773 | return QRMath.LOG_TABLE[n];
774 | },
775 |
776 | gexp : function(n) {
777 |
778 | while (n < 0) {
779 | n += 255;
780 | }
781 |
782 | while (n >= 256) {
783 | n -= 255;
784 | }
785 |
786 | return QRMath.EXP_TABLE[n];
787 | },
788 |
789 | EXP_TABLE : new Array(256),
790 |
791 | LOG_TABLE : new Array(256)
792 |
793 | };
794 |
795 | for (var i = 0; i < 8; i++) {
796 | QRMath.EXP_TABLE[i] = 1 << i;
797 | }
798 | for (var i = 8; i < 256; i++) {
799 | QRMath.EXP_TABLE[i] = QRMath.EXP_TABLE[i - 4]
800 | ^ QRMath.EXP_TABLE[i - 5]
801 | ^ QRMath.EXP_TABLE[i - 6]
802 | ^ QRMath.EXP_TABLE[i - 8];
803 | }
804 | for (var i = 0; i < 255; i++) {
805 | QRMath.LOG_TABLE[QRMath.EXP_TABLE[i] ] = i;
806 | }
807 |
808 | //---------------------------------------------------------------------
809 | // QRPolynomial
810 | //---------------------------------------------------------------------
811 |
812 | function QRPolynomial(num, shift) {
813 |
814 | if (num.length == undefined) {
815 | throw new Error(num.length + "/" + shift);
816 | }
817 |
818 | var offset = 0;
819 |
820 | while (offset < num.length && num[offset] == 0) {
821 | offset++;
822 | }
823 |
824 | this.num = new Array(num.length - offset + shift);
825 | for (var i = 0; i < num.length - offset; i++) {
826 | this.num[i] = num[i + offset];
827 | }
828 | }
829 |
830 | QRPolynomial.prototype = {
831 |
832 | get : function(index) {
833 | return this.num[index];
834 | },
835 |
836 | getLength : function() {
837 | return this.num.length;
838 | },
839 |
840 | multiply : function(e) {
841 |
842 | var num = new Array(this.getLength() + e.getLength() - 1);
843 |
844 | for (var i = 0; i < this.getLength(); i++) {
845 | for (var j = 0; j < e.getLength(); j++) {
846 | num[i + j] ^= QRMath.gexp(QRMath.glog(this.get(i) ) + QRMath.glog(e.get(j) ) );
847 | }
848 | }
849 |
850 | return new QRPolynomial(num, 0);
851 | },
852 |
853 | mod : function(e) {
854 |
855 | if (this.getLength() - e.getLength() < 0) {
856 | return this;
857 | }
858 |
859 | var ratio = QRMath.glog(this.get(0) ) - QRMath.glog(e.get(0) );
860 |
861 | var num = new Array(this.getLength() );
862 |
863 | for (var i = 0; i < this.getLength(); i++) {
864 | num[i] = this.get(i);
865 | }
866 |
867 | for (var i = 0; i < e.getLength(); i++) {
868 | num[i] ^= QRMath.gexp(QRMath.glog(e.get(i) ) + ratio);
869 | }
870 |
871 | // recursive call
872 | return new QRPolynomial(num, 0).mod(e);
873 | }
874 | };
875 |
876 | //---------------------------------------------------------------------
877 | // QRRSBlock
878 | //---------------------------------------------------------------------
879 |
880 | function QRRSBlock(totalCount, dataCount) {
881 | this.totalCount = totalCount;
882 | this.dataCount = dataCount;
883 | }
884 |
885 | QRRSBlock.RS_BLOCK_TABLE = [
886 |
887 | // L
888 | // M
889 | // Q
890 | // H
891 |
892 | // 1
893 | [1, 26, 19],
894 | [1, 26, 16],
895 | [1, 26, 13],
896 | [1, 26, 9],
897 |
898 | // 2
899 | [1, 44, 34],
900 | [1, 44, 28],
901 | [1, 44, 22],
902 | [1, 44, 16],
903 |
904 | // 3
905 | [1, 70, 55],
906 | [1, 70, 44],
907 | [2, 35, 17],
908 | [2, 35, 13],
909 |
910 | // 4
911 | [1, 100, 80],
912 | [2, 50, 32],
913 | [2, 50, 24],
914 | [4, 25, 9],
915 |
916 | // 5
917 | [1, 134, 108],
918 | [2, 67, 43],
919 | [2, 33, 15, 2, 34, 16],
920 | [2, 33, 11, 2, 34, 12],
921 |
922 | // 6
923 | [2, 86, 68],
924 | [4, 43, 27],
925 | [4, 43, 19],
926 | [4, 43, 15],
927 |
928 | // 7
929 | [2, 98, 78],
930 | [4, 49, 31],
931 | [2, 32, 14, 4, 33, 15],
932 | [4, 39, 13, 1, 40, 14],
933 |
934 | // 8
935 | [2, 121, 97],
936 | [2, 60, 38, 2, 61, 39],
937 | [4, 40, 18, 2, 41, 19],
938 | [4, 40, 14, 2, 41, 15],
939 |
940 | // 9
941 | [2, 146, 116],
942 | [3, 58, 36, 2, 59, 37],
943 | [4, 36, 16, 4, 37, 17],
944 | [4, 36, 12, 4, 37, 13],
945 |
946 | // 10
947 | [2, 86, 68, 2, 87, 69],
948 | [4, 69, 43, 1, 70, 44],
949 | [6, 43, 19, 2, 44, 20],
950 | [6, 43, 15, 2, 44, 16],
951 |
952 | // 11
953 | [4, 101, 81],
954 | [1, 80, 50, 4, 81, 51],
955 | [4, 50, 22, 4, 51, 23],
956 | [3, 36, 12, 8, 37, 13],
957 |
958 | // 12
959 | [2, 116, 92, 2, 117, 93],
960 | [6, 58, 36, 2, 59, 37],
961 | [4, 46, 20, 6, 47, 21],
962 | [7, 42, 14, 4, 43, 15],
963 |
964 | // 13
965 | [4, 133, 107],
966 | [8, 59, 37, 1, 60, 38],
967 | [8, 44, 20, 4, 45, 21],
968 | [12, 33, 11, 4, 34, 12],
969 |
970 | // 14
971 | [3, 145, 115, 1, 146, 116],
972 | [4, 64, 40, 5, 65, 41],
973 | [11, 36, 16, 5, 37, 17],
974 | [11, 36, 12, 5, 37, 13],
975 |
976 | // 15
977 | [5, 109, 87, 1, 110, 88],
978 | [5, 65, 41, 5, 66, 42],
979 | [5, 54, 24, 7, 55, 25],
980 | [11, 36, 12],
981 |
982 | // 16
983 | [5, 122, 98, 1, 123, 99],
984 | [7, 73, 45, 3, 74, 46],
985 | [15, 43, 19, 2, 44, 20],
986 | [3, 45, 15, 13, 46, 16],
987 |
988 | // 17
989 | [1, 135, 107, 5, 136, 108],
990 | [10, 74, 46, 1, 75, 47],
991 | [1, 50, 22, 15, 51, 23],
992 | [2, 42, 14, 17, 43, 15],
993 |
994 | // 18
995 | [5, 150, 120, 1, 151, 121],
996 | [9, 69, 43, 4, 70, 44],
997 | [17, 50, 22, 1, 51, 23],
998 | [2, 42, 14, 19, 43, 15],
999 |
1000 | // 19
1001 | [3, 141, 113, 4, 142, 114],
1002 | [3, 70, 44, 11, 71, 45],
1003 | [17, 47, 21, 4, 48, 22],
1004 | [9, 39, 13, 16, 40, 14],
1005 |
1006 | // 20
1007 | [3, 135, 107, 5, 136, 108],
1008 | [3, 67, 41, 13, 68, 42],
1009 | [15, 54, 24, 5, 55, 25],
1010 | [15, 43, 15, 10, 44, 16],
1011 |
1012 | // 21
1013 | [4, 144, 116, 4, 145, 117],
1014 | [17, 68, 42],
1015 | [17, 50, 22, 6, 51, 23],
1016 | [19, 46, 16, 6, 47, 17],
1017 |
1018 | // 22
1019 | [2, 139, 111, 7, 140, 112],
1020 | [17, 74, 46],
1021 | [7, 54, 24, 16, 55, 25],
1022 | [34, 37, 13],
1023 |
1024 | // 23
1025 | [4, 151, 121, 5, 152, 122],
1026 | [4, 75, 47, 14, 76, 48],
1027 | [11, 54, 24, 14, 55, 25],
1028 | [16, 45, 15, 14, 46, 16],
1029 |
1030 | // 24
1031 | [6, 147, 117, 4, 148, 118],
1032 | [6, 73, 45, 14, 74, 46],
1033 | [11, 54, 24, 16, 55, 25],
1034 | [30, 46, 16, 2, 47, 17],
1035 |
1036 | // 25
1037 | [8, 132, 106, 4, 133, 107],
1038 | [8, 75, 47, 13, 76, 48],
1039 | [7, 54, 24, 22, 55, 25],
1040 | [22, 45, 15, 13, 46, 16],
1041 |
1042 | // 26
1043 | [10, 142, 114, 2, 143, 115],
1044 | [19, 74, 46, 4, 75, 47],
1045 | [28, 50, 22, 6, 51, 23],
1046 | [33, 46, 16, 4, 47, 17],
1047 |
1048 | // 27
1049 | [8, 152, 122, 4, 153, 123],
1050 | [22, 73, 45, 3, 74, 46],
1051 | [8, 53, 23, 26, 54, 24],
1052 | [12, 45, 15, 28, 46, 16],
1053 |
1054 | // 28
1055 | [3, 147, 117, 10, 148, 118],
1056 | [3, 73, 45, 23, 74, 46],
1057 | [4, 54, 24, 31, 55, 25],
1058 | [11, 45, 15, 31, 46, 16],
1059 |
1060 | // 29
1061 | [7, 146, 116, 7, 147, 117],
1062 | [21, 73, 45, 7, 74, 46],
1063 | [1, 53, 23, 37, 54, 24],
1064 | [19, 45, 15, 26, 46, 16],
1065 |
1066 | // 30
1067 | [5, 145, 115, 10, 146, 116],
1068 | [19, 75, 47, 10, 76, 48],
1069 | [15, 54, 24, 25, 55, 25],
1070 | [23, 45, 15, 25, 46, 16],
1071 |
1072 | // 31
1073 | [13, 145, 115, 3, 146, 116],
1074 | [2, 74, 46, 29, 75, 47],
1075 | [42, 54, 24, 1, 55, 25],
1076 | [23, 45, 15, 28, 46, 16],
1077 |
1078 | // 32
1079 | [17, 145, 115],
1080 | [10, 74, 46, 23, 75, 47],
1081 | [10, 54, 24, 35, 55, 25],
1082 | [19, 45, 15, 35, 46, 16],
1083 |
1084 | // 33
1085 | [17, 145, 115, 1, 146, 116],
1086 | [14, 74, 46, 21, 75, 47],
1087 | [29, 54, 24, 19, 55, 25],
1088 | [11, 45, 15, 46, 46, 16],
1089 |
1090 | // 34
1091 | [13, 145, 115, 6, 146, 116],
1092 | [14, 74, 46, 23, 75, 47],
1093 | [44, 54, 24, 7, 55, 25],
1094 | [59, 46, 16, 1, 47, 17],
1095 |
1096 | // 35
1097 | [12, 151, 121, 7, 152, 122],
1098 | [12, 75, 47, 26, 76, 48],
1099 | [39, 54, 24, 14, 55, 25],
1100 | [22, 45, 15, 41, 46, 16],
1101 |
1102 | // 36
1103 | [6, 151, 121, 14, 152, 122],
1104 | [6, 75, 47, 34, 76, 48],
1105 | [46, 54, 24, 10, 55, 25],
1106 | [2, 45, 15, 64, 46, 16],
1107 |
1108 | // 37
1109 | [17, 152, 122, 4, 153, 123],
1110 | [29, 74, 46, 14, 75, 47],
1111 | [49, 54, 24, 10, 55, 25],
1112 | [24, 45, 15, 46, 46, 16],
1113 |
1114 | // 38
1115 | [4, 152, 122, 18, 153, 123],
1116 | [13, 74, 46, 32, 75, 47],
1117 | [48, 54, 24, 14, 55, 25],
1118 | [42, 45, 15, 32, 46, 16],
1119 |
1120 | // 39
1121 | [20, 147, 117, 4, 148, 118],
1122 | [40, 75, 47, 7, 76, 48],
1123 | [43, 54, 24, 22, 55, 25],
1124 | [10, 45, 15, 67, 46, 16],
1125 |
1126 | // 40
1127 | [19, 148, 118, 6, 149, 119],
1128 | [18, 75, 47, 31, 76, 48],
1129 | [34, 54, 24, 34, 55, 25],
1130 | [20, 45, 15, 61, 46, 16]
1131 |
1132 | ];
1133 |
1134 | QRRSBlock.getRSBlocks = function(typeNumber, errorCorrectLevel) {
1135 |
1136 | var rsBlock = QRRSBlock.getRsBlockTable(typeNumber, errorCorrectLevel);
1137 |
1138 | if (rsBlock == undefined) {
1139 | throw new Error("bad rs block @ typeNumber:" + typeNumber + "/errorCorrectLevel:" + errorCorrectLevel);
1140 | }
1141 |
1142 | var length = rsBlock.length / 3;
1143 |
1144 | var list = new Array();
1145 |
1146 | for (var i = 0; i < length; i++) {
1147 |
1148 | var count = rsBlock[i * 3 + 0];
1149 | var totalCount = rsBlock[i * 3 + 1];
1150 | var dataCount = rsBlock[i * 3 + 2];
1151 |
1152 | for (var j = 0; j < count; j++) {
1153 | list.push(new QRRSBlock(totalCount, dataCount) );
1154 | }
1155 | }
1156 |
1157 | return list;
1158 | }
1159 |
1160 | QRRSBlock.getRsBlockTable = function(typeNumber, errorCorrectLevel) {
1161 |
1162 | switch(errorCorrectLevel) {
1163 | case QRErrorCorrectLevel.L :
1164 | return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];
1165 | case QRErrorCorrectLevel.M :
1166 | return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];
1167 | case QRErrorCorrectLevel.Q :
1168 | return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];
1169 | case QRErrorCorrectLevel.H :
1170 | return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];
1171 | default :
1172 | return undefined;
1173 | }
1174 | }
1175 |
1176 | //---------------------------------------------------------------------
1177 | // QRBitBuffer
1178 | //---------------------------------------------------------------------
1179 |
1180 | function QRBitBuffer() {
1181 | this.buffer = new Array();
1182 | this.length = 0;
1183 | }
1184 |
1185 | QRBitBuffer.prototype = {
1186 |
1187 | get : function(index) {
1188 | var bufIndex = Math.floor(index / 8);
1189 | return ( (this.buffer[bufIndex] >>> (7 - index % 8) ) & 1) == 1;
1190 | },
1191 |
1192 | put : function(num, length) {
1193 | for (var i = 0; i < length; i++) {
1194 | this.putBit( ( (num >>> (length - i - 1) ) & 1) == 1);
1195 | }
1196 | },
1197 |
1198 | getLengthInBits : function() {
1199 | return this.length;
1200 | },
1201 |
1202 | putBit : function(bit) {
1203 |
1204 | var bufIndex = Math.floor(this.length / 8);
1205 | if (this.buffer.length <= bufIndex) {
1206 | this.buffer.push(0);
1207 | }
1208 |
1209 | if (bit) {
1210 | this.buffer[bufIndex] |= (0x80 >>> (this.length % 8) );
1211 | }
1212 |
1213 | this.length++;
1214 | }
1215 | };
1216 |
--------------------------------------------------------------------------------