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