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')
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):
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()
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)
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)
1041 def effect(self):
1043 so = self.options
1045 if so.TEXT == '': #abort if converting blank text
1046 inkex.errormsg(_('Please enter an input text'))
1047 else:
1049 #INKSCAPE GROUP TO CONTAIN EVERYTHING
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
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)
1064 if __name__ == '__main__':
1065 e = QRCodeInkscape()
1066 e.affect()
1068 # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99