186 lines
6.8 KiB
Python
186 lines
6.8 KiB
Python
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)
|