Code

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