import time class TsplPrinter: """ 基于 TSPL (TSC Printer Language) 的标签打印机驱动 适用于 HPRT (汉印), TSC, 佳博等支持 TSPL 指令集的打印机 参考 Android SDK: Serialport_Factory """ def __init__(self, uart, encoding='gbk'): """ :param uart: machine.UART 对象 :param encoding: 文本编码,默认 'gbk' (国产打印机通用) """ self.uart = uart self.encoding = encoding def send_raw(self, data): """发送原始数据 (bytes 或 str)""" if isinstance(data, str): try: data = data.encode(self.encoding) except Exception: # 如果无法用指定编码,尝试 utf-8 或直接发送 ascii data = data.encode('utf-8') self.uart.write(data) def send_command(self, cmd): """发送 TSPL 指令 (自动添加换行)""" self.send_raw(cmd + "\r\n") # ================================================================= # 基础设置指令 # ================================================================= def size(self, width_mm, height_mm): """ 设置标签尺寸 :param width_mm: 宽度 (mm) :param height_mm: 高度 (mm) """ # TSPL 标准: SIZE m, n (单位 mm) # 如果打印机只支持 dots,可能需要修改为 "SIZE 384 dot, 240 dot" # SDK 注释: 384*0.125=48mm self.send_command(f"SIZE {width_mm} mm, {height_mm} mm") def gap(self, gap_mm=2, offset_mm=0): """ 设置标签间隙 (定位用) :param gap_mm: 间隙高度 (mm),通常为 2mm :param offset_mm: 偏移量 (mm) """ self.send_command(f"GAP {gap_mm} mm, {offset_mm} mm") def cls(self): """清除图像缓冲区 (每次打印新标签前调用)""" self.send_command("CLS") def feed(self, len_mm=None): """进纸""" if len_mm: self.send_command(f"FEED {len_mm} mm") else: self.send_command("FORMFEED") # 进纸到下一张标签开头 def home(self): """寻找标签原点 (自动测纸后定位)""" self.send_command("HOME") # ================================================================= # 绘图与文本指令 # ================================================================= def text(self, x, y, content, font="TSS24.BF2", rotation=0, x_mul=1, y_mul=1): """ 打印文本 :param x: x 坐标 (dots) :param y: y 坐标 (dots) :param content: 文本内容 :param font: 字体名称。 "TSS24.BF2" 是常用的内置简体中文字体。 "1"~"5" 是内置英文字体。 :param rotation: 旋转角度 (0, 90, 180, 270) :param x_mul: 横向放大倍数 (1-10) :param y_mul: 纵向放大倍数 (1-10) """ # TEXT x,y,"font",rotation,x_mul,y_mul,"content" # 注意: content 需要用双引号包围,且内部双引号需要转义 safe_content = content.replace('"', '\\"') cmd = f'TEXT {x},{y},"{font}",{rotation},{x_mul},{y_mul},"{safe_content}"' self.send_command(cmd) def barcode(self, x, y, content, type="128", height=100, human=1, rotation=0, narrow=2, wide=2): """ 打印条码 :param x: x 坐标 :param y: y 坐标 :param content: 条码内容 :param type: 条码类型 ("128", "39", "EAN13", "QRCODE"等) - 注意 TSPL 有专门的 QRCODE 指令 :param height: 条码高度 (dots) :param human: 是否打印人眼可读字符 (0:不可见, 1:可见) :param rotation: 旋转 (0, 90, 180, 270) :param narrow: 窄条宽度 (dots) :param wide: 宽条宽度 (dots) """ # BARCODE x,y,"type",height,human,rotation,narrow,wide,"content" safe_content = content.replace('"', '\\"') cmd = f'BARCODE {x},{y},"{type}",{height},{human},{rotation},{narrow},{wide},"{safe_content}"' self.send_command(cmd) def qrcode(self, x, y, content, ecc="L", cell_width=5, mode="A", rotation=0): """ 打印二维码 :param x: x 坐标 :param y: y 坐标 :param content: 二维码内容 :param ecc: 纠错级别 (L, M, Q, H) :param cell_width: 单元格宽度 (dots, 1-10),控制二维码大小 :param mode: 模式 (A:自动, M:手动) :param rotation: 旋转 (0, 90, 180, 270) """ # QRCODE x,y,ECC,cell_width,mode,rotation,"content" safe_content = content.replace('"', '\\"') cmd = f'QRCODE {x},{y},{ecc},{cell_width},{mode},{rotation},"{safe_content}"' self.send_command(cmd) def box(self, x, y, x_end, y_end, thickness=1): """绘制矩形框""" self.send_command(f"BOX {x},{y},{x_end},{y_end},{thickness}") def line(self, x, y, width, height): """绘制直线 (TSPL 中 BAR 命令用于画线)""" # BAR x,y,width,height self.send_command(f"BAR {x},{y},{width},{height}") # ================================================================= # 执行打印 # ================================================================= def print_out(self, quantity=1): """ 开始打印 :param quantity: 打印份数 """ self.send_command(f"PRINT {quantity}") # ================================================================= # SDK 特殊指令兼容 (参考 Android SDK) # ================================================================= def set_special_mode(self, enabled=True): """ 发送 SDK 中出现的神秘指令 0x12 0x43 可能是某种私有模式开关(如加粗或特殊字体) """ if enabled: self.send_raw(b'\x12\x43\x01') self.send_raw(b'\x12\x45\x01') else: self.send_raw(b'\x12\x43\x00') self.send_raw(b'\x12\x45\x00') # ================================================================= # 快捷组合方法 (仿 Android SDK 逻辑) # ================================================================= def label_begin(self, width_dots, height_dots): """ 开始标签任务 (仿 SDK 接口) 自动将 dots 转换为 mm (假设 203dpi, 8 dots/mm) """ width_mm = int(width_dots / 8) height_mm = int(height_dots / 8) # 1. 清除缓冲区 self.cls() # 2. 设置尺寸 self.size(width_mm, height_mm) # 3. 设置间隙 (默认 2mm) self.gap(2, 0) # 4. 寻原点 (可选,防止跑偏) # self.home() def label_end(self): """结束标签任务并打印 (仿 SDK 接口)""" self.print_out(1)