codekingpro/portable-devtools
114k
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// Modified to work in node for this project (and some refactoring)
17//---------------------------------------------------------------------
18
19var QR8bitByte = require('./QR8bitByte');
20var QRUtil = require('./QRUtil');
21var QRPolynomial = require('./QRPolynomial');
22var QRRSBlock = require('./QRRSBlock');
23var QRBitBuffer = require('./QRBitBuffer');
24
25function QRCode(typeNumber, errorCorrectLevel) {
26 this.typeNumber = typeNumber;
27 this.errorCorrectLevel = errorCorrectLevel;
28 this.modules = null;
29 this.moduleCount = 0;
30 this.dataCache = null;
31 this.dataList = [];
32}
33
34QRCode.prototype = {
35
36 addData : function(data) {
37 var newData = new QR8bitByte(data);
38 this.dataList.push(newData);
39 this.dataCache = null;
40 },
41
42 isDark : function(row, col) {
43 if (row < 0 || this.moduleCount <= row || col < 0 || this.moduleCount <= col) {
44 throw new Error(row + "," + col);
45 }
46 return this.modules[row][col];
47 },
48
49 getModuleCount : function() {
50 return this.moduleCount;
51 },
52
53 make : function() {
54 // Calculate automatically typeNumber if provided is < 1
55 if (this.typeNumber < 1 ){
56 var typeNumber = 1;
57 for (typeNumber = 1; typeNumber < 40; typeNumber++) {
58 var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, this.errorCorrectLevel);
59
60 var buffer = new QRBitBuffer();
61 var totalDataCount = 0;
62 for (var i = 0; i < rsBlocks.length; i++) {
63 totalDataCount += rsBlocks[i].dataCount;
64 }
65
66 for (var x = 0; x < this.dataList.length; x++) {
67 var data = this.dataList[x];
68 buffer.put(data.mode, 4);
69 buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber) );
70 data.write(buffer);
71 }
72 if (buffer.getLengthInBits() <= totalDataCount * 8)
73 break;
74 }
75 this.typeNumber = typeNumber;
76 }
77 this.makeImpl(false, this.getBestMaskPattern() );
78 },
79
80 makeImpl : function(test, maskPattern) {
81
82 this.moduleCount = this.typeNumber * 4 + 17;
83 this.modules = new Array(this.moduleCount);
84
85 for (var row = 0; row < this.moduleCount; row++) {
86
87 this.modules[row] = new Array(this.moduleCount);
88
89 for (var col = 0; col < this.moduleCount; col++) {
90 this.modules[row][col] = null;//(col + row) % 3;
91 }
92 }
93
94 this.setupPositionProbePattern(0, 0);
95 this.setupPositionProbePattern(this.moduleCount - 7, 0);
96 this.setupPositionProbePattern(0, this.moduleCount - 7);
97 this.setupPositionAdjustPattern();
98 this.setupTimingPattern();
99 this.setupTypeInfo(test, maskPattern);
100
101 if (this.typeNumber >= 7) {
102 this.setupTypeNumber(test);
103 }
104
105 if (this.dataCache === null) {
106 this.dataCache = QRCode.createData(this.typeNumber, this.errorCorrectLevel, this.dataList);
107 }
108
109 this.mapData(this.dataCache, maskPattern);
110 },
111
112 setupPositionProbePattern : function(row, col) {
113
114 for (var r = -1; r <= 7; r++) {
115
116 if (row + r <= -1 || this.moduleCount <= row + r) continue;
117
118 for (var c = -1; c <= 7; c++) {
119
120 if (col + c <= -1 || this.moduleCount <= col + c) continue;
121
122 if ( (0 <= r && r <= 6 && (c === 0 || c === 6) ) ||
123 (0 <= c && c <= 6 && (r === 0 || r === 6) ) ||
124 (2 <= r && r <= 4 && 2 <= c && c <= 4) ) {
125 this.modules[row + r][col + c] = true;
126 } else {
127 this.modules[row + r][col + c] = false;
128 }
129 }
130 }
131 },
132
133 getBestMaskPattern : function() {
134
135 var minLostPoint = 0;
136 var pattern = 0;
137
138 for (var i = 0; i < 8; i++) {
139
140 this.makeImpl(true, i);
141
142 var lostPoint = QRUtil.getLostPoint(this);
143
144 if (i === 0 || minLostPoint > lostPoint) {
145 minLostPoint = lostPoint;
146 pattern = i;
147 }
148 }
149
150 return pattern;
151 },
152
153 createMovieClip : function(target_mc, instance_name, depth) {
154
155 var qr_mc = target_mc.createEmptyMovieClip(instance_name, depth);
156 var cs = 1;
157
158 this.make();
159
160 for (var row = 0; row < this.modules.length; row++) {
161
162 var y = row * cs;
163
164 for (var col = 0; col < this.modules[row].length; col++) {
165
166 var x = col * cs;
167 var dark = this.modules[row][col];
168
169 if (dark) {
170 qr_mc.beginFill(0, 100);
171 qr_mc.moveTo(x, y);
172 qr_mc.lineTo(x + cs, y);
173 qr_mc.lineTo(x + cs, y + cs);
174 qr_mc.lineTo(x, y + cs);
175 qr_mc.endFill();
176 }
177 }
178 }
179
180 return qr_mc;
181 },
182
183 setupTimingPattern : function() {
184
185 for (var r = 8; r < this.moduleCount - 8; r++) {
186 if (this.modules[r][6] !== null) {
187 continue;
188 }
189 this.modules[r][6] = (r % 2 === 0);
190 }
191
192 for (var c = 8; c < this.moduleCount - 8; c++) {
193 if (this.modules[6][c] !== null) {
194 continue;
195 }
196 this.modules[6][c] = (c % 2 === 0);
197 }
198 },
199
200 setupPositionAdjustPattern : function() {
201
202 var pos = QRUtil.getPatternPosition(this.typeNumber);
203
204 for (var i = 0; i < pos.length; i++) {
205
206 for (var j = 0; j < pos.length; j++) {
207
208 var row = pos[i];
209 var col = pos[j];
210
211 if (this.modules[row][col] !== null) {
212 continue;
213 }
214
215 for (var r = -2; r <= 2; r++) {
216
217 for (var c = -2; c <= 2; c++) {
218
219 if (Math.abs(r) === 2 ||
220 Math.abs(c) === 2 ||
221 (r === 0 && c === 0) ) {
222 this.modules[row + r][col + c] = true;
223 } else {
224 this.modules[row + r][col + c] = false;
225 }
226 }
227 }
228 }
229 }
230 },
231
232 setupTypeNumber : function(test) {
233
234 var bits = QRUtil.getBCHTypeNumber(this.typeNumber);
235 var mod;
236
237 for (var i = 0; i < 18; i++) {
238 mod = (!test && ( (bits >> i) & 1) === 1);
239 this.modules[Math.floor(i / 3)][i % 3 + this.moduleCount - 8 - 3] = mod;
240 }
241
242 for (var x = 0; x < 18; x++) {
243 mod = (!test && ( (bits >> x) & 1) === 1);
244 this.modules[x % 3 + this.moduleCount - 8 - 3][Math.floor(x / 3)] = mod;
245 }
246 },
247
248 setupTypeInfo : function(test, maskPattern) {
249
250 var data = (this.errorCorrectLevel << 3) | maskPattern;
251 var bits = QRUtil.getBCHTypeInfo(data);
252 var mod;
253
254 // vertical
255 for (var v = 0; v < 15; v++) {
256
257 mod = (!test && ( (bits >> v) & 1) === 1);
258
259 if (v < 6) {
260 this.modules[v][8] = mod;
261 } else if (v < 8) {
262 this.modules[v + 1][8] = mod;
263 } else {
264 this.modules[this.moduleCount - 15 + v][8] = mod;
265 }
266 }
267
268 // horizontal
269 for (var h = 0; h < 15; h++) {
270
271 mod = (!test && ( (bits >> h) & 1) === 1);
272
273 if (h < 8) {
274 this.modules[8][this.moduleCount - h - 1] = mod;
275 } else if (h < 9) {
276 this.modules[8][15 - h - 1 + 1] = mod;
277 } else {
278 this.modules[8][15 - h - 1] = mod;
279 }
280 }
281
282 // fixed module
283 this.modules[this.moduleCount - 8][8] = (!test);
284
285 },
286
287 mapData : function(data, maskPattern) {
288
289 var inc = -1;
290 var row = this.moduleCount - 1;
291 var bitIndex = 7;
292 var byteIndex = 0;
293
294 for (var col = this.moduleCount - 1; col > 0; col -= 2) {
295
296 if (col === 6) col--;
297
298 while (true) {
299
300 for (var c = 0; c < 2; c++) {
301
302 if (this.modules[row][col - c] === null) {
303
304 var dark = false;
305
306 if (byteIndex < data.length) {
307 dark = ( ( (data[byteIndex] >>> bitIndex) & 1) === 1);
308 }
309
310 var mask = QRUtil.getMask(maskPattern, row, col - c);
311
312 if (mask) {
313 dark = !dark;
314 }
315
316 this.modules[row][col - c] = dark;
317 bitIndex--;
318
319 if (bitIndex === -1) {
320 byteIndex++;
321 bitIndex = 7;
322 }
323 }
324 }
325
326 row += inc;
327
328 if (row < 0 || this.moduleCount <= row) {
329 row -= inc;
330 inc = -inc;
331 break;
332 }
333 }
334 }
335
336 }
337
338};
339
340QRCode.PAD0 = 0xEC;
341QRCode.PAD1 = 0x11;
342
343QRCode.createData = function(typeNumber, errorCorrectLevel, dataList) {
344
345 var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel);
346
347 var buffer = new QRBitBuffer();
348
349 for (var i = 0; i < dataList.length; i++) {
350 var data = dataList[i];
351 buffer.put(data.mode, 4);
352 buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber) );
353 data.write(buffer);
354 }
355
356 // calc num max data.
357 var totalDataCount = 0;
358 for (var x = 0; x < rsBlocks.length; x++) {
359 totalDataCount += rsBlocks[x].dataCount;
360 }
361
362 if (buffer.getLengthInBits() > totalDataCount * 8) {
363 throw new Error("code length overflow. (" +
364 buffer.getLengthInBits() +
365 ">" +
366 totalDataCount * 8 +
367 ")");
368 }
369
370 // end code
371 if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {
372 buffer.put(0, 4);
373 }
374
375 // padding
376 while (buffer.getLengthInBits() % 8 !== 0) {
377 buffer.putBit(false);
378 }
379
380 // padding
381 while (true) {
382
383 if (buffer.getLengthInBits() >= totalDataCount * 8) {
384 break;
385 }
386 buffer.put(QRCode.PAD0, 8);
387
388 if (buffer.getLengthInBits() >= totalDataCount * 8) {
389 break;
390 }
391 buffer.put(QRCode.PAD1, 8);
392 }
393
394 return QRCode.createBytes(buffer, rsBlocks);
395};
396
397QRCode.createBytes = function(buffer, rsBlocks) {
398
399 var offset = 0;
400
401 var maxDcCount = 0;
402 var maxEcCount = 0;
403
404 var dcdata = new Array(rsBlocks.length);
405 var ecdata = new Array(rsBlocks.length);
406
407 for (var r = 0; r < rsBlocks.length; r++) {
408
409 var dcCount = rsBlocks[r].dataCount;
410 var ecCount = rsBlocks[r].totalCount - dcCount;
411
412 maxDcCount = Math.max(maxDcCount, dcCount);
413 maxEcCount = Math.max(maxEcCount, ecCount);
414
415 dcdata[r] = new Array(dcCount);
416
417 for (var i = 0; i < dcdata[r].length; i++) {
418 dcdata[r][i] = 0xff & buffer.buffer[i + offset];
419 }
420 offset += dcCount;
421
422 var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
423 var rawPoly = new QRPolynomial(dcdata[r], rsPoly.getLength() - 1);
424
425 var modPoly = rawPoly.mod(rsPoly);
426 ecdata[r] = new Array(rsPoly.getLength() - 1);
427 for (var x = 0; x < ecdata[r].length; x++) {
428 var modIndex = x + modPoly.getLength() - ecdata[r].length;
429 ecdata[r][x] = (modIndex >= 0)? modPoly.get(modIndex) : 0;
430 }
431
432 }
433
434 var totalCodeCount = 0;
435 for (var y = 0; y < rsBlocks.length; y++) {
436 totalCodeCount += rsBlocks[y].totalCount;
437 }
438
439 var data = new Array(totalCodeCount);
440 var index = 0;
441
442 for (var z = 0; z < maxDcCount; z++) {
443 for (var s = 0; s < rsBlocks.length; s++) {
444 if (z < dcdata[s].length) {
445 data[index++] = dcdata[s][z];
446 }
447 }
448 }
449
450 for (var xx = 0; xx < maxEcCount; xx++) {
451 for (var t = 0; t < rsBlocks.length; t++) {
452 if (xx < ecdata[t].length) {
453 data[index++] = ecdata[t][xx];
454 }
455 }
456 }
457
458 return data;
459
460};
461
462module.exports = QRCode;
463 