暂且利用qrcode三方库来生成二维码,通过灰度处理以及位处理来生成可以直接发送到打印机执行打印的指令。
import qrcode
from PIL import Image
def str_to_send_data(content: str, page_width: int = 576) -> str:
"""
使用光栅图方式打印二维码
:param page_width: 打印页面宽度 576点阵/行
:param content: 二维码内容
:return 转换完成的十六进制指令
"""
# 创建二维码
img: Image.Image = qrcode.make(
content,
# 一个1到40之间的整数,用于控制 QR 码的大小(最小的版本1是一个21x21矩阵)。默认为None,表示代码自动确认该参数。
# https://blog.csdn.net/parasoft/article/details/84787173
version=None,
# 大约可以纠正 30% 或更少的错误
error_correction=qrcode.constants.ERROR_CORRECT_H,
# 控制二维码的每个“盒子”有多少像素,默认为10
box_size=10,
# 控制边框应该有多少个框厚(默认为 4,这是根据规范的最小值)
border=1,
)
# 二维码尺寸
img_w, img_h = img.size
# 过宽则变形
if img_w > page_width:
scale_rate = page_width / img_w
img_w = page_width
img_h = int(scale_rate * img_h)
img = img.resize((img_w, img_h))
# 二值化处理
img = img.convert("1")
# 避免长度不符合8的倍数 给最后一个byte补0 以满足字节长度 (img_w + 7) // 8
img_w_byte = (img_w - 1) // 8 + 1
row_data_list = []
for y in range(0, img_h):
row_data = [0] * img_w_byte
temp = 0
# 遍历每一行 将像素点缩到字节上 一个字节表示八个像素点
for x in range(img_w):
pixel = img.getpixel((x, y))
offset = x % 8
# 如果是0 则代表黑色 需要打印
if pixel == 0:
# 0x80是0b10000000, 点在byte中的下标是几,向右位移几,和这个字节做或运算。
# 比如一个字节A中从高向低第二个点是1,那么A = A | 0b01000000, A的从高向低第二位就是1了,表示这个位置绘制黑点。
temp |= (0x80 >> offset)
# 如果是一个字节最后一个点,或者是这一行的最后一个点,这个字节数据就满了,
# 存储到对应位置,将temp复原为0。如果最后一个字节不足8个点,剩下的位数自然补0.
if offset == 7 or x >= img_w - 1:
row_data[x // 8] = temp
temp = 0
row_data_list.append(row_data)
xl = img_w_byte % 256
xh = img_w_byte // 256
yl = img_h % 256
yh = img_h // 256
cmd = [0x1d, 0x76, 0x30, 0, xl, xh, yl, yh]
# print_text = ""
for row in row_data_list:
# print_text += ''.join([bin(i).removeprefix('0b').rjust(8, '0') for i in row])
# print_text += '\n'
cmd.extend(row)
# with open('print_text.txt', 'w', encoding='u8') as f:
# f.write(print_text)
# print(bytes(cmd).hex())
return bytes(cmd).hex()
if __name__ == '__main__':
send_data = str_to_send_data("测12312试")
print(send_data)