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