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