通过Socket在热敏打印机打印图片的Python技术求助
解决网络热敏打印机Socket打印图片的问题
问题原因
直接发送原始JPG字节流给打印机,打印机会将这些字节解析为ASCII字符输出,而非图片数据,所以出现乱码/无限字符流。热敏打印机(多数遵循ESC/POS协议)需要先接收控制指令,切换到图片打印模式,再发送处理后的图片数据。
解决方案
方法1:使用现成ESC/POS库(推荐)
python-escpos库已封装所有ESC/POS指令,支持网络打印机,无需手动处理指令:
首先安装库:
pip install python-escpos
编写Socket打印脚本:
from escpos.printer import Network # 连接网络打印机 p = Network("192.168.1.56", port=9100) # 打印图片(自动处理格式转换和指令封装) p.image("immagine.jpg") # 切纸(可选,根据打印机支持) p.cut() # 关闭连接 p.close()
方法2:手动构造ESC/POS指令(适合自定义需求)
若不想依赖第三方库,需先将JPG转为单色位图(热敏打印机通常仅支持黑白),再用ESC/POS指令包裹发送:
核心步骤:
- 用Pillow将图片转为适配打印机宽度的单色位图
- 发送ESC/POS指令
ESC *切换到位图模式 - 逐行发送位图数据
- 发送换行/切纸指令
示例代码:
import socket from PIL import Image def convert_to_printer_image(image_path, max_width=384): # 转换为单色位图,适配多数热敏打印机的384像素宽度 img = Image.open(image_path).convert("L") width, height = img.size if width > max_width: ratio = max_width / width height = int(height * ratio) img = img.resize((max_width, height), Image.Resampling.LANCZOS) # 转为1位深度黑白图 img = img.point(lambda x: 0 if x < 128 else 255, '1') return img def send_image_to_printer(ip, port, img): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((ip, port)) width = img.width height = img.height # ESC/POS位图指令:ESC * m nL nH d1...dk,m=0表示8点密度 byte_width = (width + 7) // 8 cmd = b'\x1B\x2A' + b'\x00' + byte_width.to_bytes(2, byteorder='little') # 逐行发送位图数据 for y in range(height): row = [] for x in range(byte_width): byte = 0 for bit in range(8): pos_x = x * 8 + bit if pos_x < width and img.getpixel((pos_x, y)) == 0: byte |= (1 << (7 - bit)) row.append(byte) sock.sendall(cmd + bytes(row) + b'\x0A') # 切纸指令 sock.sendall(b'\x1B\x69') sock.close() # 执行打印 img = convert_to_printer_image("immagine.jpg") send_image_to_printer("192.168.1.56", 9100, img)
关于你找到的脚本适配
你提到的脚本核心是将图片转换为适合热敏打印机的格式并生成ESC/POS指令流,完全可以适配成Socket传输:
- 保留脚本中图片处理、指令生成的逻辑
- 将原来的打印输出逻辑替换为Socket发送,用
sock.sendall()发送生成的指令流给打印机即可 - 这种方式适合需要高度自定义打印逻辑的场景,和手动构造指令的思路一致
内容的提问来源于stack exchange,提问作者Davide Michelotti
相关产品推荐
相关产品推荐

