diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index c00e7dd..472aafc 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -24,15 +24,11 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install flake8 pytest - pip install . + pip install .[dev] if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - - name: Lint with flake8 + - name: Lint run: | - # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics - # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + make lint - name: Test with pytest run: | python -m pytest diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 53b92d3..1e79947 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,13 +1,17 @@ # Contributing to rmqrcode-python - Thank you for interesting in contributing to rmqrcode-python! Any suggestions are welcome. ## Style Guides ### Git Commit Message - Consider starting commit message with one of the following prefixes. - `feat:` : New feature - `fix:` : Bug fix - `refactor:` : Refactoring - `chore:` : Little things - `doc:` : Documentation + +## Pull Requests +Before make a pull request, please do the following. +1. `make format` +2. `make lint` +3. `python -m pytest` and make sure all tests are passed. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..64421c3 --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +.PHONY: lint +lint: + flake8 src + isort --check --diff src + black --check src + +.PHONY: format +format: + isort src + black src diff --git a/pyproject.toml b/pyproject.toml index fa7093a..8969d2e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,7 @@ [build-system] requires = ["setuptools>=42"] -build-backend = "setuptools.build_meta" \ No newline at end of file +build-backend = "setuptools.build_meta" + +[tool.black] +line-length = 119 +exclude = "generator_polynomials.py" diff --git a/setup.cfg b/setup.cfg index ada13c1..8360b5f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -23,10 +23,21 @@ install_requires = [options.extras_require] dev = pytest + flake8 + isort + black [options.packages.find] where = src [options.entry_points] console_scripts = - rmqr = rmqrcode.console:main \ No newline at end of file + rmqr = rmqrcode.console:main + +[flake8] +max-line-length = 119 +extend-ignore = E203 +exclude = src/rmqrcode/format/generator_polynomials.py + +[isort] +profile=black diff --git a/src/rmqrcode/__init__.py b/src/rmqrcode/__init__.py index 2b40cee..aca9a2f 100644 --- a/src/rmqrcode/__init__.py +++ b/src/rmqrcode/__init__.py @@ -1,6 +1,5 @@ -from .rmqrcode import rMQR -from .rmqrcode import FitStrategy -from .rmqrcode import DataTooLongError -from .rmqrcode import IllegalVersionError +from .format.error_correction_level import ErrorCorrectionLevel from .qr_image import QRImage -from .format.error_correction_level import ErrorCorrectionLevel \ No newline at end of file +from .rmqrcode import DataTooLongError, FitStrategy, IllegalVersionError, rMQR + +__all__ = ("rMQR", "DataTooLongError", "FitStrategy", "IllegalVersionError", "QRImage", "ErrorCorrectionLevel") diff --git a/src/rmqrcode/console.py b/src/rmqrcode/console.py index aa1117e..5220c64 100644 --- a/src/rmqrcode/console.py +++ b/src/rmqrcode/console.py @@ -1,15 +1,16 @@ #!/usr/bin/env python -import rmqrcode -from rmqrcode import rMQR -from rmqrcode import QRImage -from rmqrcode import ErrorCorrectionLevel -from rmqrcode import FitStrategy -from rmqrcode import DataTooLongError -from rmqrcode import IllegalVersionError - import argparse import sys +from rmqrcode import ( + DataTooLongError, + ErrorCorrectionLevel, + FitStrategy, + IllegalVersionError, + QRImage, + rMQR, +) + def _show_error_and_exit(msg): print(msg, file=sys.stderr) @@ -17,7 +18,7 @@ def _show_error_and_exit(msg): def _make_qr(data, ecc, version, fit_strategy): - if version == None: + if version is None: qr = rMQR.fit(data, ecc=ecc, fit_strategy=fit_strategy) else: try: @@ -29,7 +30,6 @@ def _make_qr(data, ecc, version, fit_strategy): return qr - def _save_image(qr, output): image = QRImage(qr) try: @@ -42,24 +42,19 @@ def main(): parser = _init_argparser() args = parser.parse_args() - if args.ecc == 'M': + if args.ecc == "M": ecc = ErrorCorrectionLevel.M - elif args.ecc == 'H': + elif args.ecc == "H": ecc = ErrorCorrectionLevel.H fit_strategy = FitStrategy.BALANCED - if args.fit_strategy == 'min_width': + if args.fit_strategy == "min_width": fit_strategy = FitStrategy.MINIMIZE_WIDTH - elif args.fit_strategy == 'min_height': + elif args.fit_strategy == "min_height": fit_strategy = FitStrategy.MINIMIZE_HEIGHT try: - qr = _make_qr( - args.DATA, - ecc=ecc, - version=args.version, - fit_strategy=fit_strategy - ) + qr = _make_qr(args.DATA, ecc=ecc, version=args.version, fit_strategy=fit_strategy) except DataTooLongError: _show_error_and_exit("Error: The data is too long.") @@ -68,13 +63,20 @@ def main(): def _init_argparser(): parser = argparse.ArgumentParser() - parser.add_argument('DATA', type=str, help="Data to encode.") - parser.add_argument('OUTPUT', type=str, help="Output file path") - parser.add_argument('--ecc', help="Error correction level. (default: M)", type=str, choices=["M", "H"], default='M') - parser.add_argument('--version', help="rMQR Code version like 'R11x139'.") - parser.add_argument('--fit-strategy', choices=["min_width", "min_height", "balanced"], help="Strategy how to determine rMQR Code size.", dest="fit_strategy") + parser.add_argument("DATA", type=str, help="Data to encode.") + parser.add_argument("OUTPUT", type=str, help="Output file path") + parser.add_argument( + "--ecc", help="Error correction level. (default: M)", type=str, choices=["M", "H"], default="M" + ) + parser.add_argument("--version", help="rMQR Code version like 'R11x139'.") + parser.add_argument( + "--fit-strategy", + choices=["min_width", "min_height", "balanced"], + help="Strategy how to determine rMQR Code size.", + dest="fit_strategy", + ) return parser if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/src/rmqrcode/encoder/byte_encoder.py b/src/rmqrcode/encoder/byte_encoder.py index 38b7c22..ed6bbdf 100644 --- a/src/rmqrcode/encoder/byte_encoder.py +++ b/src/rmqrcode/encoder/byte_encoder.py @@ -4,12 +4,11 @@ class ByteEncoder: @staticmethod def _encoded_bits(s): res = "" - encoded = s.encode('utf-8') + encoded = s.encode("utf-8") for byte in encoded: res += bin(byte)[2:].zfill(8) return res - @staticmethod def encode(data, character_count_length): res = ByteEncoder.MODE_INDICATOR @@ -17,7 +16,6 @@ def encode(data, character_count_length): res += ByteEncoder._encoded_bits(data) return res - @staticmethod def length(data): - return len(data.encode('utf-8')) + return len(data.encode("utf-8")) diff --git a/src/rmqrcode/enums/color.py b/src/rmqrcode/enums/color.py index 7aeb18d..324839b 100644 --- a/src/rmqrcode/enums/color.py +++ b/src/rmqrcode/enums/color.py @@ -1,6 +1,7 @@ from enum import Enum + class Color(Enum): UNDEFINED = -1 WHITE = 0 - BLACK = 1 \ No newline at end of file + BLACK = 1 diff --git a/src/rmqrcode/enums/fit_strategy.py b/src/rmqrcode/enums/fit_strategy.py index bd006e9..80588b3 100644 --- a/src/rmqrcode/enums/fit_strategy.py +++ b/src/rmqrcode/enums/fit_strategy.py @@ -1,6 +1,7 @@ from enum import Enum + class FitStrategy(Enum): MINIMIZE_WIDTH = 0 MINIMIZE_HEIGHT = 1 - BALANCED = 2 \ No newline at end of file + BALANCED = 2 diff --git a/src/rmqrcode/format/alignment_pattern_coordinates.py b/src/rmqrcode/format/alignment_pattern_coordinates.py index 249698b..7b95c3f 100644 --- a/src/rmqrcode/format/alignment_pattern_coordinates.py +++ b/src/rmqrcode/format/alignment_pattern_coordinates.py @@ -5,4 +5,4 @@ 77: [25, 51], 99: [23, 49, 75], 139: [27, 55, 83, 111], -} \ No newline at end of file +} diff --git a/src/rmqrcode/format/data_capacities.py b/src/rmqrcode/format/data_capacities.py index 58b3739..304f067 100644 --- a/src/rmqrcode/format/data_capacities.py +++ b/src/rmqrcode/format/data_capacities.py @@ -1,326 +1,325 @@ from .error_correction_level import ErrorCorrectionLevel - # ISO/IEC 23941:2022 Table 6 DataCapacities = { - 'R7x43': { - 'height': 7, - 'width': 43, - 'capacity': { - 'Byte': { + "R7x43": { + "height": 7, + "width": 43, + "capacity": { + "Byte": { ErrorCorrectionLevel.M: 5, ErrorCorrectionLevel.H: 2, }, }, }, - 'R7x59': { - 'height': 7, - 'width': 59, - 'capacity': { - 'Byte': { + "R7x59": { + "height": 7, + "width": 59, + "capacity": { + "Byte": { ErrorCorrectionLevel.M: 11, ErrorCorrectionLevel.H: 6, }, }, }, - 'R7x77': { - 'height': 7, - 'width': 77, - 'capacity': { - 'Byte': { + "R7x77": { + "height": 7, + "width": 77, + "capacity": { + "Byte": { ErrorCorrectionLevel.M: 19, ErrorCorrectionLevel.H: 9, }, }, }, - 'R7x99': { - 'height': 7, - 'width': 99, - 'capacity': { - 'Byte': { + "R7x99": { + "height": 7, + "width": 99, + "capacity": { + "Byte": { ErrorCorrectionLevel.M: 27, ErrorCorrectionLevel.H: 13, }, }, }, - 'R7x139': { - 'height': 7, - 'width': 139, - 'capacity': { - 'Byte': { + "R7x139": { + "height": 7, + "width": 139, + "capacity": { + "Byte": { ErrorCorrectionLevel.M: 42, ErrorCorrectionLevel.H: 22, }, }, }, - 'R9x43': { - 'height': 9, - 'width': 43, - 'capacity': { - 'Byte': { + "R9x43": { + "height": 9, + "width": 43, + "capacity": { + "Byte": { ErrorCorrectionLevel.M: 11, ErrorCorrectionLevel.H: 6, }, }, }, - 'R9x59': { - 'height': 9, - 'width': 59, - 'capacity': { - 'Byte': { + "R9x59": { + "height": 9, + "width": 59, + "capacity": { + "Byte": { ErrorCorrectionLevel.M: 20, ErrorCorrectionLevel.H: 10, }, }, }, - 'R9x77': { - 'height': 9, - 'width': 77, - 'capacity': { - 'Byte': { + "R9x77": { + "height": 9, + "width": 77, + "capacity": { + "Byte": { ErrorCorrectionLevel.M: 30, ErrorCorrectionLevel.H: 16, }, }, }, - 'R9x99': { - 'height': 9, - 'width': 99, - 'capacity': { - 'Byte': { + "R9x99": { + "height": 9, + "width": 99, + "capacity": { + "Byte": { ErrorCorrectionLevel.M: 40, ErrorCorrectionLevel.H: 20, }, }, }, - 'R9x139': { - 'height': 9, - 'width': 139, - 'capacity': { - 'Byte': { + "R9x139": { + "height": 9, + "width": 139, + "capacity": { + "Byte": { ErrorCorrectionLevel.M: 61, ErrorCorrectionLevel.H: 31, }, }, }, - 'R11x27': { - 'height': 11, - 'width': 27, - 'capacity': { - 'Byte': { + "R11x27": { + "height": 11, + "width": 27, + "capacity": { + "Byte": { ErrorCorrectionLevel.M: 6, ErrorCorrectionLevel.H: 4, }, }, }, - 'R11x43': { - 'height': 11, - 'width': 43, - 'capacity': { - 'Byte': { + "R11x43": { + "height": 11, + "width": 43, + "capacity": { + "Byte": { ErrorCorrectionLevel.M: 18, ErrorCorrectionLevel.H: 10, }, }, }, - 'R11x59': { - 'height': 11, - 'width': 59, - 'capacity': { - 'Byte': { + "R11x59": { + "height": 11, + "width": 59, + "capacity": { + "Byte": { ErrorCorrectionLevel.M: 30, ErrorCorrectionLevel.H: 14, }, }, }, - 'R11x77': { - 'height': 11, - 'width': 77, - 'capacity': { - 'Byte': { + "R11x77": { + "height": 11, + "width": 77, + "capacity": { + "Byte": { ErrorCorrectionLevel.M: 41, ErrorCorrectionLevel.H: 21, }, }, }, - 'R11x99': { - 'height': 11, - 'width': 99, - 'capacity': { - 'Byte': { + "R11x99": { + "height": 11, + "width": 99, + "capacity": { + "Byte": { ErrorCorrectionLevel.M: 55, ErrorCorrectionLevel.H: 27, }, }, }, - 'R11x139': { - 'height': 11, - 'width': 139, - 'capacity': { - 'Byte': { + "R11x139": { + "height": 11, + "width": 139, + "capacity": { + "Byte": { ErrorCorrectionLevel.M: 82, ErrorCorrectionLevel.H: 40, }, }, }, - 'R13x27': { - 'height': 13, - 'width': 27, - 'capacity': { - 'Byte': { + "R13x27": { + "height": 13, + "width": 27, + "capacity": { + "Byte": { ErrorCorrectionLevel.M: 11, ErrorCorrectionLevel.H: 6, }, }, }, - 'R13x43': { - 'height': 13, - 'width': 43, - 'capacity': { - 'Byte': { + "R13x43": { + "height": 13, + "width": 43, + "capacity": { + "Byte": { ErrorCorrectionLevel.M: 26, ErrorCorrectionLevel.H: 12, }, }, }, - 'R13x59': { - 'height': 13, - 'width': 59, - 'capacity': { - 'Byte': { + "R13x59": { + "height": 13, + "width": 59, + "capacity": { + "Byte": { ErrorCorrectionLevel.M: 36, ErrorCorrectionLevel.H: 18, }, }, }, - 'R13x77': { - 'height': 13, - 'width': 77, - 'capacity': { - 'Byte': { + "R13x77": { + "height": 13, + "width": 77, + "capacity": { + "Byte": { ErrorCorrectionLevel.M: 51, ErrorCorrectionLevel.H: 27, }, }, }, - 'R13x99': { - 'height': 13, - 'width': 99, - 'capacity': { - 'Byte': { + "R13x99": { + "height": 13, + "width": 99, + "capacity": { + "Byte": { ErrorCorrectionLevel.M: 71, ErrorCorrectionLevel.H: 33, }, }, }, - 'R13x139': { - 'height': 13, - 'width': 139, - 'capacity': { - 'Byte': { + "R13x139": { + "height": 13, + "width": 139, + "capacity": { + "Byte": { ErrorCorrectionLevel.M: 104, ErrorCorrectionLevel.H: 52, }, }, }, - 'R15x43': { - 'height': 15, - 'width': 43, - 'capacity': { - 'Byte': { + "R15x43": { + "height": 15, + "width": 43, + "capacity": { + "Byte": { ErrorCorrectionLevel.M: 31, ErrorCorrectionLevel.H: 13, }, }, }, - 'R15x59': { - 'height': 15, - 'width': 59, - 'capacity': { - 'Byte': { + "R15x59": { + "height": 15, + "width": 59, + "capacity": { + "Byte": { ErrorCorrectionLevel.M: 46, ErrorCorrectionLevel.H: 24, }, }, }, - 'R15x77': { - 'height': 15, - 'width': 77, - 'capacity': { - 'Byte': { + "R15x77": { + "height": 15, + "width": 77, + "capacity": { + "Byte": { ErrorCorrectionLevel.M: 65, ErrorCorrectionLevel.H: 29, }, }, }, - 'R15x99': { - 'height': 15, - 'width': 99, - 'capacity': { - 'Byte': { + "R15x99": { + "height": 15, + "width": 99, + "capacity": { + "Byte": { ErrorCorrectionLevel.M: 86, ErrorCorrectionLevel.H: 46, }, }, }, - 'R15x139': { - 'height': 15, - 'width': 139, - 'capacity': { - 'Byte': { + "R15x139": { + "height": 15, + "width": 139, + "capacity": { + "Byte": { ErrorCorrectionLevel.M: 125, ErrorCorrectionLevel.H: 67, }, }, }, - 'R17x43': { - 'height': 17, - 'width': 43, - 'capacity': { - 'Byte': { + "R17x43": { + "height": 17, + "width": 43, + "capacity": { + "Byte": { ErrorCorrectionLevel.M: 37, ErrorCorrectionLevel.H: 19, }, }, }, - 'R17x59': { - 'height': 17, - 'width': 59, - 'capacity': { - 'Byte': { + "R17x59": { + "height": 17, + "width": 59, + "capacity": { + "Byte": { ErrorCorrectionLevel.M: 54, ErrorCorrectionLevel.H: 26, }, }, }, - 'R17x77': { - 'height': 17, - 'width': 77, - 'capacity': { - 'Byte': { + "R17x77": { + "height": 17, + "width": 77, + "capacity": { + "Byte": { ErrorCorrectionLevel.M: 76, ErrorCorrectionLevel.H: 36, }, }, }, - 'R17x99': { - 'height': 17, - 'width': 99, - 'capacity': { - 'Byte': { + "R17x99": { + "height": 17, + "width": 99, + "capacity": { + "Byte": { ErrorCorrectionLevel.M: 98, ErrorCorrectionLevel.H: 54, }, }, }, - 'R17x139': { - 'height': 17, - 'width': 139, - 'capacity': { - 'Byte': { + "R17x139": { + "height": 17, + "width": 139, + "capacity": { + "Byte": { ErrorCorrectionLevel.M: 150, ErrorCorrectionLevel.H: 74, }, }, }, -} \ No newline at end of file +} diff --git a/src/rmqrcode/format/error_correction_level.py b/src/rmqrcode/format/error_correction_level.py index 7483698..84e18e3 100644 --- a/src/rmqrcode/format/error_correction_level.py +++ b/src/rmqrcode/format/error_correction_level.py @@ -1,5 +1,6 @@ from enum import Enum + class ErrorCorrectionLevel(Enum): M = 0 - H = 1 \ No newline at end of file + H = 1 diff --git a/src/rmqrcode/format/mask.py b/src/rmqrcode/format/mask.py index 4822236..4ce92b7 100644 --- a/src/rmqrcode/format/mask.py +++ b/src/rmqrcode/format/mask.py @@ -1,2 +1,2 @@ def mask(x, y): - return (y//2 + x//3) % 2 == 0 + return (y // 2 + x // 3) % 2 == 0 diff --git a/src/rmqrcode/format/rmqr_versions.py b/src/rmqrcode/format/rmqr_versions.py index 2bc9232..6861772 100644 --- a/src/rmqrcode/format/rmqr_versions.py +++ b/src/rmqrcode/format/rmqr_versions.py @@ -1,878 +1,877 @@ from .error_correction_level import ErrorCorrectionLevel - rMQRVersions = { - 'R7x43': { - 'version_indicator': 0b00000, - 'height': 7, - 'width': 43, - 'remainder_bits': 0, - 'character_count_length': 3, - 'codewords_total': 13, - 'blocks': { + "R7x43": { + "version_indicator": 0b00000, + "height": 7, + "width": 43, + "remainder_bits": 0, + "character_count_length": 3, + "codewords_total": 13, + "blocks": { ErrorCorrectionLevel.M: [ { - 'num': 1, - 'c': 13, - 'k': 6, + "num": 1, + "c": 13, + "k": 6, }, ], ErrorCorrectionLevel.H: [ { - 'num': 1, - 'c': 13, - 'k': 3, + "num": 1, + "c": 13, + "k": 3, }, - ] - } + ], + }, }, - 'R7x59': { - 'version_indicator': 0b00001, - 'height': 7, - 'width': 59, - 'remainder_bits': 3, - 'character_count_length': 4, - 'codewords_total': 21, - 'blocks': { + "R7x59": { + "version_indicator": 0b00001, + "height": 7, + "width": 59, + "remainder_bits": 3, + "character_count_length": 4, + "codewords_total": 21, + "blocks": { ErrorCorrectionLevel.M: [ { - 'num': 1, - 'c': 21, - 'k': 12, + "num": 1, + "c": 21, + "k": 12, }, ], ErrorCorrectionLevel.H: [ { - 'num': 1, - 'c': 21, - 'k': 7, + "num": 1, + "c": 21, + "k": 7, }, - ] - } + ], + }, }, - 'R7x77': { - 'version_indicator': 0b00010, - 'height': 7, - 'width': 77, - 'remainder_bits': 5, - 'character_count_length': 5, - 'codewords_total': 32, - 'blocks': { + "R7x77": { + "version_indicator": 0b00010, + "height": 7, + "width": 77, + "remainder_bits": 5, + "character_count_length": 5, + "codewords_total": 32, + "blocks": { ErrorCorrectionLevel.M: [ { - 'num': 1, - 'c': 32, - 'k': 20, + "num": 1, + "c": 32, + "k": 20, }, ], ErrorCorrectionLevel.H: [ { - 'num': 1, - 'c': 32, - 'k': 10, + "num": 1, + "c": 32, + "k": 10, }, - ] - } + ], + }, }, - 'R7x99': { - 'version_indicator': 0b00011, - 'height': 7, - 'width': 99, - 'remainder_bits': 6, - 'character_count_length': 5, - 'codewords_total': 44, - 'blocks': { + "R7x99": { + "version_indicator": 0b00011, + "height": 7, + "width": 99, + "remainder_bits": 6, + "character_count_length": 5, + "codewords_total": 44, + "blocks": { ErrorCorrectionLevel.M: [ { - 'num': 1, - 'c': 44, - 'k': 28, + "num": 1, + "c": 44, + "k": 28, }, ], ErrorCorrectionLevel.H: [ { - 'num': 1, - 'c': 44, - 'k': 14, + "num": 1, + "c": 44, + "k": 14, }, - ] - } + ], + }, }, - 'R7x139': { - 'version_indicator': 0b00100, - 'height': 7, - 'width': 139, - 'remainder_bits': 1, - 'character_count_length': 6, - 'codewords_total': 68, - 'blocks': { + "R7x139": { + "version_indicator": 0b00100, + "height": 7, + "width": 139, + "remainder_bits": 1, + "character_count_length": 6, + "codewords_total": 68, + "blocks": { ErrorCorrectionLevel.M: [ { - 'num': 1, - 'c': 68, - 'k': 44, + "num": 1, + "c": 68, + "k": 44, }, ], ErrorCorrectionLevel.H: [ { - 'num': 2, - 'c': 34, - 'k': 12, + "num": 2, + "c": 34, + "k": 12, }, - ] - } + ], + }, }, - 'R9x43': { - 'version_indicator': 0b00101, - 'height': 9, - 'width': 43, - 'remainder_bits': 2, - 'character_count_length': 4, - 'codewords_total': 21, - 'blocks': { + "R9x43": { + "version_indicator": 0b00101, + "height": 9, + "width": 43, + "remainder_bits": 2, + "character_count_length": 4, + "codewords_total": 21, + "blocks": { ErrorCorrectionLevel.M: [ { - 'num': 1, - 'c': 21, - 'k': 12, + "num": 1, + "c": 21, + "k": 12, }, ], ErrorCorrectionLevel.H: [ { - 'num': 1, - 'c': 21, - 'k': 7, + "num": 1, + "c": 21, + "k": 7, }, - ] - } + ], + }, }, - 'R9x59': { - 'version_indicator': 0b00110, - 'height': 9, - 'width': 59, - 'remainder_bits': 3, - 'character_count_length': 5, - 'codewords_total': 33, - 'blocks': { + "R9x59": { + "version_indicator": 0b00110, + "height": 9, + "width": 59, + "remainder_bits": 3, + "character_count_length": 5, + "codewords_total": 33, + "blocks": { ErrorCorrectionLevel.M: [ { - 'num': 1, - 'c': 33, - 'k': 21, + "num": 1, + "c": 33, + "k": 21, }, ], ErrorCorrectionLevel.H: [ { - 'num': 1, - 'c': 33, - 'k': 11, + "num": 1, + "c": 33, + "k": 11, }, - ] - } + ], + }, }, - 'R9x77': { - 'version_indicator': 0b00111, - 'height': 9, - 'width': 77, - 'remainder_bits': 1, - 'character_count_length': 5, - 'codewords_total': 49, - 'blocks': { + "R9x77": { + "version_indicator": 0b00111, + "height": 9, + "width": 77, + "remainder_bits": 1, + "character_count_length": 5, + "codewords_total": 49, + "blocks": { ErrorCorrectionLevel.M: [ { - 'num': 1, - 'c': 49, - 'k': 31, + "num": 1, + "c": 49, + "k": 31, }, ], ErrorCorrectionLevel.H: [ { - 'num': 1, - 'c': 24, - 'k': 8, + "num": 1, + "c": 24, + "k": 8, }, { - 'num': 1, - 'c': 25, - 'k': 9, + "num": 1, + "c": 25, + "k": 9, }, - ] - } + ], + }, }, - 'R9x99': { - 'version_indicator': 0b01000, - 'height': 9, - 'width': 99, - 'remainder_bits': 4, - 'character_count_length': 6, - 'codewords_total': 66, - 'blocks': { + "R9x99": { + "version_indicator": 0b01000, + "height": 9, + "width": 99, + "remainder_bits": 4, + "character_count_length": 6, + "codewords_total": 66, + "blocks": { ErrorCorrectionLevel.M: [ { - 'num': 1, - 'c': 66, - 'k': 42, + "num": 1, + "c": 66, + "k": 42, }, ], ErrorCorrectionLevel.H: [ { - 'num': 2, - 'c': 33, - 'k': 11, + "num": 2, + "c": 33, + "k": 11, }, - ] - } + ], + }, }, - 'R9x139': { - 'version_indicator': 0b01001, - 'height': 9, - 'width': 139, - 'remainder_bits': 5, - 'character_count_length': 6, - 'codewords_total': 99, - 'blocks': { + "R9x139": { + "version_indicator": 0b01001, + "height": 9, + "width": 139, + "remainder_bits": 5, + "character_count_length": 6, + "codewords_total": 99, + "blocks": { ErrorCorrectionLevel.M: [ { - 'num': 1, - 'c': 49, - 'k': 31, + "num": 1, + "c": 49, + "k": 31, }, { - 'num': 1, - 'c': 50, - 'k': 32, + "num": 1, + "c": 50, + "k": 32, }, ], ErrorCorrectionLevel.H: [ { - 'num': 3, - 'c': 33, - 'k': 11, + "num": 3, + "c": 33, + "k": 11, } - ] - } + ], + }, }, - 'R11x27': { - 'version_indicator': 0b01010, - 'height': 11, - 'width': 27, - 'remainder_bits': 2, - 'character_count_length': 3, - 'codewords_total': 15, - 'blocks': { + "R11x27": { + "version_indicator": 0b01010, + "height": 11, + "width": 27, + "remainder_bits": 2, + "character_count_length": 3, + "codewords_total": 15, + "blocks": { ErrorCorrectionLevel.M: [ { - 'num': 1, - 'c': 15, - 'k': 7, + "num": 1, + "c": 15, + "k": 7, }, ], ErrorCorrectionLevel.H: [ { - 'num': 1, - 'c': 15, - 'k': 5, + "num": 1, + "c": 15, + "k": 5, } - ] - } + ], + }, }, - 'R11x43': { - 'version_indicator': 0b01011, - 'height': 11, - 'width': 43, - 'remainder_bits': 1, - 'character_count_length': 5, - 'codewords_total': 31, - 'blocks': { + "R11x43": { + "version_indicator": 0b01011, + "height": 11, + "width": 43, + "remainder_bits": 1, + "character_count_length": 5, + "codewords_total": 31, + "blocks": { ErrorCorrectionLevel.M: [ { - 'num': 1, - 'c': 31, - 'k': 19, + "num": 1, + "c": 31, + "k": 19, }, ], ErrorCorrectionLevel.H: [ { - 'num': 1, - 'c': 31, - 'k': 11, + "num": 1, + "c": 31, + "k": 11, } - ] - } + ], + }, }, - 'R11x59': { - 'version_indicator': 0b01100, - 'height': 11, - 'width': 59, - 'remainder_bits': 0, - 'character_count_length': 5, - 'codewords_total': 47, - 'blocks': { + "R11x59": { + "version_indicator": 0b01100, + "height": 11, + "width": 59, + "remainder_bits": 0, + "character_count_length": 5, + "codewords_total": 47, + "blocks": { ErrorCorrectionLevel.M: [ { - 'num': 1, - 'c': 47, - 'k': 31, + "num": 1, + "c": 47, + "k": 31, }, ], ErrorCorrectionLevel.H: [ { - 'num': 1, - 'c': 23, - 'k': 7, + "num": 1, + "c": 23, + "k": 7, }, { - 'num': 1, - 'c': 24, - 'k': 8, + "num": 1, + "c": 24, + "k": 8, }, - ] - } + ], + }, }, - 'R11x77': { - 'version_indicator': 0b01101, - 'height': 11, - 'width': 77, - 'remainder_bits': 2, - 'character_count_length': 6, - 'codewords_total': 67, - 'blocks': { + "R11x77": { + "version_indicator": 0b01101, + "height": 11, + "width": 77, + "remainder_bits": 2, + "character_count_length": 6, + "codewords_total": 67, + "blocks": { ErrorCorrectionLevel.M: [ { - 'num': 1, - 'c': 67, - 'k': 43, + "num": 1, + "c": 67, + "k": 43, }, ], ErrorCorrectionLevel.H: [ { - 'num': 1, - 'c': 33, - 'k': 11, + "num": 1, + "c": 33, + "k": 11, }, { - 'num': 1, - 'c': 34, - 'k': 12, + "num": 1, + "c": 34, + "k": 12, }, - ] - } + ], + }, }, - 'R11x99': { - 'version_indicator': 0b01110, - 'height': 11, - 'width': 99, - 'remainder_bits': 7, - 'character_count_length': 6, - 'codewords_total': 89, - 'blocks': { + "R11x99": { + "version_indicator": 0b01110, + "height": 11, + "width": 99, + "remainder_bits": 7, + "character_count_length": 6, + "codewords_total": 89, + "blocks": { ErrorCorrectionLevel.M: [ { - 'num': 1, - 'c': 44, - 'k': 28, + "num": 1, + "c": 44, + "k": 28, }, { - 'num': 1, - 'c': 45, - 'k': 29, + "num": 1, + "c": 45, + "k": 29, }, ], ErrorCorrectionLevel.H: [ { - 'num': 1, - 'c': 44, - 'k': 14, + "num": 1, + "c": 44, + "k": 14, }, { - 'num': 1, - 'c': 45, - 'k': 15, + "num": 1, + "c": 45, + "k": 15, }, - ] - } + ], + }, }, - 'R11x139': { - 'version_indicator': 0b01111, - 'height': 11, - 'width': 139, - 'remainder_bits': 6, - 'character_count_length': 7, - 'codewords_total': 132, - 'blocks': { + "R11x139": { + "version_indicator": 0b01111, + "height": 11, + "width": 139, + "remainder_bits": 6, + "character_count_length": 7, + "codewords_total": 132, + "blocks": { ErrorCorrectionLevel.M: [ { - 'num': 2, - 'c': 66, - 'k': 42, + "num": 2, + "c": 66, + "k": 42, }, ], ErrorCorrectionLevel.H: [ { - 'num': 3, - 'c': 44, - 'k': 14, + "num": 3, + "c": 44, + "k": 14, } - ] - } + ], + }, }, - 'R13x27': { - 'version_indicator': 0b10000, - 'height': 13, - 'width': 27, - 'character_count_length': 4, - 'remainder_bits': 4, - 'codewords_total': 21, - 'blocks': { + "R13x27": { + "version_indicator": 0b10000, + "height": 13, + "width": 27, + "character_count_length": 4, + "remainder_bits": 4, + "codewords_total": 21, + "blocks": { ErrorCorrectionLevel.M: [ { - 'num': 1, - 'c': 21, - 'k': 14, + "num": 1, + "c": 21, + "k": 14, }, ], ErrorCorrectionLevel.H: [ { - 'num': 1, - 'c': 21, - 'k': 7, + "num": 1, + "c": 21, + "k": 7, } - ] - } + ], + }, }, - 'R13x43': { - 'version_indicator': 0b10001, - 'height': 13, - 'width': 43, - 'remainder_bits': 1, - 'character_count_length': 5, - 'codewords_total': 41, - 'blocks': { + "R13x43": { + "version_indicator": 0b10001, + "height": 13, + "width": 43, + "remainder_bits": 1, + "character_count_length": 5, + "codewords_total": 41, + "blocks": { ErrorCorrectionLevel.M: [ { - 'num': 1, - 'c': 41, - 'k': 27, + "num": 1, + "c": 41, + "k": 27, }, ], ErrorCorrectionLevel.H: [ { - 'num': 1, - 'c': 41, - 'k': 13, + "num": 1, + "c": 41, + "k": 13, } - ] - } + ], + }, }, - 'R13x59': { - 'version_indicator': 0b10010, - 'height': 13, - 'width': 59, - 'remainder_bits': 6, - 'character_count_length': 6, - 'codewords_total': 60, - 'blocks': { + "R13x59": { + "version_indicator": 0b10010, + "height": 13, + "width": 59, + "remainder_bits": 6, + "character_count_length": 6, + "codewords_total": 60, + "blocks": { ErrorCorrectionLevel.M: [ { - 'num': 1, - 'c': 60, - 'k': 38, + "num": 1, + "c": 60, + "k": 38, }, ], ErrorCorrectionLevel.H: [ { - 'num': 2, - 'c': 30, - 'k': 10, + "num": 2, + "c": 30, + "k": 10, } - ] - } + ], + }, }, - 'R13x77': { - 'version_indicator': 0b10011, - 'height': 13, - 'width': 77, - 'remainder_bits': 4, - 'character_count_length': 6, - 'codewords_total': 85, - 'blocks': { + "R13x77": { + "version_indicator": 0b10011, + "height": 13, + "width": 77, + "remainder_bits": 4, + "character_count_length": 6, + "codewords_total": 85, + "blocks": { ErrorCorrectionLevel.M: [ { - 'num': 1, - 'c': 42, - 'k': 26, + "num": 1, + "c": 42, + "k": 26, }, { - 'num': 1, - 'c': 43, - 'k': 27, + "num": 1, + "c": 43, + "k": 27, }, ], ErrorCorrectionLevel.H: [ { - 'num': 1, - 'c': 42, - 'k': 14, + "num": 1, + "c": 42, + "k": 14, }, { - 'num': 1, - 'c': 43, - 'k': 15, + "num": 1, + "c": 43, + "k": 15, }, - ] - } + ], + }, }, - 'R13x99': { - 'version_indicator': 0b10100, - 'height': 13, - 'width': 99, - 'remainder_bits': 3, - 'character_count_length': 7, - 'codewords_total': 113, - 'blocks': { + "R13x99": { + "version_indicator": 0b10100, + "height": 13, + "width": 99, + "remainder_bits": 3, + "character_count_length": 7, + "codewords_total": 113, + "blocks": { ErrorCorrectionLevel.M: [ { - 'num': 1, - 'c': 56, - 'k': 36, + "num": 1, + "c": 56, + "k": 36, }, { - 'num': 1, - 'c': 57, - 'k': 37, + "num": 1, + "c": 57, + "k": 37, }, ], ErrorCorrectionLevel.H: [ { - 'num': 1, - 'c': 37, - 'k': 11, + "num": 1, + "c": 37, + "k": 11, }, { - 'num': 2, - 'c': 38, - 'k': 12, + "num": 2, + "c": 38, + "k": 12, }, - ] - } + ], + }, }, - 'R13x139': { - 'version_indicator': 0b10101, - 'height': 13, - 'width': 139, - 'remainder_bits': 0, - 'character_count_length': 7, - 'codewords_total': 166, - 'blocks': { + "R13x139": { + "version_indicator": 0b10101, + "height": 13, + "width": 139, + "remainder_bits": 0, + "character_count_length": 7, + "codewords_total": 166, + "blocks": { ErrorCorrectionLevel.M: [ { - 'num': 2, - 'c': 55, - 'k': 35, + "num": 2, + "c": 55, + "k": 35, }, { - 'num': 1, - 'c': 56, - 'k': 36, + "num": 1, + "c": 56, + "k": 36, }, ], ErrorCorrectionLevel.H: [ { - 'num': 2, - 'c': 41, - 'k': 13, + "num": 2, + "c": 41, + "k": 13, }, { - 'num': 2, - 'c': 42, - 'k': 14, + "num": 2, + "c": 42, + "k": 14, }, - ] - } + ], + }, }, - 'R15x43': { - 'version_indicator': 0b10110, - 'height': 15, - 'width': 43, - 'remainder_bits': 1, - 'character_count_length': 6, - 'codewords_total': 51, - 'blocks': { + "R15x43": { + "version_indicator": 0b10110, + "height": 15, + "width": 43, + "remainder_bits": 1, + "character_count_length": 6, + "codewords_total": 51, + "blocks": { ErrorCorrectionLevel.M: [ { - 'num': 1, - 'c': 51, - 'k': 33, + "num": 1, + "c": 51, + "k": 33, }, ], ErrorCorrectionLevel.H: [ { - 'num': 1, - 'c': 25, - 'k': 7, + "num": 1, + "c": 25, + "k": 7, }, { - 'num': 1, - 'c': 26, - 'k': 8, + "num": 1, + "c": 26, + "k": 8, }, - ] - } + ], + }, }, - 'R15x59': { - 'version_indicator': 0b10111, - 'height': 15, - 'width': 59, - 'remainder_bits': 4, - 'character_count_length': 6, - 'codewords_total': 74, - 'blocks': { + "R15x59": { + "version_indicator": 0b10111, + "height": 15, + "width": 59, + "remainder_bits": 4, + "character_count_length": 6, + "codewords_total": 74, + "blocks": { ErrorCorrectionLevel.M: [ { - 'num': 1, - 'c': 74, - 'k': 48, + "num": 1, + "c": 74, + "k": 48, }, ], ErrorCorrectionLevel.H: [ { - 'num': 2, - 'c': 37, - 'k': 13, + "num": 2, + "c": 37, + "k": 13, } - ] - } + ], + }, }, - 'R15x77': { - 'version_indicator': 0b11000, - 'height': 15, - 'width': 77, - 'remainder_bits': 6, - 'character_count_length': 7, - 'codewords_total': 103, - 'blocks': { + "R15x77": { + "version_indicator": 0b11000, + "height": 15, + "width": 77, + "remainder_bits": 6, + "character_count_length": 7, + "codewords_total": 103, + "blocks": { ErrorCorrectionLevel.M: [ { - 'num': 1, - 'c': 51, - 'k': 33, + "num": 1, + "c": 51, + "k": 33, }, { - 'num': 1, - 'c': 52, - 'k': 34, + "num": 1, + "c": 52, + "k": 34, }, ], ErrorCorrectionLevel.H: [ { - 'num': 2, - 'c': 34, - 'k': 10, + "num": 2, + "c": 34, + "k": 10, }, { - 'num': 1, - 'c': 35, - 'k': 11, + "num": 1, + "c": 35, + "k": 11, }, - ] - } + ], + }, }, - 'R15x99': { - 'version_indicator': 0b11001, - 'height': 15, - 'width': 99, - 'remainder_bits': 7, - 'character_count_length': 7, - 'codewords_total': 136, - 'blocks': { + "R15x99": { + "version_indicator": 0b11001, + "height": 15, + "width": 99, + "remainder_bits": 7, + "character_count_length": 7, + "codewords_total": 136, + "blocks": { ErrorCorrectionLevel.M: [ { - 'num': 2, - 'c': 68, - 'k': 44, + "num": 2, + "c": 68, + "k": 44, }, ], ErrorCorrectionLevel.H: [ { - 'num': 4, - 'c': 34, - 'k': 12, + "num": 4, + "c": 34, + "k": 12, }, ], - } + }, }, - 'R15x139': { - 'version_indicator': 0b11010, - 'height': 15, - 'width': 139, - 'remainder_bits': 2, - 'character_count_length': 7, - 'codewords_total': 199, - 'blocks': { + "R15x139": { + "version_indicator": 0b11010, + "height": 15, + "width": 139, + "remainder_bits": 2, + "character_count_length": 7, + "codewords_total": 199, + "blocks": { ErrorCorrectionLevel.M: [ { - 'num': 2, - 'c': 66, - 'k': 42, + "num": 2, + "c": 66, + "k": 42, }, { - 'num': 1, - 'c': 67, - 'k': 43, + "num": 1, + "c": 67, + "k": 43, }, ], ErrorCorrectionLevel.H: [ { - 'num': 1, - 'c': 39, - 'k': 13, + "num": 1, + "c": 39, + "k": 13, }, { - 'num': 4, - 'c': 40, - 'k': 14, + "num": 4, + "c": 40, + "k": 14, }, ], - } + }, }, - 'R17x43': { - 'version_indicator': 0b11011, - 'height': 17, - 'width': 43, - 'remainder_bits': 1, - 'character_count_length': 6, - 'codewords_total': 61, - 'blocks': { + "R17x43": { + "version_indicator": 0b11011, + "height": 17, + "width": 43, + "remainder_bits": 1, + "character_count_length": 6, + "codewords_total": 61, + "blocks": { ErrorCorrectionLevel.M: [ { - 'num': 1, - 'c': 60, - 'k': 39, + "num": 1, + "c": 60, + "k": 39, }, ], ErrorCorrectionLevel.H: [ { - 'num': 1, - 'c': 30, - 'k': 10, + "num": 1, + "c": 30, + "k": 10, }, { - 'num': 1, - 'c': 31, - 'k': 11, + "num": 1, + "c": 31, + "k": 11, }, - ] - } + ], + }, }, - 'R17x59': { - 'version_indicator': 0b11100, - 'height': 17, - 'width': 59, - 'remainder_bits': 2, - 'character_count_length': 6, - 'codewords_total': 88, - 'blocks': { + "R17x59": { + "version_indicator": 0b11100, + "height": 17, + "width": 59, + "remainder_bits": 2, + "character_count_length": 6, + "codewords_total": 88, + "blocks": { ErrorCorrectionLevel.M: [ { - 'num': 2, - 'c': 44, - 'k': 28, + "num": 2, + "c": 44, + "k": 28, }, ], ErrorCorrectionLevel.H: [ { - 'num': 2, - 'c': 44, - 'k': 14, + "num": 2, + "c": 44, + "k": 14, } - ] - } + ], + }, }, - 'R17x77': { - 'version_indicator': 0b11101, - 'height': 17, - 'width': 77, - 'remainder_bits': 0, - 'character_count_length': 7, - 'codewords_total': 122, - 'blocks': { + "R17x77": { + "version_indicator": 0b11101, + "height": 17, + "width": 77, + "remainder_bits": 0, + "character_count_length": 7, + "codewords_total": 122, + "blocks": { ErrorCorrectionLevel.M: [ { - 'num': 2, - 'c': 61, - 'k': 39, + "num": 2, + "c": 61, + "k": 39, }, ], ErrorCorrectionLevel.H: [ { - 'num': 1, - 'c': 40, - 'k': 12, + "num": 1, + "c": 40, + "k": 12, }, { - 'num': 2, - 'c': 41, - 'k': 13, + "num": 2, + "c": 41, + "k": 13, }, ], - } + }, }, - 'R17x99': { - 'version_indicator': 0b11110, - 'height': 17, - 'width': 99, - 'remainder_bits': 3, - 'character_count_length': 7, - 'codewords_total': 160, - 'blocks': { + "R17x99": { + "version_indicator": 0b11110, + "height": 17, + "width": 99, + "remainder_bits": 3, + "character_count_length": 7, + "codewords_total": 160, + "blocks": { ErrorCorrectionLevel.M: [ { - 'num': 2, - 'c': 53, - 'k': 33, + "num": 2, + "c": 53, + "k": 33, }, { - 'num': 1, - 'c': 54, - 'k': 34, - } + "num": 1, + "c": 54, + "k": 34, + }, ], ErrorCorrectionLevel.H: [ { - 'num': 4, - 'c': 40, - 'k': 14, + "num": 4, + "c": 40, + "k": 14, }, ], - } + }, }, - 'R17x139': { - 'version_indicator': 0b11111, - 'height': 17, - 'width': 139, - 'remainder_bits': 4, - 'character_count_length': 8, - 'codewords_total': 232, - 'blocks': { + "R17x139": { + "version_indicator": 0b11111, + "height": 17, + "width": 139, + "remainder_bits": 4, + "character_count_length": 8, + "codewords_total": 232, + "blocks": { ErrorCorrectionLevel.M: [ { - 'num': 4, - 'c': 58, - 'k': 38, + "num": 4, + "c": 58, + "k": 38, }, ], ErrorCorrectionLevel.H: [ { - 'num': 2, - 'c': 38, - 'k': 12, + "num": 2, + "c": 38, + "k": 12, }, { - 'num': 4, - 'c': 39, - 'k': 13, + "num": 4, + "c": 39, + "k": 13, }, ], - } + }, }, } diff --git a/src/rmqrcode/qr_image.py b/src/rmqrcode/qr_image.py index 31b1d07..f17d7b9 100644 --- a/src/rmqrcode/qr_image.py +++ b/src/rmqrcode/qr_image.py @@ -1,15 +1,13 @@ +from PIL import Image, ImageDraw + from .enums.color import Color -from PIL import Image -from PIL import ImageDraw class QRImage: def __init__(self, qr, module_size=10): self._module_size = module_size self._img = Image.new( - 'RGB', - ((qr.width() + 4) * module_size, (qr.height() + 4) * module_size), - (255, 255, 255) + "RGB", ((qr.width() + 4) * module_size, (qr.height() + 4) * module_size), (255, 255, 255) ) self._make_image(qr) @@ -28,7 +26,6 @@ def get_ndarray(self): def save(self, name): self._img.save(name) - def _make_image(self, qr): draw = ImageDraw.Draw(self._img) for y in range(qr.height()): @@ -37,8 +34,17 @@ def _make_image(self, qr): if qr.value_at(x, y) == Color.BLACK: r, g, b = 0, 0, 0 elif qr.value_at(x, y) == Color.WHITE: - r, g, b, = 255, 255, 255 + r, g, b, = ( + 255, + 255, + 255, + ) draw.rectangle( - xy=((x + 2) * self._module_size, (y + 2) * self._module_size, (x + 1 + 2) * self._module_size, (y + 1 + 2) * self._module_size), - fill=(r, g, b) - ) \ No newline at end of file + xy=( + (x + 2) * self._module_size, + (y + 2) * self._module_size, + (x + 1 + 2) * self._module_size, + (y + 1 + 2) * self._module_size, + ), + fill=(r, g, b), + ) diff --git a/src/rmqrcode/rmqrcode.py b/src/rmqrcode/rmqrcode.py index 466934b..0aa599f 100644 --- a/src/rmqrcode/rmqrcode.py +++ b/src/rmqrcode/rmqrcode.py @@ -1,17 +1,17 @@ -from .format.error_correction_level import ErrorCorrectionLevel -from .format.rmqr_versions import rMQRVersions -from .format.data_capacities import DataCapacities +import logging + +from .encoder.byte_encoder import ByteEncoder +from .enums.color import Color +from .enums.fit_strategy import FitStrategy from .format.alignment_pattern_coordinates import AlignmentPatternCoordinates +from .format.data_capacities import DataCapacities +from .format.error_correction_level import ErrorCorrectionLevel from .format.generator_polynomials import GeneratorPolynomials from .format.mask import mask - -from .encoder.byte_encoder import ByteEncoder +from .format.rmqr_versions import rMQRVersions from .util.error_correction import compute_bch, compute_reed_solomon from .util.utilities import split_into_8bits -from .enums.color import Color -from .enums.fit_strategy import FitStrategy -import logging class rMQR: @staticmethod @@ -22,9 +22,8 @@ def _init_logger(): logger.propagate = True return logger - @staticmethod - def fit(data,ecc=ErrorCorrectionLevel.M, fit_strategy=FitStrategy.BALANCED): + def fit(data, ecc=ErrorCorrectionLevel.M, fit_strategy=FitStrategy.BALANCED): logger = rMQR._init_logger() data_length = ByteEncoder.length(data) @@ -34,35 +33,45 @@ def fit(data,ecc=ErrorCorrectionLevel.M, fit_strategy=FitStrategy.BALANCED): logger.debug("Select rMQR Code version") for version_name, qr_version in DataCapacities.items(): - if data_length <= qr_version['capacity']['Byte'][ecc]: - width, height = qr_version['width'], qr_version['height'] - if not width in determined_width and not height in determined_height: + if data_length <= qr_version["capacity"]["Byte"][ecc]: + width, height = qr_version["width"], qr_version["height"] + if width not in determined_width and height not in determined_height: determined_width.add(width) determined_height.add(height) - ok_versions.append({ - 'version': version_name, - 'width': width, - 'height': height, - }) + ok_versions.append( + { + "version": version_name, + "width": width, + "height": height, + } + ) logger.debug(f"ok: {version_name}") if len(ok_versions) == 0: raise DataTooLongError("The data is too long.") if fit_strategy == FitStrategy.MINIMIZE_WIDTH: - sort_key = lambda x: x['width'] + + def sort_key(x): + return x["width"] + elif fit_strategy == FitStrategy.MINIMIZE_HEIGHT: - sort_key = lambda x: x['height'] + + def sort_key(x): + return x["height"] + elif fit_strategy == FitStrategy.BALANCED: - sort_key = lambda x: x['height'] * 9 + x['width'] + + def sort_key(x): + return x["height"] * 9 + x["width"] + selected = sorted(ok_versions, key=sort_key)[0] logger.debug(f"selected: {selected}") - qr = rMQR(selected['version'], ecc) + qr = rMQR(selected["version"], ecc) qr.make(data) return qr - def __init__(self, version, ecc, logger=None): self._logger = logger or rMQR._init_logger() @@ -71,46 +80,38 @@ def __init__(self, version, ecc, logger=None): qr_version = rMQRVersions[version] self._version = version - self._height = qr_version['height'] - self._width = qr_version['width'] + self._height = qr_version["height"] + self._width = qr_version["width"] self._error_correction_level = ecc self._qr = [[Color.UNDEFINED for x in range(self._width)] for y in range(self._height)] - def make(self, data): self._put_finder_pattern() self._put_corner_finder_pattern() self._put_alignment_pattern() self._put_timing_pattern() self._put_version_information() - mask_area = self._put_data(data); + mask_area = self._put_data(data) self._apply_mask(mask_area) - def version_name(self): return f"R{self._height}x{self._width}" - def size(self): return (self.width(), self.height()) - def height(self): return self._height - def width(self): return self._width - def value_at(self, x, y): return self._qr[y][x] - def to_list(self): return [list(map(lambda x: 1 if x == Color.BLACK else 0, column)) for column in self._qr] - def __str__(self): res = "" @@ -131,7 +132,6 @@ def __str__(self): res += "\n" return res - def _put_finder_pattern(self): # Finder pattern # Outer square @@ -145,7 +145,7 @@ def _put_finder_pattern(self): # Inner square for i in range(3): for j in range(3): - self._qr[2+i][2+j] = Color.BLACK + self._qr[2 + i][2 + j] = Color.BLACK # Separator for n in range(8): @@ -160,29 +160,27 @@ def _put_finder_pattern(self): for i in range(5): for j in range(5): color = Color.BLACK if i == 0 or i == 4 or j == 0 or j == 4 else Color.WHITE - self._qr[self._height-i-1][self._width-j-1] = color + self._qr[self._height - i - 1][self._width - j - 1] = color # Inner square - self._qr[self._height-1-2][self._width-1-2] = Color.BLACK - + self._qr[self._height - 1 - 2][self._width - 1 - 2] = Color.BLACK def _put_corner_finder_pattern(self): # Corner finder pattern # Bottom left - self._qr[self._height-1][0] = Color.BLACK - self._qr[self._height-1][1] = Color.BLACK - self._qr[self._height-1][2] = Color.BLACK + self._qr[self._height - 1][0] = Color.BLACK + self._qr[self._height - 1][1] = Color.BLACK + self._qr[self._height - 1][2] = Color.BLACK if self._height >= 11: - self._qr[self._height-2][0] = Color.BLACK - self._qr[self._height-2][1] = Color.WHITE + self._qr[self._height - 2][0] = Color.BLACK + self._qr[self._height - 2][1] = Color.WHITE # Top right - self._qr[0][self._width-1] = Color.BLACK - self._qr[0][self._width-2] = Color.BLACK - self._qr[1][self._width-1] = Color.BLACK - self._qr[1][self._width-2] = Color.WHITE - + self._qr[0][self._width - 1] = Color.BLACK + self._qr[0][self._width - 2] = Color.BLACK + self._qr[1][self._width - 1] = Color.BLACK + self._qr[1][self._width - 2] = Color.WHITE def _put_alignment_pattern(self): # Alignment pattern @@ -194,8 +192,7 @@ def _put_alignment_pattern(self): # Top side self._qr[i][center_x + j - 1] = color # Bottom side - self._qr[self._height-1-i][center_x + j - 1] = color - + self._qr[self._height - 1 - i][center_x + j - 1] = color def _put_timing_pattern(self): # Timing pattern @@ -215,13 +212,11 @@ def _put_timing_pattern(self): if self._qr[i][j] == Color.UNDEFINED: self._qr[i][j] = color - def _put_version_information(self): version_information = self._compute_version_info() self._put_version_information_finder_pattern_side(version_information) self._put_version_information_finder_sub_pattern_side(version_information) - def _put_version_information_finder_pattern_side(self, version_information): mask = 0b011111101010110010 version_information ^= mask @@ -230,8 +225,7 @@ def _put_version_information_finder_pattern_side(self, version_information): for n in range(18): di = n % 5 dj = n // 5 - self._qr[si+di][sj+dj] = Color.BLACK if version_information>>n & 1 else Color.WHITE - + self._qr[si + di][sj + dj] = Color.BLACK if version_information >> n & 1 else Color.WHITE def _put_version_information_finder_sub_pattern_side(self, version_information): mask = 0b100000101001111011 @@ -241,27 +235,31 @@ def _put_version_information_finder_sub_pattern_side(self, version_information): for n in range(15): di = n % 5 dj = n // 5 - self._qr[si+di][sj+dj] = Color.BLACK if version_information>>n & 1 else Color.WHITE - self._qr[self._height-1-5][self._width-1-4] = Color.BLACK if version_information>>15 & 1 else Color.WHITE - self._qr[self._height-1-5][self._width-1-3] = Color.BLACK if version_information>>16 & 1 else Color.WHITE - self._qr[self._height-1-5][self._width-1-2] = Color.BLACK if version_information>>17 & 1 else Color.WHITE - + self._qr[si + di][sj + dj] = Color.BLACK if version_information >> n & 1 else Color.WHITE + self._qr[self._height - 1 - 5][self._width - 1 - 4] = ( + Color.BLACK if version_information >> 15 & 1 else Color.WHITE + ) + self._qr[self._height - 1 - 5][self._width - 1 - 3] = ( + Color.BLACK if version_information >> 16 & 1 else Color.WHITE + ) + self._qr[self._height - 1 - 5][self._width - 1 - 2] = ( + Color.BLACK if version_information >> 17 & 1 else Color.WHITE + ) def _compute_version_info(self): qr_version = rMQRVersions[self.version_name()] - version_information_data = qr_version['version_indicator'] + version_information_data = qr_version["version_indicator"] if self._error_correction_level == ErrorCorrectionLevel.H: - version_information_data |= 1<<6 + version_information_data |= 1 << 6 reminder_polynomial = compute_bch(version_information_data) - version_information_data = version_information_data<<12 | reminder_polynomial + version_information_data = version_information_data << 12 | reminder_polynomial return version_information_data - def _put_data(self, data): qr_version = rMQRVersions[self.version_name()] - character_count_length = qr_version['character_count_length'] - codewords_total = qr_version['codewords_total'] + character_count_length = qr_version["character_count_length"] + codewords_total = qr_version["codewords_total"] encoded_data = self._convert_to_bites_data(data, character_count_length, codewords_total) codewords = split_into_8bits(encoded_data) @@ -278,8 +276,7 @@ def _put_data(self, data): codewords.append("00010001") data_codewords_per_block, rs_codewords_per_block = self._split_into_blocks( - codewords, - qr_version['blocks'][self._error_correction_level] + codewords, qr_version["blocks"][self._error_correction_level] ) # Construct the final message codeword sequence @@ -301,15 +298,15 @@ def _put_data(self, data): self._logger.debug(f"Put RS data codewords {i} : {rs_codewords[i]}") # Codeword placement - dy = -1 # Up + dy = -1 # Up current_codeword_idx = 0 current_bit_idx = 0 cx, cy = self._width - 2, self._height - 6 - remainder_bits = qr_version['remainder_bits'] + remainder_bits = qr_version["remainder_bits"] mask_area = [[False for i in range(self._width)] for j in range(self._height)] while True: - for x in [cx, cx-1]: + for x in [cx, cx - 1]: if self._qr[cy][x] == Color.UNDEFINED: # Process only empty cell if current_codeword_idx == len(final_codewords): @@ -319,7 +316,11 @@ def _put_data(self, data): remainder_bits -= 1 else: # Codewords - self._qr[cy][x] = Color.BLACK if final_codewords[current_codeword_idx][current_bit_idx] == '1' else Color.WHITE + self._qr[cy][x] = ( + Color.BLACK + if final_codewords[current_codeword_idx][current_bit_idx] == "1" + else Color.WHITE + ) mask_area[cy][x] = True current_bit_idx += 1 if current_bit_idx == 8: @@ -344,15 +345,14 @@ def _put_data(self, data): return mask_area - def _split_into_blocks(self, codewords, blocks_definition): data_idx, error_idx = 0, 0 data_codewords_per_block = [] rs_codewords_per_block = [] for block_definition in blocks_definition: - for i in range(block_definition['num']): - data_codewords_num = block_definition['k'] - rs_codewords_num = block_definition['c'] - block_definition['k'] + for i in range(block_definition["num"]): + data_codewords_num = block_definition["k"] + rs_codewords_num = block_definition["c"] - block_definition["k"] g = GeneratorPolynomials[rs_codewords_num] codewords_in_block = codewords[data_idx : data_idx + data_codewords_num] @@ -366,7 +366,6 @@ def _split_into_blocks(self, codewords, blocks_definition): return data_codewords_per_block, rs_codewords_per_block - def _convert_to_bites_data(self, data, character_count_length, codewords_total): encoded_data = ByteEncoder.encode(data, character_count_length) @@ -376,7 +375,6 @@ def _convert_to_bites_data(self, data, character_count_length, codewords_total): return encoded_data - def _apply_mask(self, mask_area): for y in range(self._height): for x in range(self._width): @@ -388,7 +386,6 @@ def _apply_mask(self, mask_area): elif self._qr[y][x] == Color.WHITE: self._qr[y][x] = Color.BLACK - @staticmethod def validate_version(version_name): return version_name in rMQRVersions @@ -399,4 +396,4 @@ class DataTooLongError(ValueError): class IllegalVersionError(ValueError): - pass \ No newline at end of file + pass diff --git a/src/rmqrcode/util/error_correction.py b/src/rmqrcode/util/error_correction.py index a3b47de..14943a5 100644 --- a/src/rmqrcode/util/error_correction.py +++ b/src/rmqrcode/util/error_correction.py @@ -1,12 +1,13 @@ -from .utilities import msb, to_binary from .galois_fields import GaloisFields +from .utilities import msb, to_binary + def compute_bch(data): data <<= 12 - g = 1<<12 | 1<<11 | 1<<10 | 1<<9 | 1<<8 | 1<<5 | 1<<2 | 1<<0 + g = 1 << 12 | 1 << 11 | 1 << 10 | 1 << 9 | 1 << 8 | 1 << 5 | 1 << 2 | 1 << 0 tmp_data = data - while (msb(tmp_data) >= 13): + while msb(tmp_data) >= 13: multiple = msb(tmp_data) - 13 tmp_g = g << multiple tmp_data ^= tmp_g @@ -14,6 +15,8 @@ def compute_bch(data): gf = GaloisFields() + + def compute_reed_solomon(data, g, num_error_codewords): f = list(map(lambda x: int(x, 2), data)) @@ -21,13 +24,14 @@ def compute_reed_solomon(data, g, num_error_codewords): f.append(0) for i in range(len(data)): - if f[i] == 0: continue + if f[i] == 0: + continue mult = gf.i2e[f[i]] for j in range(len(g)): - f[i+j] ^= gf.e2i[(g[j]+mult)%255] + f[i + j] ^= gf.e2i[(g[j] + mult) % 255] rs_codewords = [] for i in range(num_error_codewords): rs_codewords.append(to_binary(f[-num_error_codewords + i], 8)) - return rs_codewords \ No newline at end of file + return rs_codewords diff --git a/src/rmqrcode/util/galois_fields.py b/src/rmqrcode/util/galois_fields.py index 6b3c076..4a0cdf7 100644 --- a/src/rmqrcode/util/galois_fields.py +++ b/src/rmqrcode/util/galois_fields.py @@ -5,7 +5,7 @@ class GaloisFields: def __init__(self): # Irreducible polynomial in GF(2^8) - p = (1<<8)|(1<<4)|(1<<3)|(1<<2)|1 + p = (1 << 8) | (1 << 4) | (1 << 3) | (1 << 2) | 1 self.e2i[0] = 1 self.e2i[255] = 1 @@ -15,7 +15,7 @@ def __init__(self): tmp = 1 for e in range(1, 255): tmp <<= 1 - if tmp & (1<<8): + if tmp & (1 << 8): tmp ^= p self.e2i[e] = tmp self.i2e[tmp] = e diff --git a/src/rmqrcode/util/utilities.py b/src/rmqrcode/util/utilities.py index 8de88ac..1f4f4c4 100644 --- a/src/rmqrcode/util/utilities.py +++ b/src/rmqrcode/util/utilities.py @@ -8,9 +8,9 @@ def to_binary(data, len): def split_into_8bits(data): codewords = [] - while (len(data) >= 8): + while len(data) >= 8: codewords.append(data[:8]) data = data[8:] if data != "": - codewords.append(data.ljust(8, '0')) - return codewords \ No newline at end of file + codewords.append(data.ljust(8, "0")) + return codewords