Code

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