Code

add copyright
[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 # 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 = 'QRCode'\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