diff --git a/README.md b/README.md index 8c4e63f..6c054d1 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,8 @@ This is an rMQR Code image generator implemented in Python. This is implemented ## 📌 Important Notice -Please verify an image generated by this software whether it can decode correctly before use. - +- Please verify an image generated by this software whether it can decode correctly before use. +- Because this is in early stage, QR Code readers may have not been supported rMQR Code yet. ## 🚀 Installation ``` diff --git a/setup.cfg b/setup.cfg index bdb177a..ada13c1 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = rmqrcode -version = 0.1.2 +version = 0.1.3 author = Takahiro Tomita author_email = ttp8101@gmail.com description = An rMQR Code Generetor diff --git a/src/rmqrcode/console.py b/src/rmqrcode/console.py index 8e0324d..aa1117e 100644 --- a/src/rmqrcode/console.py +++ b/src/rmqrcode/console.py @@ -53,17 +53,18 @@ def main(): elif args.fit_strategy == 'min_height': fit_strategy = FitStrategy.MINIMIZE_HEIGHT - qr = _make_qr( - args.DATA, - ecc=ecc, - version=args.version, - fit_strategy=fit_strategy - ) + try: + 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.") _save_image(qr, args.OUTPUT) - print(f"{qr}") - def _init_argparser(): parser = argparse.ArgumentParser() diff --git a/src/rmqrcode/format/data_capacities.py b/src/rmqrcode/format/data_capacities.py index 7cb8541..58b3739 100644 --- a/src/rmqrcode/format/data_capacities.py +++ b/src/rmqrcode/format/data_capacities.py @@ -2,7 +2,7 @@ # ISO/IEC 23941:2022 Table 6 -data_capacities = { +DataCapacities = { 'R7x43': { 'height': 7, 'width': 43, diff --git a/src/rmqrcode/format/qr_versions.py b/src/rmqrcode/format/rmqr_versions.py similarity index 99% rename from src/rmqrcode/format/qr_versions.py rename to src/rmqrcode/format/rmqr_versions.py index 1c29e8a..2bc9232 100644 --- a/src/rmqrcode/format/qr_versions.py +++ b/src/rmqrcode/format/rmqr_versions.py @@ -1,7 +1,7 @@ from .error_correction_level import ErrorCorrectionLevel -qr_versions = { +rMQRVersions = { 'R7x43': { 'version_indicator': 0b00000, 'height': 7, diff --git a/src/rmqrcode/rmqrcode.py b/src/rmqrcode/rmqrcode.py index 87ab1c2..466934b 100644 --- a/src/rmqrcode/rmqrcode.py +++ b/src/rmqrcode/rmqrcode.py @@ -1,6 +1,6 @@ from .format.error_correction_level import ErrorCorrectionLevel -from .format.qr_versions import qr_versions -from .format.data_capacities import data_capacities +from .format.rmqr_versions import rMQRVersions +from .format.data_capacities import DataCapacities from .format.alignment_pattern_coordinates import AlignmentPatternCoordinates from .format.generator_polynomials import GeneratorPolynomials from .format.mask import mask @@ -33,7 +33,7 @@ def fit(data,ecc=ErrorCorrectionLevel.M, fit_strategy=FitStrategy.BALANCED): determined_height = set() logger.debug("Select rMQR Code version") - for version_name, qr_version in data_capacities.items(): + 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: @@ -69,7 +69,7 @@ def __init__(self, version, ecc, logger=None): if not rMQR.validate_version(version): raise IllegalVersionError("The rMQR version is illegal.") - qr_version = qr_versions[version] + qr_version = rMQRVersions[version] self._version = version self._height = qr_version['height'] self._width = qr_version['width'] @@ -134,7 +134,7 @@ def __str__(self): def _put_finder_pattern(self): # Finder pattern - # 周囲 + # Outer square for i in range(7): for j in range(7): if i == 0 or i == 6 or j == 0 or j == 6: @@ -142,7 +142,7 @@ def _put_finder_pattern(self): else: self._qr[i][j] = Color.WHITE - # 真ん中 + # Inner square for i in range(3): for j in range(3): self._qr[2+i][2+j] = Color.BLACK @@ -156,19 +156,19 @@ def _put_finder_pattern(self): self._qr[7][n] = Color.WHITE # Finder sub pattern - # 周囲 + # Outer square 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 - # 真ん中 + # Inner square 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 @@ -177,7 +177,7 @@ def _put_corner_finder_pattern(self): 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 @@ -191,22 +191,22 @@ def _put_alignment_pattern(self): for i in range(3): for j in range(3): color = Color.BLACK if i == 0 or i == 2 or j == 0 or j == 2 else Color.WHITE - # 上側 + # Top side self._qr[i][center_x + j - 1] = color - # 下側 + # Bottom side self._qr[self._height-1-i][center_x + j - 1] = color def _put_timing_pattern(self): # Timing pattern - # 横 + # Horizontal for j in range(self._width): color = Color.BLACK if (j + 1) % 2 else Color.WHITE for i in [0, self._height - 1]: if self._qr[i][j] == Color.UNDEFINED: self._qr[i][j] = color - # 縦 + # Vertical center_xs = [0, self._width - 1] center_xs.extend(AlignmentPatternCoordinates[self._width]) for i in range(self._height): @@ -248,7 +248,7 @@ def _put_version_information_finder_sub_pattern_side(self, version_information): def _compute_version_info(self): - qr_version = qr_versions[self.version_name()] + qr_version = rMQRVersions[self.version_name()] version_information_data = qr_version['version_indicator'] if self._error_correction_level == ErrorCorrectionLevel.H: version_information_data |= 1<<6 @@ -258,14 +258,17 @@ def _compute_version_info(self): def _put_data(self, data): - qr_version = qr_versions[self.version_name()] + qr_version = rMQRVersions[self.version_name()] 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) - # codeword数に満たない場合は規定の文字列を付与する + if len(codewords) > codewords_total: + raise DataTooLongError("The data is too long.") + + # Add the remainder codewords while True: if len(codewords) >= codewords_total: break @@ -279,7 +282,7 @@ def _put_data(self, data): qr_version['blocks'][self._error_correction_level] ) - # データの並び替え + # Construct the final message codeword sequence # Data codewords final_codewords = [] for i in range(len(data_codewords_per_block[-1])): @@ -297,8 +300,8 @@ def _put_data(self, data): final_codewords.append(rs_codewords[i]) self._logger.debug(f"Put RS data codewords {i} : {rs_codewords[i]}") - # 配置 - dy = -1 # 最初は上方向 + # Codeword placement + dy = -1 # Up current_codeword_idx = 0 current_bit_idx = 0 cx, cy = self._width - 2, self._height - 6 @@ -308,14 +311,14 @@ def _put_data(self, data): while True: for x in [cx, cx-1]: if self._qr[cy][x] == Color.UNDEFINED: - # 空白のセルのみ処理する + # Process only empty cell if current_codeword_idx == len(final_codewords): - # codewordsを配置しきった場合はremainder_bitsがあれば配置する + # Remainder bits self._qr[cy][x] = Color.WHITE mask_area[cy][x] = True remainder_bits -= 1 else: - # codewordsを配置する + # Codewords 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 @@ -323,15 +326,13 @@ def _put_data(self, data): current_bit_idx = 0 current_codeword_idx += 1 - # codewordsの配置が終わりremainder_bitsも残っていなければ終了 if current_codeword_idx == len(final_codewords) and remainder_bits == 0: break - # codewordsの配置が終わりremainder_bitsも残っていなければ終了 if current_codeword_idx == len(final_codewords) and remainder_bits == 0: break - # 座標の更新 + # Update current coordinates if dy < 0 and cy == 1: cx -= 2 dy = 1 @@ -369,7 +370,7 @@ def _split_into_blocks(self, codewords, blocks_definition): def _convert_to_bites_data(self, data, character_count_length, codewords_total): encoded_data = ByteEncoder.encode(data, character_count_length) - # 付加できるなら終端文字を付け加える + # Terminator (may be truncated) if len(encoded_data) + 3 <= codewords_total * 8: encoded_data += "000" @@ -390,7 +391,7 @@ def _apply_mask(self, mask_area): @staticmethod def validate_version(version_name): - return version_name in qr_versions + return version_name in rMQRVersions class DataTooLongError(ValueError): diff --git a/src/rmqrcode/util/galois_fields.py b/src/rmqrcode/util/galois_fields.py index c23e210..6b3c076 100644 --- a/src/rmqrcode/util/galois_fields.py +++ b/src/rmqrcode/util/galois_fields.py @@ -4,7 +4,7 @@ class GaloisFields: i2e = {} def __init__(self): - # GF(2^8)の既約多項式 + # Irreducible polynomial in GF(2^8) p = (1<<8)|(1<<4)|(1<<3)|(1<<2)|1 self.e2i[0] = 1