import numpy as np
from PIL import Image
import qrcode
from reedsolo import RSCodec, ReedSolomonError
def is_function_or_quiet_zone(i, j, size):
# Finder patterns
if (i <= 7 and j <= 7) or \
(i <= 7 and j >= size - 8) or \
(i >= size - 8 and j <= 7):
return True
# Timing patterns
if (i == 6 and 8 <= j < size - 8) or (j == 6 and 8 <= i < size - 8):
return True
# Alignment patterns
if(i >= 28 and i <= 32 and j >= 28 and j <= 32):
return True
return False
def is_central_region(i, j, size):
start = 9
end = 29
if start <= i <= end and start <= j <= end:
return True
return False
def id_to_rs_binary_blocks(id_str, ecc_symbols=16):
# 验证输入是ASCII字符串
if not all(32 <= ord(c) < 128 for c in id_str):
raise ValueError("ID contains non-ASCII characters")
# 创建Reed-Solomon编码器
rsc = RSCodec(ecc_symbols)
# 编码字符串(转换为字节并添加纠错码)
encoded_data = rsc.encode(id_str.encode('ascii'))
# 转换为二进制字符串
binary_str = ''.join(format(byte, '08b') for byte in encoded_data)
# 分割为7位一组的块
binary_blocks = []
for i in range(0, len(binary_str), 7):
block = binary_str[i:i+7]
# 不足7位则填充0
block = block.ljust(7, '0')
binary_blocks.append(block)
return binary_blocks, encoded_data, binary_str
def generate_qr_matrix(data, version, error_correction=qrcode.constants.ERROR_CORRECT_L):
qr = qrcode.QRCode(
version=version,
error_correction=error_correction,
box_size=10,
border=0,
)
qr.add_data(data)
qr.make(fit=True)
img = qr.make_image(fill_color="black", back_color="white")
return np.array(qr.get_matrix(), dtype=int), img
def matrix_to_image(matrix, scale=10):
size = len(matrix)
img = Image.new('1', (size*scale, size*scale), 255) # 初始化为白色
pixels = img.load()
for i in range(size):
for j in range(size):
color = 0 if matrix[i][j] == 1 else 255 # 1=黑色, 0=白色
for x in range(scale):
for y in range(scale):
pixels[j*scale + x, i*scale + y] = color
return img
def generate_qr_with_embedded_id(data, id_str, version=6):
# 生成原始QR码
original_matrix, _ = generate_qr_matrix(data, version)
size = len(original_matrix)
# 将ID转换为二进制块
binary_blocks, _, _ = id_to_rs_binary_blocks(id_str)
total_blocks = len(binary_blocks)
print(f"ID编码后总块数: {total_blocks} (每块7位)")
# 统计中央区域可用模块数
available_blocks = 0
for i in range(size):
for j in range(size):
if is_central_region(i, j, size) and not is_function_or_quiet_zone(i, j, size):
available_blocks += 1
print(f"中央区域可用模块数: {available_blocks}")
if total_blocks > available_blocks:
raise ValueError(f"ID数据太大! 需要 {total_blocks} 个模块, 但只有 {available_blocks} 个可用")
# 创建扩展矩阵 (3倍大小)
new_size = size * 3
new_matrix = np.zeros((new_size, new_size), dtype=int) + 1 # 初始化为白色(1)
# 第一遍:处理所有模块,创建基本3x3结构
for i in range(size):
for j in range(size):
start_i, start_j = i*3, j*3
pixel_val = original_matrix[i, j]
# 中心子模块使用原始颜色
new_matrix[start_i+1, start_j+1] = pixel_val
# 周围8个子模块使用相反颜色
opposite_val = 1 - pixel_val
for dx in range(3):
for dy in range(3):
if not (dx == 1 and dy == 1): # 排除中心点
new_matrix[start_i+dx, start_j+dy] = opposite_val
# 第二遍:在中央区域嵌入数据
block_index = 0
for i in range(size):
for j in range(size):
if not is_central_region(i, j, size):
continue
if is_function_or_quiet_zone(i, j, size):
continue
if block_index >= total_blocks:
break
start_i, start_j = i*3, j*3
current_block = binary_blocks[block_index]
block_index += 1
# 定义7个嵌入位置 (排除中心点和左上角)
embed_positions = [
(0, 1), (0, 2), # 上中,右上
(1, 0), (1, 2), # 左中,右中
(2, 0), (2, 1), (2, 2) # 左下,下中,右下
]
# 嵌入7位数据
for bit_idx, (dx, dy) in enumerate(embed_positions):
bit_val = int(current_block[bit_idx])
new_matrix[start_i+dx, start_j+dy] = bit_val
print(f"成功嵌入 {block_index} 个数据块 ({block_index * 7} 位)")
return new_matrix, matrix_to_image(new_matrix, scale=3) # scale=3保持子模块大小
# 主流程
if __name__ == "__main__":
# 配置参数
data_to_encode = "volvo-volvo-volvo-volvo" # QR码包含的数据
device_id = "5B13D3D3-2921-40A1-A24C-BE8302E0F95A" # 设备ID
qr_version = 5 # QR码版本
# 生成带嵌入ID的QR码
embedded_matrix, embedded_img = generate_qr_with_embedded_id(
data_to_encode,
device_id,
qr_version
)
# 保存生成的QR码
embedded_img.save("embedded_qr.png")
print("已保存嵌入ID的QR码: embedded_qr.png")
# 显示生成的QR码
embedded_img.show()
在以下部分,只对is_function_or_quiet_zone以外的部分进行处理
# 第一遍:处理所有模块,创建基本3x3结构
for i in range(size):
for j in range(size):
start_i, start_j = i*3, j*3
pixel_val = original_matrix[i, j]
# 中心子模块使用原始颜色
new_matrix[start_i+1, start_j+1] = pixel_val
# 周围8个子模块使用相反颜色
opposite_val = 1 - pixel_val
for dx in range(3):
for dy in range(3):
if not (dx == 1 and dy == 1): # 排除中心点
new_matrix[start_i+dx, start_j+dy] = opposite_val
最新发布