6a34f9671e65c5ce4ec98c921b8e1dd181513e59
1 import math, sys\r
2 import inkex\r
3 \r
4 #QRCode for Python\r
5 #\r
6 #Ported from the Javascript library by Sam Curren\r
7 #\r
8 #QRCode for Javascript\r
9 #http://d-project.googlecode.com/svn/trunk/misc/qrcode/js/qrcode.js\r
10 #\r
11 #Copyright (c) 2009 Kazuhiko Arase\r
12 #\r
13 #URL: http://www.d-project.com/\r
14 #\r
15 #Licensed under the MIT license:\r
16 # http://www.opensource.org/licenses/mit-license.php\r
17 #\r
18 # The word "QR Code" is registered trademark of\r
19 # DENSO WAVE INCORPORATED\r
20 # http://www.denso-wave.com/qrcode/faqpatent-e.html\r
21 \r
22 \r
23 class QR8bitByte:\r
24 \r
25 def __init__(self, data):\r
26 self.mode = QRMode.MODE_8BIT_BYTE\r
27 self.data = data\r
28 \r
29 def getLength(self):\r
30 return len(self.data)\r
31 \r
32 def write(self, buffer):\r
33 for i in range(len(self.data)):\r
34 #// not JIS ...\r
35 buffer.put(ord(self.data[i]), 8)\r
36 def __repr__(self):\r
37 return self.data\r
38 \r
39 class QRCode:\r
40 def __init__(self, typeNumber, errorCorrectLevel):\r
41 self.typeNumber = typeNumber\r
42 self.errorCorrectLevel = errorCorrectLevel\r
43 self.modules = None\r
44 self.moduleCount = 0\r
45 self.dataCache = None\r
46 self.dataList = []\r
47 def addData(self, data):\r
48 newData = QR8bitByte(data)\r
49 self.dataList.append(newData)\r
50 self.dataCache = None\r
51 def isDark(self, row, col):\r
52 if (row < 0 or self.moduleCount <= row or col < 0 or self.moduleCount <= col):\r
53 raise Exception("%s,%s - %s" % (row, col, self.moduleCount))\r
54 return self.modules[row][col]\r
55 def getModuleCount(self):\r
56 return self.moduleCount\r
57 def make(self):\r
58 self.makeImpl(False, self.getBestMaskPattern() )\r
59 def makeImpl(self, test, maskPattern):\r
60 \r
61 if self.typeNumber == 0:\r
62 self.typeNumber = QRCode.autoNumber(self.errorCorrectLevel, self.dataList)\r
63 self.moduleCount = self.typeNumber * 4 + 17\r
64 self.modules = [None for x in range(self.moduleCount)]\r
65 \r
66 for row in range(self.moduleCount):\r
67 \r
68 self.modules[row] = [None for x in range(self.moduleCount)]\r
69 \r
70 for col in range(self.moduleCount):\r
71 self.modules[row][col] = None #//(col + row) % 3;\r
72 \r
73 self.setupPositionProbePattern(0, 0)\r
74 self.setupPositionProbePattern(self.moduleCount - 7, 0)\r
75 self.setupPositionProbePattern(0, self.moduleCount - 7)\r
76 self.setupPositionAdjustPattern()\r
77 self.setupTimingPattern()\r
78 self.setupTypeInfo(test, maskPattern)\r
79 \r
80 if (self.typeNumber >= 7):\r
81 self.setupTypeNumber(test)\r
82 \r
83 if (self.dataCache == None):\r
84 self.dataCache = QRCode.createData(self.typeNumber, self.errorCorrectLevel, self.dataList)\r
85 self.mapData(self.dataCache, maskPattern)\r
86 \r
87 def setupPositionProbePattern(self, row, col):\r
88 \r
89 for r in range(-1, 8):\r
90 \r
91 if (row + r <= -1 or self.moduleCount <= row + r): continue\r
92 \r
93 for c in range(-1, 8):\r
94 \r
95 if (col + c <= -1 or self.moduleCount <= col + c): continue\r
96 \r
97 if ( (0 <= r and r <= 6 and (c == 0 or c == 6) )\r
98 or (0 <= c and c <= 6 and (r == 0 or r == 6) )\r
99 or (2 <= r and r <= 4 and 2 <= c and c <= 4) ):\r
100 self.modules[row + r][col + c] = True;\r
101 else:\r
102 self.modules[row + r][col + c] = False;\r
103 \r
104 def getBestMaskPattern(self):\r
105 \r
106 minLostPoint = 0\r
107 pattern = 0\r
108 \r
109 for i in range(8):\r
110 \r
111 self.makeImpl(True, i);\r
112 \r
113 lostPoint = QRUtil.getLostPoint(self);\r
114 \r
115 if (i == 0 or minLostPoint > lostPoint):\r
116 minLostPoint = lostPoint\r
117 pattern = i\r
118 \r
119 return pattern\r
120 \r
121 def makeSVG(self, grp, boxsize):\r
122 margin = 4\r
123 pixelsize = (self.getModuleCount() + 2*margin) * boxsize #self.getModuleCount() * boxsize\r
124 \r
125 # white background providing margin:\r
126 rect = inkex.etree.SubElement(grp, inkex.addNS('rect', 'svg'))\r
127 rect.set('x', '0')\r
128 rect.set('y', '0')\r
129 rect.set('width', str(pixelsize))\r
130 rect.set('height', str(pixelsize))\r
131 rect.set('style', 'fill:white;stroke:none')\r
132 \r
133 for r in range(self.getModuleCount()):\r
134 for c in range(self.getModuleCount()):\r
135 if (self.isDark(r, c) ):\r
136 x = (c + margin) * boxsize\r
137 y = (r + margin) * boxsize\r
138 rect = inkex.etree.SubElement(grp, inkex.addNS('rect', 'svg'))\r
139 rect.set('x', str(x))\r
140 rect.set('y', str(y))\r
141 rect.set('width', str(boxsize))\r
142 rect.set('height', str(boxsize))\r
143 rect.set('style', 'fill:black;stroke:none')\r
144 \r
145 def setupTimingPattern(self):\r
146 \r
147 for r in range(8, self.moduleCount - 8):\r
148 if (self.modules[r][6] != None):\r
149 continue\r
150 self.modules[r][6] = (r % 2 == 0)\r
151 \r
152 for c in range(8, self.moduleCount - 8):\r
153 if (self.modules[6][c] != None):\r
154 continue\r
155 self.modules[6][c] = (c % 2 == 0)\r
156 \r
157 def setupPositionAdjustPattern(self):\r
158 \r
159 pos = QRUtil.getPatternPosition(self.typeNumber)\r
160 \r
161 for i in range(len(pos)):\r
162 \r
163 for j in range(len(pos)):\r
164 \r
165 row = pos[i]\r
166 col = pos[j]\r
167 \r
168 if (self.modules[row][col] != None):\r
169 continue\r
170 \r
171 for r in range(-2, 3):\r
172 \r
173 for c in range(-2, 3):\r
174 \r
175 if (r == -2 or r == 2 or c == -2 or c == 2 or (r == 0 and c == 0) ):\r
176 self.modules[row + r][col + c] = True\r
177 else:\r
178 self.modules[row + r][col + c] = False\r
179 \r
180 def setupTypeNumber(self, test):\r
181 \r
182 bits = QRUtil.getBCHTypeNumber(self.typeNumber)\r
183 \r
184 for i in range(18):\r
185 mod = (not test and ( (bits >> i) & 1) == 1)\r
186 self.modules[i // 3][i % 3 + self.moduleCount - 8 - 3] = mod;\r
187 \r
188 for i in range(18):\r
189 mod = (not test and ( (bits >> i) & 1) == 1)\r
190 self.modules[i % 3 + self.moduleCount - 8 - 3][i // 3] = mod;\r
191 \r
192 def setupTypeInfo(self, test, maskPattern):\r
193 \r
194 data = (self.errorCorrectLevel << 3) | maskPattern\r
195 bits = QRUtil.getBCHTypeInfo(data)\r
196 \r
197 #// vertical\r
198 for i in range(15):\r
199 \r
200 mod = (not test and ( (bits >> i) & 1) == 1)\r
201 \r
202 if (i < 6):\r
203 self.modules[i][8] = mod\r
204 elif (i < 8):\r
205 self.modules[i + 1][8] = mod\r
206 else:\r
207 self.modules[self.moduleCount - 15 + i][8] = mod\r
208 \r
209 #// horizontal\r
210 for i in range(15):\r
211 \r
212 mod = (not test and ( (bits >> i) & 1) == 1);\r
213 \r
214 if (i < 8):\r
215 self.modules[8][self.moduleCount - i - 1] = mod\r
216 elif (i < 9):\r
217 self.modules[8][15 - i - 1 + 1] = mod\r
218 else:\r
219 self.modules[8][15 - i - 1] = mod\r
220 \r
221 #// fixed module\r
222 self.modules[self.moduleCount - 8][8] = (not test)\r
223 \r
224 def mapData(self, data, maskPattern):\r
225 \r
226 inc = -1\r
227 row = self.moduleCount - 1\r
228 bitIndex = 7\r
229 byteIndex = 0\r
230 \r
231 for col in range(self.moduleCount - 1, 0, -2):\r
232 \r
233 if (col == 6): col-=1\r
234 \r
235 while (True):\r
236 \r
237 for c in range(2):\r
238 \r
239 if (self.modules[row][col - c] == None):\r
240 \r
241 dark = False\r
242 \r
243 if (byteIndex < len(data)):\r
244 dark = ( ( (data[byteIndex] >> bitIndex) & 1) == 1)\r
245 \r
246 mask = QRUtil.getMask(maskPattern, row, col - c)\r
247 \r
248 if (mask):\r
249 dark = not dark\r
250 \r
251 self.modules[row][col - c] = dark\r
252 bitIndex-=1\r
253 \r
254 if (bitIndex == -1):\r
255 byteIndex+=1\r
256 bitIndex = 7\r
257 \r
258 row += inc\r
259 \r
260 if (row < 0 or self.moduleCount <= row):\r
261 row -= inc\r
262 inc = -inc\r
263 break\r
264 PAD0 = 0xEC\r
265 PAD1 = 0x11\r
266 \r
267 @staticmethod\r
268 def autoNumber(errorCorrectLevel, dataList):\r
269 \r
270 for tn in range (1, 40):\r
271 \r
272 rsBlocks = QRRSBlock.getRSBlocks(tn, errorCorrectLevel)\r
273 \r
274 buffer = QRBitBuffer();\r
275 \r
276 for i in range(len(dataList)):\r
277 data = dataList[i]\r
278 buffer.put(data.mode, 4)\r
279 buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, tn) )\r
280 data.write(buffer)\r
281 \r
282 #// calc num max data.\r
283 totalDataCount = 0;\r
284 for i in range(len(rsBlocks)):\r
285 totalDataCount += rsBlocks[i].dataCount\r
286 \r
287 if (buffer.getLengthInBits() <= totalDataCount * 8):\r
288 return tn\r
289 \r
290 inkex.errormsg("Even the largest size won't take this much data ("\r
291 + str(buffer.getLengthInBits())\r
292 + ">"\r
293 + str(totalDataCount * 8)\r
294 + ")")\r
295 sys.exit()\r
296 \r
297 \r
298 \r
299 @staticmethod\r
300 def createData(typeNumber, errorCorrectLevel, dataList):\r
301 \r
302 rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel)\r
303 \r
304 buffer = QRBitBuffer();\r
305 \r
306 for i in range(len(dataList)):\r
307 data = dataList[i]\r
308 buffer.put(data.mode, 4)\r
309 buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber) )\r
310 data.write(buffer)\r
311 \r
312 #// calc num max data.\r
313 totalDataCount = 0;\r
314 for i in range(len(rsBlocks)):\r
315 totalDataCount += rsBlocks[i].dataCount\r
316 \r
317 if (buffer.getLengthInBits() > totalDataCount * 8):\r
318 inkex.errormsg("Text is too long for this size ("\r
319 + str(buffer.getLengthInBits())\r
320 + ">"\r
321 + str(totalDataCount * 8)\r
322 + ")")\r
323 sys.exit()\r
324 \r
325 #// end code\r
326 if (buffer.getLengthInBits() + 4 <= totalDataCount * 8):\r
327 buffer.put(0, 4)\r
328 \r
329 #// padding\r
330 while (buffer.getLengthInBits() % 8 != 0):\r
331 buffer.putBit(False)\r
332 \r
333 #// padding\r
334 while (True):\r
335 \r
336 if (buffer.getLengthInBits() >= totalDataCount * 8):\r
337 break\r
338 buffer.put(QRCode.PAD0, 8)\r
339 \r
340 if (buffer.getLengthInBits() >= totalDataCount * 8):\r
341 break\r
342 buffer.put(QRCode.PAD1, 8)\r
343 \r
344 return QRCode.createBytes(buffer, rsBlocks)\r
345 \r
346 @staticmethod\r
347 def createBytes(buffer, rsBlocks):\r
348 \r
349 offset = 0\r
350 \r
351 maxDcCount = 0\r
352 maxEcCount = 0\r
353 \r
354 dcdata = [0 for x in range(len(rsBlocks))]\r
355 ecdata = [0 for x in range(len(rsBlocks))]\r
356 \r
357 for r in range(len(rsBlocks)):\r
358 \r
359 dcCount = rsBlocks[r].dataCount\r
360 ecCount = rsBlocks[r].totalCount - dcCount\r
361 \r
362 maxDcCount = max(maxDcCount, dcCount)\r
363 maxEcCount = max(maxEcCount, ecCount)\r
364 \r
365 dcdata[r] = [0 for x in range(dcCount)]\r
366 \r
367 for i in range(len(dcdata[r])):\r
368 dcdata[r][i] = 0xff & buffer.buffer[i + offset]\r
369 offset += dcCount\r
370 \r
371 rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount)\r
372 rawPoly = QRPolynomial(dcdata[r], rsPoly.getLength() - 1)\r
373 \r
374 modPoly = rawPoly.mod(rsPoly)\r
375 ecdata[r] = [0 for x in range(rsPoly.getLength()-1)]\r
376 for i in range(len(ecdata[r])):\r
377 modIndex = i + modPoly.getLength() - len(ecdata[r])\r
378 if (modIndex >= 0):\r
379 ecdata[r][i] = modPoly.get(modIndex)\r
380 else:\r
381 ecdata[r][i] = 0\r
382 \r
383 totalCodeCount = 0\r
384 for i in range(len(rsBlocks)):\r
385 totalCodeCount += rsBlocks[i].totalCount\r
386 \r
387 data = [None for x in range(totalCodeCount)]\r
388 index = 0\r
389 \r
390 for i in range(maxDcCount):\r
391 for r in range(len(rsBlocks)):\r
392 if (i < len(dcdata[r])):\r
393 data[index] = dcdata[r][i]\r
394 index+=1\r
395 \r
396 for i in range(maxEcCount):\r
397 for r in range(len(rsBlocks)):\r
398 if (i < len(ecdata[r])):\r
399 data[index] = ecdata[r][i]\r
400 index+=1\r
401 \r
402 return data\r
403 \r
404 \r
405 class QRMode:\r
406 MODE_NUMBER = 1 << 0\r
407 MODE_ALPHA_NUM = 1 << 1\r
408 MODE_8BIT_BYTE = 1 << 2\r
409 MODE_KANJI = 1 << 3\r
410 \r
411 class QRErrorCorrectLevel:\r
412 L = 1\r
413 M = 0\r
414 Q = 3\r
415 H = 2\r
416 \r
417 class QRMaskPattern:\r
418 PATTERN000 = 0\r
419 PATTERN001 = 1\r
420 PATTERN010 = 2\r
421 PATTERN011 = 3\r
422 PATTERN100 = 4\r
423 PATTERN101 = 5\r
424 PATTERN110 = 6\r
425 PATTERN111 = 7\r
426 \r
427 class QRUtil(object):\r
428 PATTERN_POSITION_TABLE = [\r
429 [],\r
430 [6, 18],\r
431 [6, 22],\r
432 [6, 26],\r
433 [6, 30],\r
434 [6, 34],\r
435 [6, 22, 38],\r
436 [6, 24, 42],\r
437 [6, 26, 46],\r
438 [6, 28, 50],\r
439 [6, 30, 54],\r
440 [6, 32, 58],\r
441 [6, 34, 62],\r
442 [6, 26, 46, 66],\r
443 [6, 26, 48, 70],\r
444 [6, 26, 50, 74],\r
445 [6, 30, 54, 78],\r
446 [6, 30, 56, 82],\r
447 [6, 30, 58, 86],\r
448 [6, 34, 62, 90],\r
449 [6, 28, 50, 72, 94],\r
450 [6, 26, 50, 74, 98],\r
451 [6, 30, 54, 78, 102],\r
452 [6, 28, 54, 80, 106],\r
453 [6, 32, 58, 84, 110],\r
454 [6, 30, 58, 86, 114],\r
455 [6, 34, 62, 90, 118],\r
456 [6, 26, 50, 74, 98, 122],\r
457 [6, 30, 54, 78, 102, 126],\r
458 [6, 26, 52, 78, 104, 130],\r
459 [6, 30, 56, 82, 108, 134],\r
460 [6, 34, 60, 86, 112, 138],\r
461 [6, 30, 58, 86, 114, 142],\r
462 [6, 34, 62, 90, 118, 146],\r
463 [6, 30, 54, 78, 102, 126, 150],\r
464 [6, 24, 50, 76, 102, 128, 154],\r
465 [6, 28, 54, 80, 106, 132, 158],\r
466 [6, 32, 58, 84, 110, 136, 162],\r
467 [6, 26, 54, 82, 110, 138, 166],\r
468 [6, 30, 58, 86, 114, 142, 170]\r
469 ]\r
470 \r
471 G15 = (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0)\r
472 G18 = (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0)\r
473 G15_MASK = (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1)\r
474 \r
475 @staticmethod\r
476 def getBCHTypeInfo(data):\r
477 d = data << 10;\r
478 while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0):\r
479 d ^= (QRUtil.G15 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) ) )\r
480 \r
481 return ( (data << 10) | d) ^ QRUtil.G15_MASK\r
482 @staticmethod\r
483 def getBCHTypeNumber(data):\r
484 d = data << 12;\r
485 while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0):\r
486 d ^= (QRUtil.G18 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) ) )\r
487 return (data << 12) | d\r
488 @staticmethod\r
489 def getBCHDigit(data):\r
490 digit = 0;\r
491 while (data != 0):\r
492 digit += 1\r
493 data >>= 1\r
494 return digit\r
495 @staticmethod\r
496 def getPatternPosition(typeNumber):\r
497 return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1]\r
498 @staticmethod\r
499 def getMask(maskPattern, i, j):\r
500 if maskPattern == QRMaskPattern.PATTERN000 : return (i + j) % 2 == 0\r
501 if maskPattern == QRMaskPattern.PATTERN001 : return i % 2 == 0\r
502 if maskPattern == QRMaskPattern.PATTERN010 : return j % 3 == 0\r
503 if maskPattern == QRMaskPattern.PATTERN011 : return (i + j) % 3 == 0\r
504 if maskPattern == QRMaskPattern.PATTERN100 : return (math.floor(i / 2) + math.floor(j / 3) ) % 2 == 0\r
505 if maskPattern == QRMaskPattern.PATTERN101 : return (i * j) % 2 + (i * j) % 3 == 0\r
506 if maskPattern == QRMaskPattern.PATTERN110 : return ( (i * j) % 2 + (i * j) % 3) % 2 == 0\r
507 if maskPattern == QRMaskPattern.PATTERN111 : return ( (i * j) % 3 + (i + j) % 2) % 2 == 0\r
508 raise Exception("bad maskPattern:" + maskPattern);\r
509 @staticmethod\r
510 def getErrorCorrectPolynomial(errorCorrectLength):\r
511 a = QRPolynomial([1], 0);\r
512 for i in range(errorCorrectLength):\r
513 a = a.multiply(QRPolynomial([1, QRMath.gexp(i)], 0) )\r
514 return a\r
515 @staticmethod\r
516 def getLengthInBits(mode, type):\r
517 \r
518 if 1 <= type and type < 10:\r
519 \r
520 #// 1 - 9\r
521 \r
522 if mode == QRMode.MODE_NUMBER : return 10\r
523 if mode == QRMode.MODE_ALPHA_NUM : return 9\r
524 if mode == QRMode.MODE_8BIT_BYTE : return 8\r
525 if mode == QRMode.MODE_KANJI : return 8\r
526 raise Exception("mode:" + mode)\r
527 \r
528 elif (type < 27):\r
529 \r
530 #// 10 - 26\r
531 \r
532 if mode == QRMode.MODE_NUMBER : return 12\r
533 if mode == QRMode.MODE_ALPHA_NUM : return 11\r
534 if mode == QRMode.MODE_8BIT_BYTE : return 16\r
535 if mode == QRMode.MODE_KANJI : return 10\r
536 raise Exception("mode:" + mode)\r
537 \r
538 elif (type < 41):\r
539 \r
540 #// 27 - 40\r
541 \r
542 if mode == QRMode.MODE_NUMBER : return 14\r
543 if mode == QRMode.MODE_ALPHA_NUM : return 13\r
544 if mode == QRMode.MODE_8BIT_BYTE : return 16\r
545 if mode == QRMode.MODE_KANJI : return 12\r
546 raise Exception("mode:" + mode)\r
547 \r
548 else:\r
549 raise Exception("type:" + type)\r
550 @staticmethod\r
551 def getLostPoint(qrCode):\r
552 \r
553 moduleCount = qrCode.getModuleCount();\r
554 \r
555 lostPoint = 0;\r
556 \r
557 #// LEVEL1\r
558 \r
559 for row in range(moduleCount):\r
560 \r
561 for col in range(moduleCount):\r
562 \r
563 sameCount = 0;\r
564 dark = qrCode.isDark(row, col);\r
565 \r
566 for r in range(-1, 2):\r
567 \r
568 if (row + r < 0 or moduleCount <= row + r):\r
569 continue\r
570 \r
571 for c in range(-1, 2):\r
572 \r
573 if (col + c < 0 or moduleCount <= col + c):\r
574 continue\r
575 if (r == 0 and c == 0):\r
576 continue\r
577 \r
578 if (dark == qrCode.isDark(row + r, col + c) ):\r
579 sameCount+=1\r
580 if (sameCount > 5):\r
581 lostPoint += (3 + sameCount - 5)\r
582 \r
583 #// LEVEL2\r
584 \r
585 for row in range(moduleCount - 1):\r
586 for col in range(moduleCount - 1):\r
587 count = 0;\r
588 if (qrCode.isDark(row, col ) ): count+=1\r
589 if (qrCode.isDark(row + 1, col ) ): count+=1\r
590 if (qrCode.isDark(row, col + 1) ): count+=1\r
591 if (qrCode.isDark(row + 1, col + 1) ): count+=1\r
592 if (count == 0 or count == 4):\r
593 lostPoint += 3\r
594 \r
595 #// LEVEL3\r
596 \r
597 for row in range(moduleCount):\r
598 for col in range(moduleCount - 6):\r
599 if (qrCode.isDark(row, col)\r
600 and not qrCode.isDark(row, col + 1)\r
601 and qrCode.isDark(row, col + 2)\r
602 and qrCode.isDark(row, col + 3)\r
603 and qrCode.isDark(row, col + 4)\r
604 and not qrCode.isDark(row, col + 5)\r
605 and qrCode.isDark(row, col + 6) ):\r
606 lostPoint += 40\r
607 \r
608 for col in range(moduleCount):\r
609 for row in range(moduleCount - 6):\r
610 if (qrCode.isDark(row, col)\r
611 and not qrCode.isDark(row + 1, col)\r
612 and qrCode.isDark(row + 2, col)\r
613 and qrCode.isDark(row + 3, col)\r
614 and qrCode.isDark(row + 4, col)\r
615 and not qrCode.isDark(row + 5, col)\r
616 and qrCode.isDark(row + 6, col) ):\r
617 lostPoint += 40\r
618 \r
619 #// LEVEL4\r
620 \r
621 darkCount = 0;\r
622 \r
623 for col in range(moduleCount):\r
624 for row in range(moduleCount):\r
625 if (qrCode.isDark(row, col) ):\r
626 darkCount+=1\r
627 \r
628 ratio = abs(100 * darkCount / moduleCount / moduleCount - 50) / 5\r
629 lostPoint += ratio * 10\r
630 \r
631 return lostPoint\r
632 \r
633 class QRMath:\r
634 \r
635 @staticmethod\r
636 def glog(n):\r
637 if (n < 1):\r
638 raise Exception("glog(" + n + ")")\r
639 return LOG_TABLE[n];\r
640 @staticmethod\r
641 def gexp(n):\r
642 while n < 0:\r
643 n += 255\r
644 while n >= 256:\r
645 n -= 255\r
646 return EXP_TABLE[n];\r
647 \r
648 EXP_TABLE = [x for x in range(256)]\r
649 \r
650 LOG_TABLE = [x for x in range(256)]\r
651 \r
652 for i in range(8):\r
653 EXP_TABLE[i] = 1 << i;\r
654 \r
655 for i in range(8, 256):\r
656 EXP_TABLE[i] = EXP_TABLE[i - 4] ^ EXP_TABLE[i - 5] ^ EXP_TABLE[i - 6] ^ EXP_TABLE[i - 8]\r
657 \r
658 for i in range(255):\r
659 LOG_TABLE[EXP_TABLE[i] ] = i\r
660 \r
661 class QRPolynomial:\r
662 \r
663 def __init__(self, num, shift):\r
664 \r
665 if (len(num) == 0):\r
666 raise Exception(num.length + "/" + shift)\r
667 \r
668 offset = 0\r
669 \r
670 while offset < len(num) and num[offset] == 0:\r
671 offset += 1\r
672 \r
673 self.num = [0 for x in range(len(num)-offset+shift)]\r
674 for i in range(len(num) - offset):\r
675 self.num[i] = num[i + offset]\r
676 \r
677 \r
678 def get(self, index):\r
679 return self.num[index]\r
680 def getLength(self):\r
681 return len(self.num)\r
682 def multiply(self, e):\r
683 num = [0 for x in range(self.getLength() + e.getLength() - 1)];\r
684 \r
685 for i in range(self.getLength()):\r
686 for j in range(e.getLength()):\r
687 num[i + j] ^= QRMath.gexp(QRMath.glog(self.get(i) ) + QRMath.glog(e.get(j) ) )\r
688 \r
689 return QRPolynomial(num, 0);\r
690 def mod(self, e):\r
691 \r
692 if (self.getLength() - e.getLength() < 0):\r
693 return self;\r
694 \r
695 ratio = QRMath.glog(self.get(0) ) - QRMath.glog(e.get(0) )\r
696 \r
697 num = [0 for x in range(self.getLength())]\r
698 \r
699 for i in range(self.getLength()):\r
700 num[i] = self.get(i);\r
701 \r
702 for i in range(e.getLength()):\r
703 num[i] ^= QRMath.gexp(QRMath.glog(e.get(i) ) + ratio)\r
704 \r
705 # recursive call\r
706 return QRPolynomial(num, 0).mod(e);\r
707 \r
708 class QRRSBlock:\r
709 \r
710 RS_BLOCK_TABLE = [\r
711 \r
712 #// L\r
713 #// M\r
714 #// Q\r
715 #// H\r
716 \r
717 #// 1\r
718 [1, 26, 19],\r
719 [1, 26, 16],\r
720 [1, 26, 13],\r
721 [1, 26, 9],\r
722 \r
723 #// 2\r
724 [1, 44, 34],\r
725 [1, 44, 28],\r
726 [1, 44, 22],\r
727 [1, 44, 16],\r
728 \r
729 #// 3\r
730 [1, 70, 55],\r
731 [1, 70, 44],\r
732 [2, 35, 17],\r
733 [2, 35, 13],\r
734 \r
735 #// 4\r
736 [1, 100, 80],\r
737 [2, 50, 32],\r
738 [2, 50, 24],\r
739 [4, 25, 9],\r
740 \r
741 #// 5\r
742 [1, 134, 108],\r
743 [2, 67, 43],\r
744 [2, 33, 15, 2, 34, 16],\r
745 [2, 33, 11, 2, 34, 12],\r
746 \r
747 #// 6\r
748 [2, 86, 68],\r
749 [4, 43, 27],\r
750 [4, 43, 19],\r
751 [4, 43, 15],\r
752 \r
753 #// 7\r
754 [2, 98, 78],\r
755 [4, 49, 31],\r
756 [2, 32, 14, 4, 33, 15],\r
757 [4, 39, 13, 1, 40, 14],\r
758 \r
759 #// 8\r
760 [2, 121, 97],\r
761 [2, 60, 38, 2, 61, 39],\r
762 [4, 40, 18, 2, 41, 19],\r
763 [4, 40, 14, 2, 41, 15],\r
764 \r
765 #// 9\r
766 [2, 146, 116],\r
767 [3, 58, 36, 2, 59, 37],\r
768 [4, 36, 16, 4, 37, 17],\r
769 [4, 36, 12, 4, 37, 13],\r
770 \r
771 #// 10\r
772 [2, 86, 68, 2, 87, 69],\r
773 [4, 69, 43, 1, 70, 44],\r
774 [6, 43, 19, 2, 44, 20],\r
775 [6, 43, 15, 2, 44, 16],\r
776 \r
777 # 11\r
778 [4, 101, 81],\r
779 [1, 80, 50, 4, 81, 51],\r
780 [4, 50, 22, 4, 51, 23],\r
781 [3, 36, 12, 8, 37, 13],\r
782 \r
783 # 12\r
784 [2, 116, 92, 2, 117, 93],\r
785 [6, 58, 36, 2, 59, 37],\r
786 [4, 46, 20, 6, 47, 21],\r
787 [7, 42, 14, 4, 43, 15],\r
788 \r
789 # 13\r
790 [4, 133, 107],\r
791 [8, 59, 37, 1, 60, 38],\r
792 [8, 44, 20, 4, 45, 21],\r
793 [12, 33, 11, 4, 34, 12],\r
794 \r
795 # 14\r
796 [3, 145, 115, 1, 146, 116],\r
797 [4, 64, 40, 5, 65, 41],\r
798 [11, 36, 16, 5, 37, 17],\r
799 [11, 36, 12, 5, 37, 13],\r
800 \r
801 # 15\r
802 [5, 109, 87, 1, 110, 88],\r
803 [5, 65, 41, 5, 66, 42],\r
804 [5, 54, 24, 7, 55, 25],\r
805 [11, 36, 12],\r
806 \r
807 # 16\r
808 [5, 122, 98, 1, 123, 99],\r
809 [7, 73, 45, 3, 74, 46],\r
810 [15, 43, 19, 2, 44, 20],\r
811 [3, 45, 15, 13, 46, 16],\r
812 \r
813 # 17\r
814 [1, 135, 107, 5, 136, 108],\r
815 [10, 74, 46, 1, 75, 47],\r
816 [1, 50, 22, 15, 51, 23],\r
817 [2, 42, 14, 17, 43, 15],\r
818 \r
819 # 18\r
820 [5, 150, 120, 1, 151, 121],\r
821 [9, 69, 43, 4, 70, 44],\r
822 [17, 50, 22, 1, 51, 23],\r
823 [2, 42, 14, 19, 43, 15],\r
824 \r
825 # 19\r
826 [3, 141, 113, 4, 142, 114],\r
827 [3, 70, 44, 11, 71, 45],\r
828 [17, 47, 21, 4, 48, 22],\r
829 [9, 39, 13, 16, 40, 14],\r
830 \r
831 # 20\r
832 [3, 135, 107, 5, 136, 108],\r
833 [3, 67, 41, 13, 68, 42],\r
834 [15, 54, 24, 5, 55, 25],\r
835 [15, 43, 15, 10, 44, 16],\r
836 \r
837 # 21\r
838 [4, 144, 116, 4, 145, 117],\r
839 [17, 68, 42],\r
840 [17, 50, 22, 6, 51, 23],\r
841 [19, 46, 16, 6, 47, 17],\r
842 \r
843 # 22\r
844 [2, 139, 111, 7, 140, 112],\r
845 [17, 74, 46],\r
846 [7, 54, 24, 16, 55, 25],\r
847 [34, 37, 13],\r
848 \r
849 # 23\r
850 [4, 151, 121, 5, 152, 122],\r
851 [4, 75, 47, 14, 76, 48],\r
852 [11, 54, 24, 14, 55, 25],\r
853 [16, 45, 15, 14, 46, 16],\r
854 \r
855 # 24\r
856 [6, 147, 117, 4, 148, 118],\r
857 [6, 73, 45, 14, 74, 46],\r
858 [11, 54, 24, 16, 55, 25],\r
859 [30, 46, 16, 2, 47, 17],\r
860 \r
861 # 25\r
862 [8, 132, 106, 4, 133, 107],\r
863 [8, 75, 47, 13, 76, 48],\r
864 [7, 54, 24, 22, 55, 25],\r
865 [22, 45, 15, 13, 46, 16],\r
866 \r
867 # 26\r
868 [10, 142, 114, 2, 143, 115],\r
869 [19, 74, 46, 4, 75, 47],\r
870 [28, 50, 22, 6, 51, 23],\r
871 [33, 46, 16, 4, 47, 17],\r
872 \r
873 # 27\r
874 [8, 152, 122, 4, 153, 123],\r
875 [22, 73, 45, 3, 74, 46],\r
876 [8, 53, 23, 26, 54, 24],\r
877 [12, 45, 15, 28, 46, 16],\r
878 \r
879 # 28\r
880 [3, 147, 117, 10, 148, 118],\r
881 [3, 73, 45, 23, 74, 46],\r
882 [4, 54, 24, 31, 55, 25],\r
883 [11, 45, 15, 31, 46, 16],\r
884 \r
885 # 29\r
886 [7, 146, 116, 7, 147, 117],\r
887 [21, 73, 45, 7, 74, 46],\r
888 [1, 53, 23, 37, 54, 24],\r
889 [19, 45, 15, 26, 46, 16],\r
890 \r
891 # 30\r
892 [5, 145, 115, 10, 146, 116],\r
893 [19, 75, 47, 10, 76, 48],\r
894 [15, 54, 24, 25, 55, 25],\r
895 [23, 45, 15, 25, 46, 16],\r
896 \r
897 # 31\r
898 [13, 145, 115, 3, 146, 116],\r
899 [2, 74, 46, 29, 75, 47],\r
900 [42, 54, 24, 1, 55, 25],\r
901 [23, 45, 15, 28, 46, 16],\r
902 \r
903 # 32\r
904 [17, 145, 115],\r
905 [10, 74, 46, 23, 75, 47],\r
906 [10, 54, 24, 35, 55, 25],\r
907 [19, 45, 15, 35, 46, 16],\r
908 \r
909 # 33\r
910 [17, 145, 115, 1, 146, 116],\r
911 [14, 74, 46, 21, 75, 47],\r
912 [29, 54, 24, 19, 55, 25],\r
913 [11, 45, 15, 46, 46, 16],\r
914 \r
915 # 34\r
916 [13, 145, 115, 6, 146, 116],\r
917 [14, 74, 46, 23, 75, 47],\r
918 [44, 54, 24, 7, 55, 25],\r
919 [59, 46, 16, 1, 47, 17],\r
920 \r
921 # 35\r
922 [12, 151, 121, 7, 152, 122],\r
923 [12, 75, 47, 26, 76, 48],\r
924 [39, 54, 24, 14, 55, 25],\r
925 [22, 45, 15, 41, 46, 16],\r
926 \r
927 # 36\r
928 [6, 151, 121, 14, 152, 122],\r
929 [6, 75, 47, 34, 76, 48],\r
930 [46, 54, 24, 10, 55, 25],\r
931 [2, 45, 15, 64, 46, 16],\r
932 \r
933 # 37\r
934 [17, 152, 122, 4, 153, 123],\r
935 [29, 74, 46, 14, 75, 47],\r
936 [49, 54, 24, 10, 55, 25],\r
937 [24, 45, 15, 46, 46, 16],\r
938 \r
939 # 38\r
940 [4, 152, 122, 18, 153, 123],\r
941 [13, 74, 46, 32, 75, 47],\r
942 [48, 54, 24, 14, 55, 25],\r
943 [42, 45, 15, 32, 46, 16],\r
944 \r
945 # 39\r
946 [20, 147, 117, 4, 148, 118],\r
947 [40, 75, 47, 7, 76, 48],\r
948 [43, 54, 24, 22, 55, 25],\r
949 [10, 45, 15, 67, 46, 16],\r
950 \r
951 # 40\r
952 [19, 148, 118, 6, 149, 119],\r
953 [18, 75, 47, 31, 76, 48],\r
954 [34, 54, 24, 34, 55, 25],\r
955 [20, 45, 15, 61, 46, 16]\r
956 \r
957 ]\r
958 \r
959 def __init__(self, totalCount, dataCount):\r
960 self.totalCount = totalCount\r
961 self.dataCount = dataCount\r
962 \r
963 @staticmethod\r
964 def getRSBlocks(typeNumber, errorCorrectLevel):\r
965 rsBlock = QRRSBlock.getRsBlockTable(typeNumber, errorCorrectLevel);\r
966 if rsBlock == None:\r
967 raise Exception("bad rs block @ typeNumber:" + typeNumber + "/errorCorrectLevel:" + errorCorrectLevel)\r
968 \r
969 length = len(rsBlock) / 3\r
970 \r
971 list = []\r
972 \r
973 for i in range(length):\r
974 \r
975 count = rsBlock[i * 3 + 0]\r
976 totalCount = rsBlock[i * 3 + 1]\r
977 dataCount = rsBlock[i * 3 + 2]\r
978 \r
979 for j in range(count):\r
980 list.append(QRRSBlock(totalCount, dataCount))\r
981 \r
982 return list;\r
983 \r
984 @staticmethod\r
985 def getRsBlockTable(typeNumber, errorCorrectLevel):\r
986 if errorCorrectLevel == QRErrorCorrectLevel.L:\r
987 return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];\r
988 elif errorCorrectLevel == QRErrorCorrectLevel.M:\r
989 return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];\r
990 elif errorCorrectLevel == QRErrorCorrectLevel.Q:\r
991 return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];\r
992 elif errorCorrectLevel == QRErrorCorrectLevel.H:\r
993 return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];\r
994 else:\r
995 return None;\r
996 \r
997 class QRBitBuffer:\r
998 def __init__(self):\r
999 self.buffer = []\r
1000 self.length = 0\r
1001 def __repr__(self):\r
1002 return ".".join([str(n) for n in self.buffer])\r
1003 def get(self, index):\r
1004 bufIndex = math.floor(index / 8)\r
1005 val = ( (self.buffer[bufIndex] >> (7 - index % 8) ) & 1) == 1\r
1006 print "get ", val\r
1007 return ( (self.buffer[bufIndex] >> (7 - index % 8) ) & 1) == 1\r
1008 def put(self, num, length):\r
1009 for i in range(length):\r
1010 self.putBit( ( (num >> (length - i - 1) ) & 1) == 1)\r
1011 def getLengthInBits(self):\r
1012 return self.length\r
1013 def putBit(self, bit):\r
1014 bufIndex = self.length // 8\r
1015 if len(self.buffer) <= bufIndex:\r
1016 self.buffer.append(0)\r
1017 if bit:\r
1018 self.buffer[bufIndex] |= (0x80 >> (self.length % 8) )\r
1019 self.length+=1\r
1020 \r
1021 class QRCodeInkscape(inkex.Effect):\r
1022 def __init__(self):\r
1023 inkex.Effect.__init__(self)\r
1024 \r
1025 #PARSE OPTIONS\r
1026 self.OptionParser.add_option("--text",\r
1027 action="store", type="string",\r
1028 dest="TEXT", default='www.inkscape.org')\r
1029 self.OptionParser.add_option("--typenumber",\r
1030 action="store", type="string",\r
1031 dest="TYPENUMBER", default="0")\r
1032 self.OptionParser.add_option("--correctionlevel",\r
1033 action="store", type="string",\r
1034 dest="CORRECTIONLEVEL", default="0")\r
1035 self.OptionParser.add_option("--modulesize",\r
1036 action="store", type="float",\r
1037 dest="MODULESIZE", default=10)\r
1038 \r
1039 def effect(self):\r
1040 \r
1041 so = self.options\r
1042 \r
1043 if so.TEXT == '': #abort if converting blank text\r
1044 inkex.errormsg(_('Please enter an input text'))\r
1045 else:\r
1046 \r
1047 #INKSCAPE GROUP TO CONTAIN EVERYTHING\r
1048 \r
1049 centre = self.view_center #Put in in the centre of the current view\r
1050 grp_transform = 'translate' + str( centre )\r
1051 grp_name = 'QRCode'\r
1052 grp_attribs = {inkex.addNS('label','inkscape'):grp_name,\r
1053 'transform':grp_transform }\r
1054 grp = inkex.etree.SubElement(self.current_layer, 'g', grp_attribs) #the group to put everything in\r
1055 \r
1056 #GENERATE THE QRCODE\r
1057 qr = QRCode(int(so.TYPENUMBER), int(so.CORRECTIONLEVEL))\r
1058 qr.addData(so.TEXT)\r
1059 qr.make()\r
1060 qr.makeSVG(grp, so.MODULESIZE)\r
1061 \r
1062 if __name__ == '__main__':\r
1063 e = QRCodeInkscape()\r
1064 e.affect()\r
1065 \r
1066 # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99\r