1#
2# QR Code Generator for Python
3#
4# Copyright (c) 2012 Kazuhiko Arase
5#
6# URL: http://www.d-project.com/
7#
8# Licensed under the MIT license:
9#    http://www.opensource.org/licenses/mit-license.php
10#
11# The word 'QR Code' is registered trademark of
12# DENSO WAVE INCORPORATED
13#    http://www.denso-wave.com/qrcode/faqpatent-e.html
14#
15
16"""QR Code Generator for Python
17
18    from qrcode import QRCode, ErrorCorrectLevel
19
20    # generate with explicit type number
21    qr = QRCode()
22    qr.setTypeNumber(4)
23    qr.setErrorCorrectLevel(ErrorCorrectLevel.M)
24    qr.addData('here comes qr!')
25    qr.make()
26
27    # generate with auto type number
28    # qr = QRCode.getMinimumQRCode('here comes qr!', ErrorCorrectLevel.M)
29
30    # create an image
31    for r in range(qr.getModuleCount() ):
32        for c in range(qr.getModuleCount() ):
33            color = black if qr.isDark(r, c) else white
34            # set pixel ...
35
36"""
37
38class QRCode:
39
40    PAD0 = 0xEC
41    PAD1 = 0x11
42
43    def __init__(self):
44        self.typeNumber = 1
45        self.errorCorrectLevel = ErrorCorrectLevel.H
46        self.qrDataList = []
47        self.modules = []
48        self.moduleCount = 0
49
50    def getTypeNumber(self):
51        return self.typeNumber
52
53    def setTypeNumber(self, typeNumber):
54        self.typeNumber = typeNumber
55
56    def getErrorCorrectLevel(self):
57        return self.errorCorrectLevel
58
59    def setErrorCorrectLevel(self, errorCorrectLevel):
60        self.errorCorrectLevel = errorCorrectLevel
61
62    def clearData(self):
63        self.qrDataList = []
64
65    def addData(self, data):
66        self.qrDataList.append(QR8BitByte(data) )
67
68    def getDataCount(self):
69        return len(self.qrDataList)
70
71    def getData(self, index):
72        return self.qrDataList[index]
73
74    def isDark(self, row, col):
75        return (self.modules[row][col] if self.modules[row][col] != None
76            else False)
77
78    def getModuleCount(self):
79        return self.moduleCount
80
81    def make(self):
82        self._make(False, self._getBestMaskPattern() )
83
84    def _getBestMaskPattern(self):
85        minLostPoint = 0
86        pattern = 0
87        for i in range(8):
88            self._make(True, i)
89            lostPoint = QRUtil.getLostPoint(self)
90            if i == 0 or minLostPoint > lostPoint:
91                minLostPoint = lostPoint
92                pattern = i
93        return pattern
94
95    def _make(self, test, maskPattern):
96
97        self.moduleCount = self.typeNumber * 4 + 17
98        self.modules = [[None] * self.moduleCount
99            for i in range(self.moduleCount)]
100
101        self._setupPositionProbePattern(0, 0)
102        self._setupPositionProbePattern(self.moduleCount - 7, 0)
103        self._setupPositionProbePattern(0, self.moduleCount - 7)
104
105        self._setupPositionAdjustPattern()
106        self._setupTimingPattern()
107
108        self._setupTypeInfo(test, maskPattern)
109
110        if self.typeNumber >= 7:
111            self._setupTypeNumber(test)
112
113        data = QRCode._createData(
114            self.typeNumber,
115            self.errorCorrectLevel,
116            self.qrDataList)
117
118        self._mapData(data, maskPattern)
119
120    def _mapData(self, data, maskPattern):
121
122        rows = list(range(self.moduleCount) )
123        cols = [col - 1 if col <= 6 else col
124            for col in range(self.moduleCount - 1, 0, -2)]
125        maskFunc = QRUtil.getMaskFunction(maskPattern)
126
127        byteIndex = 0
128        bitIndex = 7
129
130        for col in cols:
131            rows.reverse()
132            for row in rows:
133                for c in range(2):
134                    if self.modules[row][col - c] is None:
135
136                        dark = False
137                        if byteIndex < len(data):
138                            dark = ( (data[byteIndex] >> bitIndex) & 1) == 1
139                        if maskFunc(row, col - c):
140                            dark = not dark
141                        self.modules[row][col - c] = dark
142
143                        bitIndex -= 1
144                        if bitIndex == -1:
145                            byteIndex += 1
146                            bitIndex = 7
147
148    def _setupPositionAdjustPattern(self):
149        pos = QRUtil.getPatternPosition(self.typeNumber)
150        for row in pos:
151            for col in pos:
152                if self.modules[row][col] != None:
153                    continue
154                for r in range(-2, 3):
155                    for c in range(-2, 3):
156                        self.modules[row + r][col + c] = (
157                            r == -2 or r == 2 or c == -2 or c == 2
158                            or (r == 0 and c == 0) )
159
160    def _setupPositionProbePattern(self, row, col):
161        for r in range(-1, 8):
162            for c in range(-1, 8):
163                if (row + r <= -1 or self.moduleCount <= row + r
164                        or col + c <= -1 or self.moduleCount <= col + c):
165                    continue
166                self.modules[row + r][col + c] = (
167                    (0 <= r and r <= 6 and (c == 0 or c == 6) )
168                    or (0 <= c and c <= 6 and (r == 0 or r == 6) )
169                    or (2 <= r and r <= 4 and 2 <= c and c <= 4) )
170
171    def _setupTimingPattern(self):
172        for r in range(8, self.moduleCount - 8):
173            if self.modules[r][6] != None:
174                continue
175            self.modules[r][6] = r % 2 == 0
176        for c in range(8, self.moduleCount - 8):
177            if self.modules[6][c] != None:
178                continue
179            self.modules[6][c] = c % 2 == 0
180
181    def _setupTypeNumber(self, test):
182        bits = QRUtil.getBCHTypeNumber(self.typeNumber)
183        for i in range(18):
184            self.modules[i // 3][i % 3 + self.moduleCount - 8 - 3] = (
185                not test and ( (bits >> i) & 1) == 1)
186        for i in range(18):
187            self.modules[i % 3 + self.moduleCount - 8 - 3][i // 3] = (
188                not test and ( (bits >> i) & 1) == 1)
189
190    def _setupTypeInfo(self, test, maskPattern):
191
192        data = (self.errorCorrectLevel << 3) | maskPattern
193        bits = QRUtil.getBCHTypeInfo(data)
194
195        # vertical
196        for i in range(15):
197            mod = not test and ( (bits >> i) & 1) == 1
198            if i < 6:
199                self.modules[i][8] = mod
200            elif i < 8:
201                self.modules[i + 1][8] = mod
202            else:
203                self.modules[self.moduleCount - 15 + i][8] = mod
204
205        # horizontal
206        for i in range(15):
207            mod = not test and ( (bits >> i) & 1) == 1
208            if i < 8:
209                self.modules[8][self.moduleCount - i - 1] = mod
210            elif i < 9:
211                self.modules[8][15 - i - 1 + 1] = mod
212            else:
213                self.modules[8][15 - i - 1] = mod
214
215        # fixed
216        self.modules[self.moduleCount - 8][8] = not test
217
218    @staticmethod
219    def _createData(typeNumber, errorCorrectLevel, dataArray):
220
221        rsBlocks = RSBlock.getRSBlocks(typeNumber, errorCorrectLevel)
222
223        buffer = BitBuffer()
224
225        for data in dataArray:
226            buffer.put(data.getMode(), 4)
227            buffer.put(data.getLength(), data.getLengthInBits(typeNumber) )
228            data.write(buffer)
229
230        totalDataCount = sum(rsBlock.getDataCount()
231                              for rsBlock in rsBlocks)
232
233        if buffer.getLengthInBits() > totalDataCount * 8:
234            raise Exception('code length overflow. (%s > %s)' %
235                    (buffer.getLengthInBits(), totalDataCount * 8) )
236
237        # end code
238        if buffer.getLengthInBits() + 4 <= totalDataCount * 8:
239            buffer.put(0, 4)
240
241        # padding
242        while buffer.getLengthInBits() % 8 != 0:
243            buffer.put(False)
244
245        # padding
246        while True:
247            if buffer.getLengthInBits() >= totalDataCount * 8:
248                break
249            buffer.put(QRCode.PAD0, 8)
250            if buffer.getLengthInBits() >= totalDataCount * 8:
251                break
252            buffer.put(QRCode.PAD1, 8)
253
254        return QRCode._createBytes(buffer, rsBlocks)
255
256    @staticmethod
257    def _createBytes(buffer, rsBlocks):
258
259        offset = 0
260
261        maxDcCount = 0
262        maxEcCount = 0
263
264        dcdata = [None] * len(rsBlocks)
265        ecdata = [None] * len(rsBlocks)
266
267        for r in range(len(rsBlocks) ):
268
269            dcCount = rsBlocks[r].getDataCount()
270            ecCount = rsBlocks[r].getTotalCount() - dcCount
271
272            maxDcCount = max(maxDcCount, dcCount)
273            maxEcCount = max(maxEcCount, ecCount)
274
275            dcdata[r] = [0] * dcCount
276            for i in range(len(dcdata[r] ) ):
277                dcdata[r][i] = 0xff & buffer.getBuffer()[i + offset]
278            offset += dcCount
279
280            rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount)
281            rawPoly = Polynomial(dcdata[r], rsPoly.getLength() - 1)
282
283            modPoly = rawPoly.mod(rsPoly)
284            ecdata[r] = [0] * (rsPoly.getLength() - 1)
285            for i in range(len(ecdata[r]) ):
286                modIndex = i + modPoly.getLength() - len(ecdata[r])
287                ecdata[r][i] = modPoly.get(modIndex) if modIndex >= 0 else 0
288
289        totalCodeCount = sum(rsBlock.getTotalCount()
290                              for rsBlock in rsBlocks)
291
292        data = [0] * totalCodeCount
293
294        index = 0
295
296        for i in range(maxDcCount):
297            for r in range(len(rsBlocks) ):
298                if i < len(dcdata[r] ):
299                    data[index] = dcdata[r][i]
300                    index += 1
301
302        for i in range(maxEcCount):
303            for r in range(len(rsBlocks) ):
304                if i < len(ecdata[r] ):
305                    data[index] = ecdata[r][i]
306                    index += 1
307
308        return data
309
310    @staticmethod
311    def getMinimumQRCode(data, errorCorrectLevel):
312        mode = Mode.MODE_8BIT_BYTE # fixed to 8bit byte
313        qr = QRCode()
314        qr.setErrorCorrectLevel(errorCorrectLevel)
315        qr.addData(data)
316        length = qr.getData(0).getLength()
317        for typeNumber in range(1, 11):
318            if length <= QRUtil.getMaxLength(
319                    typeNumber, mode, errorCorrectLevel):
320                qr.setTypeNumber(typeNumber)
321                break
322        qr.make()
323        return qr
324
325class Mode:
326    MODE_NUMBER    = 1 << 0
327    MODE_ALPHA_NUM = 1 << 1
328    MODE_8BIT_BYTE = 1 << 2
329    MODE_KANJI     = 1 << 3
330
331class ErrorCorrectLevel:
332    L = 1 # 7%
333    M = 0 # 15%
334    Q = 3 # 25%
335    H = 2 # 30%
336
337class MaskPattern:
338    PATTERN000 = 0
339    PATTERN001 = 1
340    PATTERN010 = 2
341    PATTERN011 = 3
342    PATTERN100 = 4
343    PATTERN101 = 5
344    PATTERN110 = 6
345    PATTERN111 = 7
346
347class QRUtil:
348
349    @staticmethod
350    def getPatternPosition(typeNumber):
351        return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1]
352
353    PATTERN_POSITION_TABLE = [
354        [],
355        [6, 18],
356        [6, 22],
357        [6, 26],
358        [6, 30],
359        [6, 34],
360        [6, 22, 38],
361        [6, 24, 42],
362        [6, 26, 46],
363        [6, 28, 50],
364        [6, 30, 54],
365        [6, 32, 58],
366        [6, 34, 62],
367        [6, 26, 46, 66],
368        [6, 26, 48, 70],
369        [6, 26, 50, 74],
370        [6, 30, 54, 78],
371        [6, 30, 56, 82],
372        [6, 30, 58, 86],
373        [6, 34, 62, 90],
374        [6, 28, 50, 72, 94],
375        [6, 26, 50, 74, 98],
376        [6, 30, 54, 78, 102],
377        [6, 28, 54, 80, 106],
378        [6, 32, 58, 84, 110],
379        [6, 30, 58, 86, 114],
380        [6, 34, 62, 90, 118],
381        [6, 26, 50, 74, 98, 122],
382        [6, 30, 54, 78, 102, 126],
383        [6, 26, 52, 78, 104, 130],
384        [6, 30, 56, 82, 108, 134],
385        [6, 34, 60, 86, 112, 138],
386        [6, 30, 58, 86, 114, 142],
387        [6, 34, 62, 90, 118, 146],
388        [6, 30, 54, 78, 102, 126, 150],
389        [6, 24, 50, 76, 102, 128, 154],
390        [6, 28, 54, 80, 106, 132, 158],
391        [6, 32, 58, 84, 110, 136, 162],
392        [6, 26, 54, 82, 110, 138, 166],
393        [6, 30, 58, 86, 114, 142, 170]
394        ]
395
396    MAX_LENGTH = [
397        [ [41,  25,  17,  10],  [34,  20,  14,  8],   [27,  16,  11,  7],  [17,  10,  7,   4] ],
398        [ [77,  47,  32,  20],  [63,  38,  26,  16],  [48,  29,  20,  12], [34,  20,  14,  8] ],
399        [ [127, 77,  53,  32],  [101, 61,  42,  26],  [77,  47,  32,  20], [58,  35,  24,  15] ],
400        [ [187, 114, 78,  48],  [149, 90,  62,  38],  [111, 67,  46,  28], [82,  50,  34,  21] ],
401        [ [255, 154, 106, 65],  [202, 122, 84,  52],  [144, 87,  60,  37], [106, 64,  44,  27] ],
402        [ [322, 195, 134, 82],  [255, 154, 106, 65],  [178, 108, 74,  45], [139, 84,  58,  36] ],
403        [ [370, 224, 154, 95],  [293, 178, 122, 75],  [207, 125, 86,  53], [154, 93,  64,  39] ],
404        [ [461, 279, 192, 118], [365, 221, 152, 93],  [259, 157, 108, 66], [202, 122, 84,  52] ],
405        [ [552, 335, 230, 141], [432, 262, 180, 111], [312, 189, 130, 80], [235, 143, 98,  60] ],
406        [ [652, 395, 271, 167], [513, 311, 213, 131], [364, 221, 151, 93], [288, 174, 119, 74] ]
407        ]
408
409    @staticmethod
410    def getMaxLength(typeNumber, mode, errorCorrectLevel):
411        t = typeNumber - 1
412        e = {
413            ErrorCorrectLevel.L: 0,
414            ErrorCorrectLevel.M: 1,
415            ErrorCorrectLevel.Q: 2,
416            ErrorCorrectLevel.H: 3
417            }[errorCorrectLevel]
418        m = {
419            Mode.MODE_NUMBER: 0,
420            Mode.MODE_ALPHA_NUM: 1,
421            Mode.MODE_8BIT_BYTE: 2,
422            Mode.MODE_KANJI: 3
423            }[mode]
424        return QRUtil.MAX_LENGTH[t][e][m]
425
426    @staticmethod
427    def getErrorCorrectPolynomial(errorCorrectLength):
428        a = Polynomial([1])
429        for i in range(errorCorrectLength):
430            a = a.multiply(Polynomial([1, QRMath.gexp(i)]) )
431        return a
432
433    @staticmethod
434    def getMaskFunction(maskPattern):
435        return {
436            MaskPattern.PATTERN000:
437                lambda i, j: (i + j) % 2 == 0,
438            MaskPattern.PATTERN001:
439                lambda i, j: i % 2 == 0,
440            MaskPattern.PATTERN010:
441                lambda i, j: j % 3 == 0,
442            MaskPattern.PATTERN011:
443                lambda i, j: (i + j) % 3 == 0,
444            MaskPattern.PATTERN100:
445                lambda i, j: (i // 2 + j // 3) % 2 == 0,
446            MaskPattern.PATTERN101:
447                lambda i, j: (i * j) % 2 + (i * j) % 3 == 0,
448            MaskPattern.PATTERN110:
449                lambda i, j: ( (i * j) % 2 + (i * j) % 3) % 2 == 0,
450            MaskPattern.PATTERN111:
451                lambda i, j: ( (i * j) % 3 + (i + j) % 2) % 2 == 0
452            }[maskPattern]
453
454    @staticmethod
455    def getLostPoint(qrcode):
456
457        moduleCount = qrcode.getModuleCount()
458        lostPoint = 0
459
460        # LEVEL1
461        for row in range(moduleCount):
462            for col in range(moduleCount):
463                sameCount = 0
464                dark = qrcode.isDark(row, col)
465                for r in range(-1, 2):
466                    if row + r < 0 or moduleCount <= row + r:
467                        continue
468                    for c in range(-1, 2):
469                        if col + c < 0 or moduleCount <= col + c:
470                            continue
471                        if r == 0 and c == 0:
472                            continue
473                        if dark == qrcode.isDark(row + r, col + c):
474                            sameCount += 1
475                if sameCount > 5:
476                    lostPoint += (3 + sameCount - 5)
477
478        # LEVEL2
479        for row in range(moduleCount - 1):
480            for col in range(moduleCount - 1):
481                count = 0
482                if qrcode.isDark(row, col):
483                    count += 1
484                if qrcode.isDark(row + 1, col):
485                    count += 1
486                if qrcode.isDark(row, col + 1):
487                    count += 1
488                if qrcode.isDark(row + 1, col + 1):
489                    count += 1
490                if count == 0 or count == 4:
491                    lostPoint += 3
492
493        # LEVEL3
494        for row in range(moduleCount):
495            for col in range(moduleCount - 6):
496                if (qrcode.isDark(row, col)
497                        and not qrcode.isDark(row, col + 1)
498                        and     qrcode.isDark(row, col + 2)
499                        and     qrcode.isDark(row, col + 3)
500                        and     qrcode.isDark(row, col + 4)
501                        and not qrcode.isDark(row, col + 5)
502                        and     qrcode.isDark(row, col + 6) ):
503                    lostPoint += 40
504
505        for col in range(moduleCount):
506            for row in range(moduleCount - 6):
507                if (qrcode.isDark(row, col)
508                        and not qrcode.isDark(row + 1, col)
509                        and     qrcode.isDark(row + 2, col)
510                        and     qrcode.isDark(row + 3, col)
511                        and     qrcode.isDark(row + 4, col)
512                        and not qrcode.isDark(row + 5, col)
513                        and     qrcode.isDark(row + 6, col) ):
514                    lostPoint += 40
515
516        # LEVEL4
517        darkCount = 0
518        for col in range(moduleCount):
519            for row in range(moduleCount):
520                if qrcode.isDark(row, col):
521                    darkCount += 1
522
523        ratio = abs(100 * darkCount // moduleCount // moduleCount - 50) // 5
524        lostPoint += ratio * 10
525
526        return lostPoint
527
528    G15 = ( (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) |
529            (1 << 2) | (1 << 1) | (1 << 0) )
530    G18 = ( (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) |
531            (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0) )
532    G15_MASK = (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1)
533
534    @staticmethod
535    def getBCHTypeInfo(data):
536        d = data << 10
537        while QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0:
538            d ^= (QRUtil.G15 << (QRUtil.getBCHDigit(d) -
539                                 QRUtil.getBCHDigit(QRUtil.G15) ) )
540        return ( (data << 10) | d) ^ QRUtil.G15_MASK
541
542    @staticmethod
543    def getBCHTypeNumber(data):
544        d = data << 12
545        while QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0:
546            d ^= (QRUtil.G18 << (QRUtil.getBCHDigit(d) -
547                                 QRUtil.getBCHDigit(QRUtil.G18) ) )
548        return (data << 12) | d
549
550    @staticmethod
551    def getBCHDigit(data):
552        digit = 0
553        while data != 0:
554            digit += 1
555            data >>= 1
556        return digit
557
558    @staticmethod
559    def stringToBytes(s):
560        return [ord(c) & 0xff for c in s]
561
562class QR8BitByte:
563
564    def __init__(self, data):
565        self.mode = Mode.MODE_8BIT_BYTE
566        self.data = data
567
568    def getMode(self):
569        return self.mode
570
571    def getData(self):
572        return self.data
573
574    '''
575    def write(self, buffer): raise Exception('not implemented.')
576    def getLength(self): raise Exception('not implemented.')
577    '''
578
579    def write(self, buffer):
580        data = QRUtil.stringToBytes(self.getData() )
581        for d in data:
582            buffer.put(d, 8)
583
584    def getLength(self):
585        return len(QRUtil.stringToBytes(self.getData() ) )
586
587    def getLengthInBits(self, type):
588        if 1 <= type and type < 10: # 1 - 9
589            return {
590                Mode.MODE_NUMBER:    10,
591                Mode.MODE_ALPHA_NUM: 9,
592                Mode.MODE_8BIT_BYTE: 8,
593                Mode.MODE_KANJI:     8
594                }[self.mode]
595
596        elif type < 27: # 10 - 26
597            return {
598                Mode.MODE_NUMBER:    12,
599                Mode.MODE_ALPHA_NUM: 11,
600                Mode.MODE_8BIT_BYTE: 16,
601                Mode.MODE_KANJI:     10
602                }[self.mode]
603
604        elif type < 41: # 27 - 40
605            return {
606                Mode.MODE_NUMBER:    14,
607                Mode.MODE_ALPHA_NUM: 13,
608                Mode.MODE_8BIT_BYTE: 16,
609                Mode.MODE_KANJI:     12
610                }[self.mode]
611
612        else:
613            raise Exception('type:%s' % type)
614
615class QRMath:
616
617    EXP_TABLE = None
618    LOG_TABLE = None
619
620    @staticmethod
621    def _init():
622
623        QRMath.EXP_TABLE = [0] * 256
624        for i in range(256):
625            QRMath.EXP_TABLE[i] = (1 << i if i < 8 else
626                     QRMath.EXP_TABLE[i - 4] ^ QRMath.EXP_TABLE[i - 5] ^
627                     QRMath.EXP_TABLE[i - 6] ^ QRMath.EXP_TABLE[i - 8])
628
629        QRMath.LOG_TABLE = [0] * 256
630        for i in range(255):
631            QRMath.LOG_TABLE[QRMath.EXP_TABLE[i] ] = i
632
633    @staticmethod
634    def glog(n):
635        if n < 1:
636            raise Exception('log(%s)' % n)
637        return QRMath.LOG_TABLE[n]
638
639    @staticmethod
640    def gexp(n):
641        while n < 0:
642            n += 255
643        while n >= 256:
644            n -= 255
645        return QRMath.EXP_TABLE[n]
646
647# initialize statics
648QRMath._init()
649
650class Polynomial:
651
652    def __init__(self, num, shift=0):
653        offset = 0
654        length = len(num)
655        while offset < length and num[offset] == 0:
656            offset += 1
657        self.num = num[offset:] + [0] * shift
658
659    def get(self, index):
660        return self.num[index]
661
662    def getLength(self):
663        return len(self.num)
664
665    def __repr__(self):
666        return ','.join( [str(self.get(i) )
667            for i in range(self.getLength() ) ] )
668
669    def toLogString(self):
670        return ','.join( [str(QRMath.glog(self.get(i) ) )
671            for i in range(self.getLength() ) ] )
672
673    def multiply(self, e):
674        num = [0] * (self.getLength() + e.getLength() - 1)
675        for i in range(self.getLength() ):
676            for j in range(e.getLength() ):
677                num[i + j] ^= QRMath.gexp(QRMath.glog(self.get(i) ) +
678                              QRMath.glog(e.get(j) ) )
679        return Polynomial(num)
680
681    def mod(self, e):
682        if self.getLength() - e.getLength() < 0:
683            return self
684        ratio = QRMath.glog(self.get(0) ) - QRMath.glog(e.get(0) )
685        num = self.num[:]
686        for i in range(e.getLength() ):
687            num[i] ^= QRMath.gexp(QRMath.glog(e.get(i) ) + ratio)
688        return Polynomial(num).mod(e)
689
690class RSBlock:
691
692    RS_BLOCK_TABLE = [
693
694        # L
695        # M
696        # Q
697        # H
698
699        # 1
700        [1, 26, 19],
701        [1, 26, 16],
702        [1, 26, 13],
703        [1, 26, 9],
704
705        # 2
706        [1, 44, 34],
707        [1, 44, 28],
708        [1, 44, 22],
709        [1, 44, 16],
710
711        # 3
712        [1, 70, 55],
713        [1, 70, 44],
714        [2, 35, 17],
715        [2, 35, 13],
716
717        # 4
718        [1, 100, 80],
719        [2, 50, 32],
720        [2, 50, 24],
721        [4, 25, 9],
722
723        # 5
724        [1, 134, 108],
725        [2, 67, 43],
726        [2, 33, 15, 2, 34, 16],
727        [2, 33, 11, 2, 34, 12],
728
729        # 6
730        [2, 86, 68],
731        [4, 43, 27],
732        [4, 43, 19],
733        [4, 43, 15],
734
735        # 7
736        [2, 98, 78],
737        [4, 49, 31],
738        [2, 32, 14, 4, 33, 15],
739        [4, 39, 13, 1, 40, 14],
740
741        # 8
742        [2, 121, 97],
743        [2, 60, 38, 2, 61, 39],
744        [4, 40, 18, 2, 41, 19],
745        [4, 40, 14, 2, 41, 15],
746
747        # 9
748        [2, 146, 116],
749        [3, 58, 36, 2, 59, 37],
750        [4, 36, 16, 4, 37, 17],
751        [4, 36, 12, 4, 37, 13],
752
753        # 10
754        [2, 86, 68, 2, 87, 69],
755        [4, 69, 43, 1, 70, 44],
756        [6, 43, 19, 2, 44, 20],
757        [6, 43, 15, 2, 44, 16]
758        ]
759
760    def __init__(self, totalCount, dataCount):
761        self.totalCount = totalCount
762        self.dataCount  = dataCount
763
764    def getDataCount(self):
765        return self.dataCount
766
767    def getTotalCount(self):
768        return self.totalCount
769
770    def __repr__(self):
771        return ('(total=%s,data=%s)' % (self.totalCount, self.dataCount) )
772
773    @staticmethod
774    def getRSBlocks(typeNumber, errorCorrectLevel):
775        rsBlock = RSBlock.getRsBlockTable(typeNumber, errorCorrectLevel)
776        length = len(rsBlock) // 3
777        list = []
778        for i in range(length):
779            count      = rsBlock[i * 3 + 0]
780            totalCount = rsBlock[i * 3 + 1]
781            dataCount  = rsBlock[i * 3 + 2]
782            list += [RSBlock(totalCount, dataCount)] * count
783        return list
784
785    @staticmethod
786    def getRsBlockTable(typeNumber, errorCorrectLevel):
787        return {
788            ErrorCorrectLevel.L:
789                RSBlock.RS_BLOCK_TABLE[ (typeNumber - 1) * 4 + 0],
790            ErrorCorrectLevel.M:
791                RSBlock.RS_BLOCK_TABLE[ (typeNumber - 1) * 4 + 1],
792            ErrorCorrectLevel.Q:
793                RSBlock.RS_BLOCK_TABLE[ (typeNumber - 1) * 4 + 2],
794            ErrorCorrectLevel.H:
795                RSBlock.RS_BLOCK_TABLE[ (typeNumber - 1) * 4 + 3]
796            }[errorCorrectLevel]
797
798class BitBuffer:
799
800    def __init__(self, inclements=32):
801        self.inclements = inclements
802        self.buffer = [0] * self.inclements
803        self.length = 0
804
805    def getBuffer(self):
806        return self.buffer
807
808    def getLengthInBits(self):
809        return self.length
810
811    def get(self, index):
812        return ( (self.buffer[index // 8] >> (7 - index % 8) ) & 1) == 1
813
814    def putBit(self, bit):
815        if self.length == len(self.buffer) * 8:
816            self.buffer += [0] * self.inclements
817        if bit:
818            self.buffer[self.length // 8] |= (0x80 >> (self.length % 8) )
819        self.length += 1
820
821    def put(self, num, length):
822        for i in range(length):
823            self.putBit( ( (num >> (length - i - 1) ) & 1) == 1)
824
825    def __repr__(self):
826        return ''.join('1' if self.get(i) else '0'
827            for i in range(self.getLengthInBits() ) )
828