From c66f80d0eb51f115c7307231340361ffc088254e Mon Sep 17 00:00:00 2001 From: jeremygan2021 Date: Thu, 5 Mar 2026 19:59:56 +0800 Subject: [PATCH] printer --- .DS_Store | Bin 8196 -> 8196 bytes config.py | 61 +++++---- convert_img.py | 257 +++++++++++++++++++++++++++++++++++++ printer_driver.py | 185 ++++++++++++++++++++++++++ printer_image_print.py | 56 ++++++++ websocket_server/server.py | 8 +- 6 files changed, 537 insertions(+), 30 deletions(-) create mode 100644 convert_img.py create mode 100644 printer_driver.py create mode 100644 printer_image_print.py diff --git a/.DS_Store b/.DS_Store index 0ef48d91a4fc329f014e6b5a30d5923db233151c..303f87d2840cdf0fe3602c28fa013f3e009fe9d3 100644 GIT binary patch delta 391 zcmZp1XmOa}FDlBwz`)4BAi%(o%#aAg84Rfm@f!=Lu}^H^-OSFx!eI_l!Oaj4gar(h z$f_9PJ#+GtlXCKtfGU6nFl++iHUGhYfnhR_z)n#<*AFu-~BO>H*EoV@OB!1@j@0%QkNkoXxVCUE&+dW@lk` FW&n?iWLW?J delta 81 zcmV-X0IvUpK!iY$PZbUT0003101yBGZvZX;Z~%EpY;R++ah3;>fDN+;2m}ZL4wFI< nxsx{$G?SwdT$7CwYO{G0js&rQx&gBX81@9Sw-!(Vv4FP$Vs#jj diff --git a/config.py b/config.py index 7ae042c..437fa6e 100644 --- a/config.py +++ b/config.py @@ -4,41 +4,49 @@ from micropython import const from machine import Pin, SPI 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配置------------------------------------------------- # SPI引脚配置 -sck = Pin(47) # SCK pin47 -miso = Pin(46) # MISO pin46 -mosi = Pin(21) # SDI/MOSI pin21 +# sck = Pin(47) # SCK pin47 +# miso = Pin(46) # MISO pin46 +# mosi = Pin(21) # SDI/MOSI pin21 -# 控制引脚配置 -dc = Pin(40) # D/C pin40 -cs = Pin(45) # CS pin45 -rst = Pin(41) # RES pin41 -busy = Pin(42) # BUSY pin42 +# # 控制引脚配置 +# dc = Pin(40) # D/C pin40 +# cs = Pin(45) # CS pin45 +# rst = Pin(41) # RES pin41 +# busy = Pin(42) # BUSY pin42 -# 按钮引脚配置 -btn1 = Pin(46, Pin.IN, Pin.PULL_UP) # 按钮1连接到引脚46 -btn2 = Pin(20, Pin.IN, Pin.PULL_UP) # 按钮2连接到引脚20 -btn3 = Pin(12, Pin.IN, Pin.PULL_UP) # 按钮3连接到引脚12 -btn4 = Pin(11, Pin.IN, Pin.PULL_UP) # 按钮4连接到引脚11 +# # 按钮引脚配置 +# btn1 = Pin(46, Pin.IN, Pin.PULL_UP) # 按钮1连接到引脚46 +# btn2 = Pin(20, Pin.IN, Pin.PULL_UP) # 按钮2连接到引脚20 +# btn3 = Pin(12, Pin.IN, Pin.PULL_UP) # 按钮3连接到引脚12 +# btn4 = Pin(11, Pin.IN, Pin.PULL_UP) # 按钮4连接到引脚11 -# 蜂鸣器引脚配置 -buzzer_pin = 14 # 蜂鸣器连接到引脚14 +# # 蜂鸣器引脚配置 +# buzzer_pin = 14 # 蜂鸣器连接到引脚14 -# epaper屏幕尺寸 -WIDTH = 400 -HEIGHT = 300 +# # epaper屏幕尺寸 +# WIDTH = 400 +# HEIGHT = 300 -# 初始化 SPI2(HSPI/VSPI 视固件而定) -spi = SPI(2, baudrate=2_000_000, polarity=0, phase=0, - sck=sck, miso=miso, mosi=mosi) +# # 初始化 SPI2(HSPI/VSPI 视固件而定) +# spi = SPI(2, baudrate=2_000_000, polarity=0, phase=0, +# sck=sck, miso=miso, mosi=mosi) -# 如果你板子上真有单独的 EPD 电源控制 FET,就按实际 IO 改; -# 若只是直接 3.3V 供电,可以把下面这一段去掉。 -epd_power = Pin(2, Pin.OUT) -epd_power.on() -sleep_ms(10) +# # 如果你板子上真有单独的 EPD 电源控制 FET,就按实际 IO 改; +# # 若只是直接 3.3V 供电,可以把下面这一段去掉。 +# epd_power = Pin(2, Pin.OUT) +# epd_power.on() +# sleep_ms(10) # ----------------------------epaper配置------------------------------------------------- @@ -122,3 +130,4 @@ SERVER_IP = "118.196.74.38" SERVER_PORT = 8811 SERVER_PATH = "/ws/audio" SERVER_URL = f"ws://{SERVER_IP}:{SERVER_PORT}{SERVER_PATH}" + diff --git a/convert_img.py b/convert_img.py new file mode 100644 index 0000000..564a94c --- /dev/null +++ b/convert_img.py @@ -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" + ) diff --git a/printer_driver.py b/printer_driver.py new file mode 100644 index 0000000..74b6a51 --- /dev/null +++ b/printer_driver.py @@ -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) diff --git a/printer_image_print.py b/printer_image_print.py new file mode 100644 index 0000000..fb08b33 --- /dev/null +++ b/printer_image_print.py @@ -0,0 +1,56 @@ +from machine import UART +import time +from config import ttl_tx, ttl_rx +from printer_driver import TsplPrinter +import ubinascii + +# ============================================================================== +# 图片打印脚本 (自动生成) +# ============================================================================== +# 图片来源: /Users/jeremygan/Desktop/python_dev/V2_micropython/test_image.png +# ============================================================================== + +# 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 = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeef7bdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb7fdef7aadb6fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6ffffffffffffd55fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb6db5fffbffffffedbfef55bfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffffdffffffffff55bfff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffffddffbffffffffffeff7ddfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5bfff6d6f76aeaab7ffff57fdbdf7bfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5fedabb6b2aaaaaddaadfffff6d6befffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5ed555449080040100252957fab5555edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdab7a8000000000000000023fee8094b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6b5a810000000000000000057b012024abdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd2bec00000000000000000003fe900100157bfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa96f200000024000000000005f500000005afffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd56fa89000bb5b40000000000bfa000040005b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffaaffa44d00b5fe80000000000fe802400aa017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffed5ff537682febf00000000002ff55aa10140095ffffffffffffffffffffffffffffffffffffffffffffffffffffffffb2bffddde00bfff800000255517d6edd823ea02fbfffffffffffffffffffffffffffffffffffffffffffffffffffffff4bffdf7fd417dfea00002955c5fbbfff401bd405fffffffffffffffffffffffffffffffffffffffffffffffffffffffdadfeffffe80f75ba80002efff2fd7fffc01ff8157ffffffffffffffffffffffffffffffffffffffffffffffffffffff657ffffffa015ffee8000b7dfcbf6ffffa20fff42dbfffffffffffffffffffffffffffffffffffffffffffffffffffff97ff7ffffa017fab7d0001fffe3faaaffc82bff417fffffffffffffffffffffffffffffffffffffffffffffffffffffd4bfdffffe881fed4aa0003fff55f5513fe007ffd45bfffffffffffffffffffffffffbffffffffffffffffffffffffff4bffffffff402fd012bc000fffabfa0457d007fff12fbffffffffffffffffffffffffffffffffffffffffffffffffffeabfefffffa803f40005a0017ff8fe8001ff483fffc16fffffffffffffffffffffffffffffffffffffffffffffffffffb57f7fffffd405fd0003e8003ff57e8000fe805fff6afffffffffffffffffffffffffbffffffffffffffffffffffffff4affffffff6807f00005f0001ff1fe80007f043fffd82efffffffffffffffffffffffffffffffffffffffffffffffffeabfbffffdfa00bf80003fa002fe97d0000ffa03fffeebffffffffffffffffffffffffffffbfffffffffffffffffffffb57ff7ffffed20fe8000178000ba5fe00007f4417ffb54b7ffffffffffffffffffffffffffffffffffffffffffffffff4bfffffffff4017f00002fc000d55fa00005f902fdfef9fffffffffffffffffffffffffffffffffffffffffffffffeddabfdbfffffd600fe80001f0000287fd0000bfc00f7fef45afffffffffffffffffffffffffffffffffffffffffffffbf657ffffffffe902ff00000fa240815f402b576a417f7ebd7fffffffffffffffffffffffffffffffffffffffffffffefd95fefffffefac01fe800016891008ffe82ffdf500bfdf7e1b7ffffffffffffffffffffffffffffffffffffffffffffde4bfbfffffffe20aff00000e24a0007ea0bff7ba10fefedebfffffffffffffffffffffffffffffffffffffffffffff5fabffffffffff5805ff000015011401ffe8ffffed007fdf6f2d5ffffffffffffffffffffffffffffffffffffffffffff74affffffffffe807fd40004aa82502fde17ffffe00bff5be97ffffffffffffffffffffffffffffffffffffffffffff5faffffffffffea012eb000aada01503fef5fffffe907fbf4fdfaffffffffffffffffffffffffffffffffffffffffffffd2fedfffffb7d580aa800ab7fff4242fdd3fffffe045fefb74ffbffffffffffffffffffff7fffffffffffffffffffffa45db7ffff6fd6a04100027ffffd8885fef5ffffff403f7fdfabdffffffffffffffffffffffffffffffffffffffffffed22e44aaaad4549114000095ff7f400bf7fbff7daa9057db4faff5bfffffffffffffffffffffffffffffffffffffffef40210295a29290080000004a414aa02ffd77fdd76d001effb557ff6fffffffffffffffffffffffffffffffffffffff7aa494084548484422512a820114224017effdb77a92a85f55dfdbfdfbf7ffffffffffffffffffffffffffffffffff77ff5249532aa5ab294aaaaa54a8011128befb6aa9044552adff6aefff5ffffffffffffffffffffffffffffff7ffffedddb7ddf76ddffb75f6bbb6b7b556ed5556efefd404410ad55f6dffbdfff5ffffffffffffffffffffffffffefdffffbbf77fefffffffdfffffffffffdfffbb6edabfff740200827fff5fffffffffefffffffffffffffffffffffffffffff76ff5ddbfffffffffffffffffffffffffffbefffffbd002455b5f5fffffff7ffbbffefffffffffffffffffffffffffffffd5fffffffffffffffffffffffffffdfddfffbffeda0aabbfffffff7fffffffefffffffff7ffffffffffffffffffffded7f77ffffffffffffffffffffffffffeffffff7ff752bffffffffffffffedaff5ffffffffffffffffffffffffffffffbfdbffffffffffffffffffffffffffefffffffdfffbeaf7fffffff7ffffffffb6fffffffffffffffffffffffffefffb6f5fffffffffffffffffffffffff7777fffffff7ffedbfff7fffffffffb6db7bff9fffffffffffffffffffffffffffaffdfbfffffffffffffffffffffffbffffffffffbfffbffffffffffffbeeffffef7f6ffffffffffffffffffffffffffefd5fffffffffffffffffffffffffbfdddffffffbeffbf5ffffffffffefbfff6b7fefbffffffffffffffffffffffffffbfffbfffffffffffffffffffffffdf77ffffffedebb7fffffbdffffefbefffbfdffffd7ffffff7fffffffffffffffffff6fffffffffffffffffffffffffdffffffffbdbf7ffeffffff7dff77dfbfbffd6beff7ffffffffffffffffffffffffed7fbfffffffffffffffffffffff6ff7fffffdf7f7deffffdfffffedfffdffffffbffdfd7fffffffffffffffffffffffbbdbfffffffffffffffffffffffdff7ffffffffeddfbfffffffff77fded77ffffdd5fffdfffffffffffffffffffffffbeefffffffffffffffffffffffff7fbfffffff6dbffffffffefffdffffbfadfffff7ffbfb7fffffffffffffffffffffef77fffffffffffffffffffffffedfdfffffffbfffffffffffffbefdef7faf7fffffdbff7efffffffffffffffffffffffeddb7fffffffffffffffffffffbfffffffffbeb6fbfffffffdbf7f7bfff7adffffffffdfbbffffffffffffffffffffedbbfffffffffffffffffffffffefffffffffdeffffffffffff7f7fdfffffdf7fffff7ff7feffffffffffffffffffffbffff7ffffffffffffffffffffff7ffffffff6f7bffffffffff7edffffffff6aeffffffdffffffffffffffffffffdfffff5dbffffffffffffffffffffffdff7fffffffdffbffffffffdffffffffffffffffffffffffd7ffffffffffffffffffdfdf7ffffffffffffffffffffffffdbffffffddfdffffffffff7db7ffffffffd77ffffffbffffffffffbfffffffffffffff7fffffffffffffffffffffffdbfffffffeff77fffffffffffffffffffffffffffffffffffffffffffffffffffffffff5fdffffffbfffffffffffffffffffffffffeffffffffffffffffdffffffffffeff7ffffdffd7ffdfffffffffffffffff7fffffffffffffffffffffffefffffffffbbffffffffffffffffffdfffffffffffffff7fb7ffffffffffffffffdffffd3fffffffffffffffffffffffbddffffffefffffffffffffffffffffffffffffdffffffeeffeffffffffffffffefffffeaefffffffffffffffffffffffffffffff7dfffffffffffffffff7fffffffffffffffffba9fbbfffffffffffffffffff5bfffffff7ffbbfffffffffffffffffeab96aafffffffff7fffffeffffffffffffffffefa57fffffffffffffffffffffdebff76dbefeffbbfffffffbfffffff7fcab55bfffffffdf7fffffffffffffffb7fffffe81fd7ffffffffffffffffffd6b555fffffdbffffdffffffffffffdbaa6ddaafffffffffffffffbffffffffffffffff7b005ffffffffffffffeffffff5eaaeab7edeffffffddb77ffffdb56cdbb6afe97fffffdffdbfffffffffffffffffffffc007ebfeffffffffffbfffffdbf452ddd7f75fdfef7ffff7ffefdaab6ddffbb5fffffff7ffffffdffffffffffdfffffed005ffffffffffffffffffffeff9092554aaeaf57bf77dfffdbaaaaab77daffafffffeffefefff7fffffffffffffffff8003ebffffffffffffffffffd5d44490213baa2b555dd7baaeaaddb7ddf7fded7ffffbffbffdfffffffffffffffffffd4005ffffffffffffffffffffebfb2804804ad094ab6abd6db5556fedefdfb77afffffffefff7fffffffffffffb7fffff4043efffffffeffffdffffffbed48250082da8421492a292daabbabf7f7ddbffffffefeb4affffbffffffffffffffffd0105fbffffffbfffffffffffe7fa280242aad511410488417addffedf5f6bd6affffbfd802bf7ff7fffffffffffffffe8a03effffffbffffffffffffdaa902a92955744814202105edff6d5f7fdad7f7ffffff60007fffdffffffffffdffffdd0a82ffffffffffffffffffffabea542495aaa81240828012f6ffffbbff76eadbffffff40002fff7ffffffffff7fffbfe1e83fbffffffffffffffffffcbe8914944a9748094142a8bdbfbfdeeffdb5fedfffefd0000176fffffffffffffffdffa2b41effffffffffffffffffeadb52a24236ab22a0949446fefffdf5fbffdebf7fffff400000bfffffffffffbff7ffffc1f82ffffffffffffffffffffd6d491428aaad490a4252a9ff7df7bfdfd57bfafffeffa011007ffdffffffffffdfffff42ec3f7fdfffffffffffffffd7b524a282575524a5294a45f5f77feb7fffeefdffefdd0040002fffffffffffff7fffffa3ba2fffffffffffffffffffffdb820828adb55512922913fbfffedfedb6fbf6fefefe8104001f7fffffffffffffffff44ec3d7ffff7ffffffffffff57fd50a20256dc888844908dedbbdbffffffd6abeffbf40000802ffbffffffffffffefff137e57ffffffffffffffffffffffa40954ad6a252511442ff7eeffbffb7f7bd5bfbf780400200bfffffffff7ffbffdff8db52dbfffffffffffffffffaffed2a4202b69100844229fad7bb6f7ededcab7fbffd41000040ffdffffbfbfffff7ffe877c3effffffffffffffffffbfffed528a1550452212905fabaedb5d76b6b6dffffbf00000100777fffffefffedbf7ff15deabffffffffffffffffffdb7ffeaa5096a01095448b775d756d579aaadbbfffffd020000005fffffffffffffffffe8b6d37ffffffffffffffffffbfffbbfdaa55a54a201254bfabaeb6d4ebbb7effffffe000240005fffffffffff76ffffb0dbe5dffffffffffffffffffefdbffefefbad2a95549037feefbffff7eefefefffff8080920403fbffffffffbffffffe86ad2fffffffffffffffffff7fffffbfbeef6d5555245aff7ffffbf7dbffffbffffbc0017d0105fffffbfffefedffff61abd5bffffffffffffffffffdffeddfefffbbffedadb57fffffffffeffffffffffef2205daa001edfffffffffffffffd8eae37ffdfffff7fffffffffbfffff6bf7beff6ffff7ffffffffffffffffffffffff00057f8002fffffffbbbffffff76177aaffffffffffffffffffffffffdbf5defedffffdfffffffffffffffbb6efffffe8017ffe081ffffffdffffefff7dd0dae5ffdffffffffffff7fffaf7ffffbfebbbffdef7fffffff776f6fddffffffffdf041b57d00176feeffeffffdfbf7c16debffffffffffffffffffffffffefebbfff5577ffedb77edfffdfefffffffffffc005f2ff001fffffefffffffdfffe0b7d2fffffffffffffffffff5dfffbfffffddffdddfbfffeffdbffffffffffffff7e003e9fe820fbfffbffffff77fffa2d9ebfffffffffffffffffffffbffffffffffadf7fefffdfffff77fffffffffffff9105f0efa017fffdfffffffdfdd7c0aecbffffffbf7ffffffffff5fffffffffffffffdfffff7feffffffffffffffffffa00bebf7401fffeffffffedfffffc2f5e7fffffffffffffffffffd6fffefffffffffff7fffffffffffffffffffffffef8005716dc106dffffffffffbffbba1ebabfffffffffffffffffff6ffffbffffffffff5ffffffffffffffffffffffffff402afdefa017ffffffffeffedaff817d57fffffffffffffffffffd2fffffffffffffffffffffffffffffffffffffffff80116babd00ffffffffb7feff7efa1abc7fffffffffffffffffffadffffffffffffffdfffffffffffffffffffffffff68444fdefc20befffffeffbbb7fbe80fd55fffffffffffffffffffeb55bf7fffffffff7ffffffffffffffffbbbbbfffdf00305ebbe80fffffff7fffffdbfd015b6bffffffffffffffdffffb5eaf5ffffffffffeffffffffffffffddfffffbfffe80417fefe017dffffdffeeeafff400f797fffffffffffffffffffeb5297ffffffffffbfffffffffffffffffefffffffd00787abee80bfffff7feffbfff52215ed7fffffffffffffffffffedd049fffffffffffffffffffff7bfeffeff7ffff7e00543ffbe017ffeeffefb5fffd4000ab5ffff7dfffffffffffffff76001ffffffffff6ffffffffffffbbfffffffffffd00babd6ff80fffffdffbffffad00817e8bffffff7ffffffffffffd59002ffffffffffffffffffffffffffbfffffffffc08fd6fd5e417dfbbff7edfdaaa0000ab2aafffffffffffffffffff5c081fffffff7bfafffffffffdffffefbffffffffc207f5ad3f00ffbfffbd7ff750800205e8255ffffffffffffffffff6a2257ffffffffff6effffdfdfddefbeeb7fffff7a015fabc2e82bdfffbefffdd00102007e000fffffffffffffffffff548815556ffffff92b55577afb77bafbfdfffffffc00ffeea5f40fff76effeeb20000000150017ffffffffffffffffff6822042bbffffffc80956dffafdadf56aeaffffff4017eb5975817effffbffb4000008905a002ffffffff7fffffffffdb5082004555bfffc020113fdfad76aedf5bffbffda21ffdf6bf01fffadbfed40000020020000bfffffffdffffffffff7da008881025556f50828007f6fe9fdbb5ed5fffff800ab75dfec0bbbffff751000000000102b7ffffffffffffffffffefc100410200095ba0000012fffd577eff76ffffbfa02bddf7ff02feedffd800000000124000bfffffffffffffffffffbef442242001208a85152105ffff57fbeddd5ffffe8016abdfff816dfffee5000000000000157fffffffffffffffffffebd210800004020100000402ffffabffffffbfffff401f6ff55aa1ffffaa100000000000004bffffffffffffffffffffbffda00012514008000280a83fffebfff6f6d7ffff002dadb56f00bf7fe9000000000000013fffffffffffffffffffffebff55408004080091242800afffeaeedfbfaffffe8017b7ea5d82fdf5200000000000002afffffffffffffffffffffff6fffab524008084440102401ffffabbfbef57ffff442d5ed83e41ffda040000000000adaf7ffffffffffffffffffffffbbfffda908000228954400807fffd5edeb7abfffe00157b747f02ff4000000000000237fffffffffffffffffffffffffdd5fffed52a44082001122112fffeab776d56ffff002aaedcbe83f550000000000011dffffffffffffbffffffffffffff56b77ffed521010000008442ffff6ddbbbedffbd01057b7ebe0ad00000000000004f7ffffffffff7efffffffffffffff55ddffdbfbaa500004882100bff7b76deeb7fffe8415fdb7fe85200000000000015ffffffffffffffffbffffffffffffd6b757fffefaab49100204117f5ffbbebbfffffe0017f6df7d02800000000000157fffffffffffbfffffffffffffffff7bdaedffffefedb54548004455fdaeebefb6fffe002fdbb5ee1000000000000057ffffffffffffffffffffffffffffffff7f555fbffffffeb5215112bf6ffdff7efffffe841fefd7fc000000000000015fffffffffffffffffffffffffffffffffebd0a4ebfffff7ffdeaadfedfb77bdfffffbbd001755e1fa80000000000015bfffffffffffffffffffffffffffffffffffe812aeffffffedfbff7bbfdffff7fbfbdffc001fdfd57c10000000000057ffffffffffffffffffffffffffffffffffffe80053555bbffffffffffbffdfffffef7efe080f2b71f40000000000015fffffffffffffffffffffffffffffbffffffff502042aeeefffffffffff76fdbfdfbffbf5022b57eaba000000000015fffffffffffffffffffffffffffffffffffffffe80000213757ffff7fffffff7f6fbfffffe000e9df5e8100000000057fffffffffffffffffffffffffffffbfffffffffe4000008895aaadbfffddffbffffffffff80005175ff40000000002bffffffffffffffffffffffffffffffffffffffffb00000002024b76fdbffffffffffffffffa04141eb768800000002affffffffffffffffffffffffffffffffffffffffd50000000000048aabffffffffffffffffe800023d7fe00000000057ffffffffffffbffffffffffffffffffffffffffaa8400000000010215495fffbfffffffdfbb004095caff0000000055ffffffffffffffffffffffffffffffffffffdff4a010000000000000402252aaeddb7bb6fad400082be5fc08000002afffffffffffffffffffffffffffffffffffffffda000000000000000000000a552aadaeedaf4048202f97f5000000057ffffffffffffffffffffffffffffffffffffffee90000000000000000000000809252512a540000801bebf800000055ffffffffffffffffffffdfffffffffffffffffff0000000000000000000000000200000000290000002fded4200002bffffffffffffffffffffffffffffffffffffffffe8000000000000000000000000000000000000122080bf7e80000097ffffffffffffffffffffdfffffffffffffffffffe00000000000000000000000000000000000004000007ffa0000057ffffffffffffffffffffdfffffffffffffffffffff000000000000000000000000000000000000200812097d408002bdfffffffffffffffffffffffffffffffffffffffffe80000000000000000000000000000000000000200002de8000097fffffffffffffffffffffffffffffffffffffffffffea0000000000000000000000000000000000010104016a0100abfffffffffffffffffeffffffffffffffffffffffffffb90000000000000000000000000000000000080000801104027ffffffffffffffffffbfffffffffffffffffffffffffffea80000000000000000000000000000000000081000440009bfffffffffffffffffffffffffffffffffffffffffffffffeb500000000000000000000000000000000081010000002bffffffffffffffffffbfffffffffffffffffffffdffffffffd49000000000000000000000000000000000400200000affffffffffffffffffefffffffffffffffffffffffffffffffff49000000000000000000000000000000020448000157ffffffffffffffbffffffffffffffffffffffffffffffffffffdf6b5000000000000000000000000000000000000025fffffffffffffffffffffffffffffffffffffffffffffffffffffffd4a000000000000000000000000000000101000afffffffffffffffffffffffffffffffffffffffffffffffffffffffffb5548800000000000000000000000000000212bfffffffffffffffffffffffffffffffffffdfffffffffffffffffffffffd551000000000000000000000000000000adffffffffffffffffffffefffffffffffffff7fffffffffffffffffffffffff6aa4000000000000000000000000000a57fffffffffffffffffffffffffffffffffffdfffffffffffffffffffffffffffd5554800000000000000000000492abffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffdaa5480000000000000000152557effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa54400000000000012a2bfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfdab56aaaa924aaaacabfeffffffffffffffffffffffbffffffffffffffffffffffffffffffffffffffffffffffffffff7fffbed555554aadbfeefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbffefbbbbffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbdffff7ffffffffffffffffffffffffffbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfffffffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbeffffffffffffffffffffffffffffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffffffffffffffffffffffffffffffffffffffffefdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffff7efffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbffffffffffffffffffffffffffffffffffffdffffffffffff7fffffffffffffffffffffffffffffffffbffffffffff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffff7ffffffffffffbffffffffffffffffffffffdffffffffffffffffffffffffffffdfffdffffffffffffffffffffffffffffffffffffffbfffffffffffffffffffffff7efbf7ffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfffff7ffffefdfffffffffffffffffffffdfffffffffffffffffffffffffffffffffffffffffffffffffffefffffffefffffffffff7fffffffffffffffffffffffffbffffffffffffffffffffffffffffffffffffbffffffffffffbfffffff7fffffffffffffffffffffffffffffffffffffffffffffbfffffffffffffffffffffffffffffffbffffffbfefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbffffffeffbffffffffffffff7fffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffdffeffffffff7ffffffffdfffffffffffffffffffffffffdfffeffffeff7ffffffffffffbffffffffffffffffffffffffffbfffffffbffffffffffffffffffffffffffffffffffbfffffffffffdffdfffffffffffffffffffffbffffffffffffffefffffffffffffffffffffffffffffffffbffffffffeffffffffffffffdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbffffffffffffffffffffffffffffffffffffffffbfffffff7bfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfffffffffffffffbfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffdfffffffeffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + 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 - 240) // 2) + + cmd = f"BITMAP 0,{y_offset},48,240,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}") diff --git a/websocket_server/server.py b/websocket_server/server.py index acc153e..dc92e56 100644 --- a/websocket_server/server.py +++ b/websocket_server/server.py @@ -526,11 +526,11 @@ def optimize_prompt(asr_text, progress_callback=None): if progress_callback: progress_callback(0, "正在准备优化提示词...") - system_prompt = """你是一个AI图像提示词优化专家。将用户简短的语音识别结果转化为详细的、适合AI图像生成的英文提示词。 + system_prompt = """你是一个AI图像提示词优化专家。将用户简短的语音识别结果转化为详细的、适合AI图像生成的中文提示词。 要求: -1. 保留核心内容和主要元素 -2. 添加适合AI绘画的描述词(风格、光线、氛围等) -3. 用英文输出 +1. 用于热敏打印机的中文提示词图片 +2. 添加适合AI绘画的描述词尺寸宽48mm, 高30mm 的线稿图片,线稿要存粗方便热敏打印 +3. 适合热敏打印机打印图片,还可以是icon方便这个标签打印机打印效果 4. 简洁但描述详细 5. 不要添加多余解释,直接输出优化后的提示词"""