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