def test_thonky_add_version_info(): # <http://www.thonky.com/qr-code-tutorial/format-version-information> version = 7 matrix = encoder.make_matrix(version, reserve_regions=False) encoder.add_finder_patterns(matrix, is_micro=False) encoder.add_alignment_patterns(matrix, version) encoder.add_version_info(matrix, version) matrix[-8][8] = 0x1 # dark module ref_matrix = read_matrix('thonky_version') assert ref_matrix == matrix
def matrix_iter_detail(matrix, version, scale=1, border=None): """\ Returns an iterator / generator over the provided matrix which includes the border and the scaling factor. This iterator / generator returns different values for dark / light modules and therefor the different parts (like the finder patterns, alignment patterns etc.) are distinguishable. If this information isn't necessary, use the :py:func:`matrix_iter()` function because it is much cheaper and faster. If either the `scale` or `border` value is invalid, a py:exc:`ValueError` is raised. :param matrix: An iterable of bytearrays. :param int version: A version constant. :param int scale: The scaling factor (default: ``1``). :param int border: The border size or ``None`` to specify the default quiet zone (4 for QR Codes, 2 for Micro QR Codes). :raises: :py:exc:`ValueError` if an illegal scale or border value is provided """ from segno import encoder check_valid_border(border) scale = int(scale) check_valid_scale(scale) border = get_border(version, border) width, height = get_symbol_size(version, scale=1, border=0) is_micro = version < 1 # Create an empty matrix with invalid 0x2 values alignment_matrix = encoder.make_matrix(version, reserve_regions=False, add_timing=False) encoder.add_alignment_patterns(alignment_matrix, version) def get_bit(i, j): # Check if we operate upon the matrix or the "virtual" border if 0 <= i < height and 0 <= j < width: val = matrix[i][j] if not is_micro: # Alignment pattern alignment_val = alignment_matrix[i][j] if alignment_val != 0x2: return (TYPE_ALIGNMENT_PATTERN_LIGHT, TYPE_ALIGNMENT_PATTERN_DARK)[alignment_val] if version > 6: # Version information if i < 6 and width - 12 < j < width - 8 \ or height - 12 < i < height - 8 and j < 6: return (TYPE_VERSION_LIGHT, TYPE_VERSION_DARK)[val] # Dark module if i == height - 8 and j == 8: return TYPE_DARKMODULE # Timing - IMPORTANT: Check alignment (see above) in advance! if not is_micro and ((i == 6 and j > 7 and j < width - 8) or (j == 6 and i > 7 and i < height - 8)) \ or is_micro and (i == 0 and j > 7 or j == 0 and i > 7): return (TYPE_TIMING_LIGHT, TYPE_TIMING_DARK)[val] # Format - IMPORTANT: Check timing (see above) in advance! if i == 8 and (j < 9 or (not is_micro and j > width - 10)) \ or j == 8 and (i < 8 or not is_micro and i > height - 9): return (TYPE_FORMAT_LIGHT, TYPE_FORMAT_DARK)[val] # Finder pattern # top left top right if i < 7 and (j < 7 or (not is_micro and j > width - 8)) \ or not is_micro and i > height - 8 and j < 7: # bottom left return (TYPE_FINDER_PATTERN_LIGHT, TYPE_FINDER_PATTERN_DARK)[val] # Separator # top left top right if i < 8 and (j < 8 or (not is_micro and j > width - 9)) \ or not is_micro and (i > height - 9 and j < 8): # bottom left return TYPE_SEPARATOR return (TYPE_DATA_LIGHT, TYPE_DATA_DARK)[val] else: return TYPE_QUIET_ZONE for i in range(-border, height + border): for s in range(scale): yield chain.from_iterable(([get_bit(i, j)] * scale for j in range(-border, width + border)))
def matrix_iter_verbose(matrix, version, scale=1, border=None): """\ Returns an iterator / generator over the provided matrix which includes the border and the scaling factor. This iterator / generator returns different values for dark / light modules and therefor the different parts (like the finder patterns, alignment patterns etc.) are distinguishable. If this information isn't necessary, use the :py:func:`matrix_iter()` function because it is much cheaper and faster. If either the `scale` or `border` value is invalid, a py:exc:`ValueError` is raised. :param matrix: An iterable of bytearrays. :param int version: A version constant. :param int scale: The scaling factor (default: ``1``). :param int border: The border size or ``None`` to specify the default quiet zone (4 for QR Codes, 2 for Micro QR Codes). :raises: :py:exc:`ValueError` if an illegal scale or border value is provided """ from segno import encoder check_valid_border(border) scale = int(scale) check_valid_scale(scale) border = get_border(version, border) width, height = get_symbol_size(version, scale=1, border=0) is_micro = version < 1 # Create an empty matrix with invalid 0x2 values alignment_matrix = encoder.make_matrix(version, reserve_regions=False, add_timing=False) encoder.add_alignment_patterns(alignment_matrix, version) def get_bit(i, j): # Check if we operate upon the matrix or the "virtual" border if 0 <= i < height and 0 <= j < width: val = matrix[i][j] if not is_micro: # Alignment pattern alignment_val = alignment_matrix[i][j] if alignment_val != 0x2: return (consts.TYPE_ALIGNMENT_PATTERN_LIGHT, consts.TYPE_ALIGNMENT_PATTERN_DARK)[alignment_val] if version > 6: # Version information if i < 6 and width - 12 < j < width - 8 \ or height - 12 < i < height - 8 and j < 6: return (consts.TYPE_VERSION_LIGHT, consts.TYPE_VERSION_DARK)[val] # Dark module if i == height - 8 and j == 8: return consts.TYPE_DARKMODULE # Timing - IMPORTANT: Check alignment (see above) in advance! if not is_micro and ((i == 6 and 7 < j < width - 8) or (j == 6 and 7 < i < height - 8)) \ or is_micro and (i == 0 and j > 7 or j == 0 and i > 7): return (consts.TYPE_TIMING_LIGHT, consts.TYPE_TIMING_DARK)[val] # Format - IMPORTANT: Check timing (see above) in advance! if i == 8 and (j < 9 or (not is_micro and j > width - 10)) \ or j == 8 and (i < 8 or not is_micro and i > height - 9): return (consts.TYPE_FORMAT_LIGHT, consts.TYPE_FORMAT_DARK)[val] # Finder pattern # top left top right if i < 7 and (j < 7 or (not is_micro and j > width - 8)) \ or not is_micro and i > height - 8 and j < 7: # bottom left return (consts.TYPE_FINDER_PATTERN_LIGHT, consts.TYPE_FINDER_PATTERN_DARK)[val] # Separator # top left top right if i < 8 and (j < 8 or (not is_micro and j > width - 9)) \ or not is_micro and (i > height - 9 and j < 8): # bottom left return consts.TYPE_SEPARATOR return (consts.TYPE_DATA_LIGHT, consts.TYPE_DATA_DARK)[val] else: return consts.TYPE_QUIET_ZONE size_range = range(-border, width + border) for i in size_range: row = tuple( chain.from_iterable( repeat(get_bit(i, j), scale) for j in size_range)) for s in repeat(None, scale): yield row