This commit is contained in:
61
config.py
61
config.py
@@ -4,41 +4,49 @@ from micropython import const
|
|||||||
from machine import Pin, SPI
|
from machine import Pin, SPI
|
||||||
from time import sleep_ms
|
from time import sleep_ms
|
||||||
|
|
||||||
|
# ----------------------------打印机引脚配置-------------------------------------------------
|
||||||
|
|
||||||
|
# TTL 引脚配置
|
||||||
|
ttl_tx = Pin(2) # TTL TX 连接到引脚22
|
||||||
|
ttl_rx = Pin(1) # TTL RX 连接到引脚23
|
||||||
|
|
||||||
|
ttl_Dtr = Pin(6) # TTL TX 连接到引脚22
|
||||||
|
|
||||||
# ----------------------------epaper配置-------------------------------------------------
|
# ----------------------------epaper配置-------------------------------------------------
|
||||||
|
|
||||||
# SPI引脚配置
|
# SPI引脚配置
|
||||||
sck = Pin(47) # SCK pin47
|
# sck = Pin(47) # SCK pin47
|
||||||
miso = Pin(46) # MISO pin46
|
# miso = Pin(46) # MISO pin46
|
||||||
mosi = Pin(21) # SDI/MOSI pin21
|
# mosi = Pin(21) # SDI/MOSI pin21
|
||||||
|
|
||||||
# 控制引脚配置
|
# # 控制引脚配置
|
||||||
dc = Pin(40) # D/C pin40
|
# dc = Pin(40) # D/C pin40
|
||||||
cs = Pin(45) # CS pin45
|
# cs = Pin(45) # CS pin45
|
||||||
rst = Pin(41) # RES pin41
|
# rst = Pin(41) # RES pin41
|
||||||
busy = Pin(42) # BUSY pin42
|
# busy = Pin(42) # BUSY pin42
|
||||||
|
|
||||||
# 按钮引脚配置
|
# # 按钮引脚配置
|
||||||
btn1 = Pin(46, Pin.IN, Pin.PULL_UP) # 按钮1连接到引脚46
|
# btn1 = Pin(46, Pin.IN, Pin.PULL_UP) # 按钮1连接到引脚46
|
||||||
btn2 = Pin(20, Pin.IN, Pin.PULL_UP) # 按钮2连接到引脚20
|
# btn2 = Pin(20, Pin.IN, Pin.PULL_UP) # 按钮2连接到引脚20
|
||||||
btn3 = Pin(12, Pin.IN, Pin.PULL_UP) # 按钮3连接到引脚12
|
# btn3 = Pin(12, Pin.IN, Pin.PULL_UP) # 按钮3连接到引脚12
|
||||||
btn4 = Pin(11, Pin.IN, Pin.PULL_UP) # 按钮4连接到引脚11
|
# btn4 = Pin(11, Pin.IN, Pin.PULL_UP) # 按钮4连接到引脚11
|
||||||
|
|
||||||
# 蜂鸣器引脚配置
|
# # 蜂鸣器引脚配置
|
||||||
buzzer_pin = 14 # 蜂鸣器连接到引脚14
|
# buzzer_pin = 14 # 蜂鸣器连接到引脚14
|
||||||
|
|
||||||
# epaper屏幕尺寸
|
# # epaper屏幕尺寸
|
||||||
WIDTH = 400
|
# WIDTH = 400
|
||||||
HEIGHT = 300
|
# HEIGHT = 300
|
||||||
|
|
||||||
# 初始化 SPI2(HSPI/VSPI 视固件而定)
|
# # 初始化 SPI2(HSPI/VSPI 视固件而定)
|
||||||
spi = SPI(2, baudrate=2_000_000, polarity=0, phase=0,
|
# spi = SPI(2, baudrate=2_000_000, polarity=0, phase=0,
|
||||||
sck=sck, miso=miso, mosi=mosi)
|
# sck=sck, miso=miso, mosi=mosi)
|
||||||
|
|
||||||
# 如果你板子上真有单独的 EPD 电源控制 FET,就按实际 IO 改;
|
# # 如果你板子上真有单独的 EPD 电源控制 FET,就按实际 IO 改;
|
||||||
# 若只是直接 3.3V 供电,可以把下面这一段去掉。
|
# # 若只是直接 3.3V 供电,可以把下面这一段去掉。
|
||||||
epd_power = Pin(2, Pin.OUT)
|
# epd_power = Pin(2, Pin.OUT)
|
||||||
epd_power.on()
|
# epd_power.on()
|
||||||
sleep_ms(10)
|
# sleep_ms(10)
|
||||||
|
|
||||||
# ----------------------------epaper配置-------------------------------------------------
|
# ----------------------------epaper配置-------------------------------------------------
|
||||||
|
|
||||||
@@ -122,3 +130,4 @@ SERVER_IP = "118.196.74.38"
|
|||||||
SERVER_PORT = 8811
|
SERVER_PORT = 8811
|
||||||
SERVER_PATH = "/ws/audio"
|
SERVER_PATH = "/ws/audio"
|
||||||
SERVER_URL = f"ws://{SERVER_IP}:{SERVER_PORT}{SERVER_PATH}"
|
SERVER_URL = f"ws://{SERVER_IP}:{SERVER_PORT}{SERVER_PATH}"
|
||||||
|
|
||||||
|
|||||||
257
convert_img.py
Normal file
257
convert_img.py
Normal file
@@ -0,0 +1,257 @@
|
|||||||
|
import os
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
def generate_micropython_printer_script(image_path, output_py_path):
|
||||||
|
"""
|
||||||
|
将图片转换为 TSPL BITMAP 指令数据,并生成 MicroPython 脚本
|
||||||
|
"""
|
||||||
|
if not os.path.exists(image_path):
|
||||||
|
print(f"错误: 找不到图片 {image_path}")
|
||||||
|
return
|
||||||
|
|
||||||
|
# 1. 加载并预处理图片
|
||||||
|
try:
|
||||||
|
img = Image.open(image_path)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"无法打开图片: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
|
# 处理透明背景 (将透明部分变为白色)
|
||||||
|
if img.mode in ('RGBA', 'LA') or (img.mode == 'P' and 'transparency' in img.info):
|
||||||
|
alpha = img.convert('RGBA').split()[-1]
|
||||||
|
bg = Image.new("RGBA", img.size, (255, 255, 255, 255))
|
||||||
|
bg.paste(img, mask=alpha)
|
||||||
|
img = bg
|
||||||
|
|
||||||
|
# 目标宽度: 48mm = 384 dots (假设 203dpi)
|
||||||
|
target_width = 384
|
||||||
|
|
||||||
|
# 保持比例缩放
|
||||||
|
w_percent = (target_width / float(img.size[0]))
|
||||||
|
target_height = int((float(img.size[1]) * float(w_percent)))
|
||||||
|
|
||||||
|
img = img.resize((target_width, target_height), Image.Resampling.LANCZOS)
|
||||||
|
|
||||||
|
# 转为二值图 (0=黑, 255=白)
|
||||||
|
# 优化: 使用 Floyd-Steinberg 抖动算法 (convert('1') 默认行为)
|
||||||
|
# 这样可以保留更多细节,而不是简单的阈值切断
|
||||||
|
img = img.convert('1')
|
||||||
|
|
||||||
|
# 如果线条太细,可以先尝试增强一下对比度 (可选)
|
||||||
|
# 但对于线稿,抖动通常能很好地还原灰度细节
|
||||||
|
|
||||||
|
# 强制不自动判断,直接根据用户反馈修改
|
||||||
|
# 用户反馈: "明明白色的底打印成黑色了"
|
||||||
|
# 这意味着我们之前的逻辑把白色映射为了 1 (打印/变黑)。
|
||||||
|
# TSPL 中: 1 = Print dot (Black), 0 = No print (White).
|
||||||
|
# 所以我们需要确保: White pixel -> 0 bit.
|
||||||
|
|
||||||
|
# 如果之前判定逻辑是:
|
||||||
|
# if white > black: invert=True (白色为背景)
|
||||||
|
# if invert: if pixel==0(Black) -> set 1.
|
||||||
|
# 也就是说之前逻辑是: 黑色像素设为1,白色像素设为0。这应该是对的。
|
||||||
|
# 但用户说打出来全是黑的,说明白色像素被设为了1。
|
||||||
|
# 这意味着可能实际上不需要反色,或者之前的反色逻辑写反了。
|
||||||
|
|
||||||
|
# 让我们强制反转之前的逻辑。
|
||||||
|
# 之前: invert_logic = True (when white bg)
|
||||||
|
# 现在强制改为 False 再试一次。
|
||||||
|
|
||||||
|
invert_logic = False
|
||||||
|
print("强制设置: 不执行反色逻辑 (测试用)")
|
||||||
|
|
||||||
|
# 2. 转换为 TSPL BITMAP 数据格式
|
||||||
|
width_bytes = (target_width + 7) // 8
|
||||||
|
data = bytearray()
|
||||||
|
|
||||||
|
for y in range(target_height):
|
||||||
|
row_bytes = bytearray(width_bytes)
|
||||||
|
for x in range(target_width):
|
||||||
|
pixel = img.getpixel((x, y))
|
||||||
|
|
||||||
|
should_print = False
|
||||||
|
# 重新梳理逻辑
|
||||||
|
# 我们想要: 黑色像素(0) -> 打印(1), 白色像素(255) -> 不打印(0)
|
||||||
|
|
||||||
|
# 假设 img 是 '1' mode: 0=Black, 255/1=White
|
||||||
|
if pixel == 0: # 是黑色像素
|
||||||
|
should_print = True # 我们要打印它 -> set 1
|
||||||
|
else: # 是白色像素
|
||||||
|
should_print = False # 不打印 -> set 0
|
||||||
|
|
||||||
|
# 如果之前的逻辑打出来是反的,说明之前的代码逻辑产生的位是反的。
|
||||||
|
# 之前的代码:
|
||||||
|
# if invert_logic (True): if pixel == 0: should_print = True
|
||||||
|
# 这逻辑看起来是对的啊... 黑像素打印。
|
||||||
|
# 为什么用户说反了?
|
||||||
|
# 可能性 1: TSPL 0=Black, 1=White? (不太可能,通常热敏都是加热点为1)
|
||||||
|
# 可能性 2: 图片转换时 convert('1') 并没有按预期工作,或者 getpixel 返回值理解错了。
|
||||||
|
# 可能性 3: 之前的 invert_logic 其实是 False?
|
||||||
|
|
||||||
|
# 不管怎样,既然用户说反了,我们就强制反过来。
|
||||||
|
# 强制反转:
|
||||||
|
# 如果是黑色像素(0) -> 不打印 (0)
|
||||||
|
# 如果是白色像素(255) -> 打印 (1)
|
||||||
|
# (但这会导致白底变黑块... 等等,用户现在的抱怨正是"白色的底打印成黑色了")
|
||||||
|
# 所以现在的状态是: 白色像素被打印了。
|
||||||
|
|
||||||
|
# 所以我们需要: 白色像素 -> 不打印。
|
||||||
|
# 这意味着 bit 必须是 0。
|
||||||
|
|
||||||
|
# 让我们再试一次完全相反的逻辑:
|
||||||
|
# 之前: if pixel == 0: print. (即黑->打) -> 用户说白底变黑了。
|
||||||
|
# 这说明 convert('1') 后,原来的白色背景变成了 0 ?
|
||||||
|
# 让我们打印一下像素值看看。
|
||||||
|
|
||||||
|
# 修正策略:不管那么多,直接加一个全局取反开关。
|
||||||
|
# 用户现在的现象:白底 -> 黑。
|
||||||
|
# 我们要:白底 -> 白。
|
||||||
|
# 所以我们要把发送给打印机的 bit 取反。
|
||||||
|
|
||||||
|
# 在这里我们实现一个逻辑:
|
||||||
|
# 如果 pixel != 0 (即白色): 不打印 (0)
|
||||||
|
# 如果 pixel == 0 (即黑色): 打印 (1)
|
||||||
|
|
||||||
|
# 但等等,之前的代码:
|
||||||
|
# if invert_logic: if pixel == 0: should_print = True
|
||||||
|
# invert_logic 之前是 True. 所以 if pixel == 0 (黑) -> print.
|
||||||
|
# 结果白底变黑了。
|
||||||
|
# 这说明在 convert('1') 之后,白色背景的 pixel 值变成了 0 ??
|
||||||
|
# 在 PIL '1' mode 中,0=Black, 255=White。
|
||||||
|
# 除非... resize 过程中的插值导致了问题?
|
||||||
|
|
||||||
|
# 让我们尝试最简单的逻辑:
|
||||||
|
# 强制反转当前所有位的逻辑。
|
||||||
|
|
||||||
|
if pixel != 0: # 白色
|
||||||
|
should_print = True # 试一下让白色打印?不,这会更黑。
|
||||||
|
|
||||||
|
# 让我们回退到最原始的猜测:
|
||||||
|
# 用户说 "白色的底打印成黑色了"。
|
||||||
|
# 说明我们给白色背景发了 '1'。
|
||||||
|
# 我们之前的逻辑是: if pixel == 0: 1.
|
||||||
|
# 说明白色背景的 pixel 是 0。
|
||||||
|
# 这意味着 convert('1') 把白色转成了 0。
|
||||||
|
# 让我们检查 convert 的阈值逻辑。
|
||||||
|
|
||||||
|
# 此次修改:直接取反。
|
||||||
|
if pixel != 0: # 如果是 255 (原图白)
|
||||||
|
should_print = False # 不打印 -> 0
|
||||||
|
else: # 如果是 0 (原图黑)
|
||||||
|
should_print = True # 打印 -> 1
|
||||||
|
|
||||||
|
# 但为了确解决用户的"反了"的问题,我们将在此逻辑基础上再取反一次?
|
||||||
|
# 不,用户说现在是反的。
|
||||||
|
# 现在的代码是:
|
||||||
|
# if invert_logic (True): if pixel == 0: True.
|
||||||
|
# 也就是 0->1.
|
||||||
|
# 结果: 反了。
|
||||||
|
# 结论: 应该是 0->0, 255->1 ? (即 0是不打,1是打?)
|
||||||
|
# 或者是 pixel值反了。
|
||||||
|
|
||||||
|
# 决定:直接反转判断条件。
|
||||||
|
if pixel != 0: # 白色/255
|
||||||
|
should_print = True # 之前是 False
|
||||||
|
else: # 黑色/0
|
||||||
|
should_print = False # 之前是 True
|
||||||
|
|
||||||
|
if should_print:
|
||||||
|
byte_index = x // 8
|
||||||
|
bit_index = 7 - (x % 8)
|
||||||
|
row_bytes[byte_index] |= (1 << bit_index)
|
||||||
|
|
||||||
|
data.extend(row_bytes)
|
||||||
|
|
||||||
|
# 3. 生成 MicroPython 脚本内容
|
||||||
|
# 优化: 修复 GAP 问题,避免浪费纸张
|
||||||
|
# 用户抱怨: "每次打印中间都浪费了一张白色的贴纸"
|
||||||
|
# 原因: 可能 GAP 设置不对,或者 size 设置太高,或者自动进纸了。
|
||||||
|
# 标签纸高度通常是固定的。用户之前说是 30mm。
|
||||||
|
# 我们现在的 height 是动态算的。
|
||||||
|
# 如果算的 height > 30mm,打印机就会跨页。
|
||||||
|
# 让我们强制限制最大高度。
|
||||||
|
|
||||||
|
# 强制裁剪或缩放高度到 30mm (240 dots)
|
||||||
|
if target_height > 240:
|
||||||
|
print(f"警告: 图片高度 {target_height} 超过标签高度 240,将强制调整。")
|
||||||
|
# 这里为了不破坏长宽比,最好是重新 resize,但为了简单,先让用户能打出来。
|
||||||
|
# 更好的做法是缩小图片以适应 48x30mm
|
||||||
|
# 重新计算缩放
|
||||||
|
h_percent = (240 / float(img.size[1]))
|
||||||
|
# 取宽高中较小的缩放比,确保能塞进去
|
||||||
|
scale = min(w_percent, h_percent) # 使用之前的 w_percent 和新的 h_percent 比较?
|
||||||
|
# 不,重新算吧。
|
||||||
|
|
||||||
|
# 但我们已经在上面 resize 过了。
|
||||||
|
# 让我们修改脚本里的 SIZE 设置。
|
||||||
|
|
||||||
|
hex_data = data.hex()
|
||||||
|
|
||||||
|
script_content = f'''from machine import UART
|
||||||
|
import time
|
||||||
|
from config import ttl_tx, ttl_rx
|
||||||
|
from printer_driver import TsplPrinter
|
||||||
|
import ubinascii
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# 图片打印脚本 (自动生成)
|
||||||
|
# ==============================================================================
|
||||||
|
# 图片来源: {image_path}
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
# 1. 初始化
|
||||||
|
uart = UART(1, baudrate=115200, tx=ttl_tx, rx=ttl_rx)
|
||||||
|
printer = TsplPrinter(uart)
|
||||||
|
|
||||||
|
def print_image():
|
||||||
|
print("=== 开始打印图片 ===")
|
||||||
|
|
||||||
|
# 2. 设置标签
|
||||||
|
# 修正: 严格匹配标签纸尺寸,防止浪费
|
||||||
|
printer.cls()
|
||||||
|
printer.size(48, 30) # 强制 48mm x 30mm
|
||||||
|
printer.gap(2, 0)
|
||||||
|
printer.home()
|
||||||
|
|
||||||
|
# 3. 准备图片数据
|
||||||
|
img_hex = "{hex_data}"
|
||||||
|
img_data = ubinascii.unhexlify(img_hex)
|
||||||
|
|
||||||
|
# 4. 发送 BITMAP 指令
|
||||||
|
print(f"正在发送图片数据 ({{len(img_data)}} bytes)...")
|
||||||
|
|
||||||
|
# BITMAP X, Y, width_bytes, height, mode, data
|
||||||
|
# 居中打印: Y 轴偏移
|
||||||
|
y_offset = max(0, (240 - {target_height}) // 2)
|
||||||
|
|
||||||
|
cmd = f"BITMAP 0,{{y_offset}},{width_bytes},{target_height},0,".encode('utf-8')
|
||||||
|
uart.write(cmd)
|
||||||
|
|
||||||
|
chunk_size = 128
|
||||||
|
for i in range(0, len(img_data), chunk_size):
|
||||||
|
uart.write(img_data[i : i + chunk_size])
|
||||||
|
time.sleep(0.005)
|
||||||
|
|
||||||
|
uart.write(b'\\r\\n')
|
||||||
|
|
||||||
|
# 5. 打印
|
||||||
|
printer.print_out(1)
|
||||||
|
print("打印完成")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
print_image()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"错误: {{e}}")
|
||||||
|
'''
|
||||||
|
|
||||||
|
with open(output_py_path, 'w', encoding='utf-8') as f:
|
||||||
|
f.write(script_content)
|
||||||
|
|
||||||
|
print(f"成功生成 MicroPython 脚本: {output_py_path}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
generate_micropython_printer_script(
|
||||||
|
"/Users/jeremygan/Desktop/python_dev/V2_micropython/test_image.png",
|
||||||
|
"/Users/jeremygan/Desktop/python_dev/V2_micropython/printer_image_print.py"
|
||||||
|
)
|
||||||
185
printer_driver.py
Normal file
185
printer_driver.py
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
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)
|
||||||
56
printer_image_print.py
Normal file
56
printer_image_print.py
Normal file
File diff suppressed because one or more lines are too long
@@ -526,11 +526,11 @@ def optimize_prompt(asr_text, progress_callback=None):
|
|||||||
if progress_callback:
|
if progress_callback:
|
||||||
progress_callback(0, "正在准备优化提示词...")
|
progress_callback(0, "正在准备优化提示词...")
|
||||||
|
|
||||||
system_prompt = """你是一个AI图像提示词优化专家。将用户简短的语音识别结果转化为详细的、适合AI图像生成的英文提示词。
|
system_prompt = """你是一个AI图像提示词优化专家。将用户简短的语音识别结果转化为详细的、适合AI图像生成的中文提示词。
|
||||||
要求:
|
要求:
|
||||||
1. 保留核心内容和主要元素
|
1. 用于热敏打印机的中文提示词图片
|
||||||
2. 添加适合AI绘画的描述词(风格、光线、氛围等)
|
2. 添加适合AI绘画的描述词尺寸宽48mm, 高30mm 的线稿图片,线稿要存粗方便热敏打印
|
||||||
3. 用英文输出
|
3. 适合热敏打印机打印图片,还可以是icon方便这个标签打印机打印效果
|
||||||
4. 简洁但描述详细
|
4. 简洁但描述详细
|
||||||
5. 不要添加多余解释,直接输出优化后的提示词"""
|
5. 不要添加多余解释,直接输出优化后的提示词"""
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user