Code

add QR Code rendering extension
[inkscape.git] / share / extensions / render_barcode_qrcode.py
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