import socket import os from io import BytesIO from PIL import Image, ImageDraw # 引入条形码生成库 try: import barcode from barcode.writer import ImageWriter except ImportError: print("❌ 错误: 请先安装 python-barcode (pip install python-barcode)") exit() class BarcodeStackTester: # 打印机配置 PRINTER_IP = "192.168.9.205" PRINTER_PORT = 9100 # 纸张配置: 40mm x 30mm @ 300 DPI DOTS_PER_MM = 12 CANVAS_W = int(40 * DOTS_PER_MM) # 480px CANVAS_H = int(30 * DOTS_PER_MM) # 360px @staticmethod def _generate_raw_barcode(content, bar_height_mm=4): """ 生成原始条码图片 (不强制缩放宽度,让其自然生长) """ try: # Code128 自动优化 (数字会被压缩,所以20位数字其实不长) writer = ImageWriter() # module_width: 条码黑条的最小宽度(mm)。 # 0.2mm 在 300DPI 下约等于 2.4像素。这是一个比较清晰且节省空间的数值。 # 如果设得太大(如0.3),20位可能会超出40mm纸张。 options = { "module_width": 0.2, "module_height": bar_height_mm, # 条码高度 "quiet_zone": 2.0, # 两侧留白(mm) "write_text": False, # 【关键】不写文字 "dpi": 300 # 对应打印机DPI } code_img = barcode.get('code128', content, writer=writer) # 渲染到内存 buffer = BytesIO() code_img.write(buffer, options=options) buffer.seek(0) return Image.open(buffer) except Exception as e: print(f"生成失败: {e}") return None def run_test(self): # 1. 创建白色底图 (40x30mm) canvas = Image.new('RGB', (self.CANVAS_W, self.CANVAS_H), color='white') # 测试用例: 长度从小到大 test_lengths = [13, 15, 17, 20] # 布局参数 current_y = 20 # 顶部起始留白 (px) gap = 10 # 间距 (px) print("-" * 50) print("🚀 开始生成堆叠条码测试图...") for length in test_lengths: # 生成全7的内容 content = "7" * length print(f" 正在处理: {length}位 -> {content}") # 生成条码 (高度设为5mm左右,方便在一张纸上放下4个) bar_img = self._generate_raw_barcode(content, bar_height_mm=5) if bar_img: # 计算居中位置 # bar_img.width 是条码生成的自然宽度 x_pos = (self.CANVAS_W - bar_img.width) // 2 # 如果宽度超出了纸张 (x_pos < 0),说明40mm纸打不下这么多位 if x_pos < 0: print(f" ⚠️ 警告: {length}位条码过宽 ({bar_img.width}px > {self.CANVAS_W}px),可能会被裁切!") x_pos = 0 # 粘贴到画布 canvas.paste(bar_img, (x_pos, current_y)) # 更新Y坐标,准备画下一个 current_y += bar_img.height + gap else: print(" 生成失败") # 2. 保存预览图 preview_file = "test_stack_preview.jpg" canvas.save(preview_file) print(f"✅ 图片已生成: {preview_file} (请打开查看宽度是否超出)") # 3. 发送打印 (二值化处理) self._send_to_printer(canvas) def _send_to_printer(self, img_rgb): try: # 转二值化 (白=1, 黑=0) img_bw = img_rgb.convert('L').convert('1', dither=Image.Dither.NONE) bitmap_data = img_bw.tobytes() width_bytes = (img_bw.width + 7) // 8 height_dots = img_bw.height # TSPL 指令 header = ( f"SIZE 40 mm, 30 mm\r\n" "GAP 2 mm, 0 mm\r\n" "CLS\r\n" "DIRECTION 1\r\n" ).encode('gbk') bitmap_cmd = f"BITMAP 0,0,{width_bytes},{height_dots},0,".encode('gbk') footer = b"\r\nPRINT 1,1\r\n" print("🖨️ 正在发送打印指令...") s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.settimeout(5) s.connect((self.PRINTER_IP, self.PRINTER_PORT)) s.sendall(header + bitmap_cmd + bitmap_data + footer) s.close() print("✅ 指令已发送") except Exception as e: print(f"❌ 打印失败: {e}") if __name__ == "__main__": tester = BarcodeStackTester() tester.run_test()