如何用Groovy通过ESC/POS指令在Star MC-Print3打印机打印图片?
问题:Groovy脚本实现Star MC-Print3热敏打印机的ESC/POS图片打印
我正在编写Groovy脚本,使用Star MC-Print3热敏打印机和ESC/POS指令打印票据。目前已成功实现文本对齐、文本打印、切纸等基础打印功能,但在使用ESC/POS指令打印图片时遇到困难。
我需要在票据上打印图片(接收的是位图的Base64字符串),但不清楚如何向打印机发送图像数据。我知道ESC/POS支持位图打印,但不确定将图像转换为所需格式并正确发送到打印机的具体步骤。
以下是我当前未包含图片打印功能的脚本:
def printTicket(String ticketNumber) { println 'Printer' // Replace with your printer's IP address and port def PRINTER_IP = '192.168.1.3' def PRINTER_PORT = 9100 try { // Create a socket connection to the printer Socket client = new Socket(PRINTER_IP, PRINTER_PORT) println 'Connected to printer' OutputStream out = client.getOutputStream() // Example ESC/POS commands for a basic ticket byte[] initPrinter = [0x1B, 0x40] // Initialize printer byte[] centerAlign = [0x1B, 0x1D, 0x61, 0x01] // Center alignment byte[] text = 'Hello, Star Printer!\n'.getBytes('UTF-8') // Ticket text byte[] ticketText = ticketNumber.getBytes('UTF-8') // Ticket number byte[] lineFeed = [0x0A] // Line feed byte[] cutPaper = [0x1B, 0x64, 0x03] // Cut paper // Send commands to printer out.write(initPrinter) // Initialize printer out.write(centerAlign) // Set alignment to center out.write(text) // Print text out.write(lineFeed) // Add line feed out.write(ticketText) // Print ticket text out.write(lineFeed) // Add another line feed out.write(cutPaper) // Cut paper // Close the connection out.close() client.close() println 'Connection to printer closed' } catch (Exception e) { println "Printer connection error: ${e.message}" } }
问题说明
我在打印图片时遇到困难。据了解ESC/POS支持位图打印,但我不知道如何:
- 将图像(如PNG/JPG或位图的Base64字符串)转换为打印机可识别的合适字节数组。
- 使用ESC/POS指令将该图像数据发送到打印机。
已尝试的操作
我知道需要将图像转换为单色(1位每像素)的位图格式,也查到了用于打印位图的GS v 0指令,但不确定如何构造图像数据或处理不同的图像格式。
所需帮助
- 图像转换:如何将图像转换为ESC/POS所需的正确字节数组格式?是否需要先转换为单色?
- ESC/POS指令:需要使用哪些指令将图像数据发送到打印机?
- Groovy/Java实现:希望获得Groovy/Java语言的图片打印示例或代码片段。
解答
一、图像转换:必须转为单色位图
ESC/POS打印机仅支持1位单色位图(黑/白,无灰度),转换步骤如下:
- 解码Base64:将Base64字符串转为字节数组,再生成
BufferedImage对象。 - 调整尺寸:根据打印机最大打印宽度缩放图像(Star MC-Print3通常支持最大576点宽度,对应80mm纸)。
- 转为单色:将图像转为1位灰度图,通过亮度阈值判断(比如亮度低于128的像素设为黑色,否则白色)。
- 字节打包:把单色图像的像素按字节打包,每8个像素组成1个字节(从左到右,高位对应左侧像素)。
二、ESC/POS图像打印指令:GS v 0
使用GS v 0指令(十六进制:0x1D 0x76 0x30),指令格式为:
GS v 0 <m> <xL> <xH> <yL> <yH> <图像数据>
各参数说明:
m:打印模式,固定为0x00(正常打印)xL/xH:图像宽度(单位:点)的低/高字节,总宽度 = xL + xH*256yL/yH:图像高度(单位:点)的低/高字节,总高度 = yL + yH*256图像数据:打包后的单色像素字节数组
三、Groovy实现完整示例
以下是集成图片打印的完整脚本,包含Base64图像解码、转换、打印的逻辑:
import java.awt.image.BufferedImage import java.io.ByteArrayInputStream import java.net.Socket import javax.imageio.ImageIO def printTicket(String ticketNumber, String base64Image) { println 'Printer' def PRINTER_IP = '192.168.1.3' def PRINTER_PORT = 9100 try { Socket client = new Socket(PRINTER_IP, PRINTER_PORT) println 'Connected to printer' OutputStream out = client.getOutputStream() // 初始化打印机 out.write([0x1B, 0x40] as byte[]) // 设置居中对齐 out.write([0x1B, 0x1D, 0x61, 0x01] as byte[]) // 处理并打印图片 byte[] imageBytes = Base64.getDecoder().decode(base64Image) BufferedImage originalImage = ImageIO.read(new ByteArrayInputStream(imageBytes)) // 转换为ESC/POS兼容的字节数组 byte[] printImageData = convertToEscPosImage(originalImage) // 发送图像打印指令 sendEscPosImage(out, printImageData, originalImage.width, originalImage.height) // 打印文本和切纸 out.write('Hello, Star Printer!\n'.getBytes('UTF-8')) out.write(ticketNumber.getBytes('UTF-8')) out.write([0x0A] as byte[]) out.write([0x1B, 0x64, 0x03] as byte[]) out.close() client.close() println 'Connection to printer closed' } catch (Exception e) { println "Printer connection error: ${e.message}" e.printStackTrace() } } // 将BufferedImage转为ESC/POS兼容的字节数组 def byte[] convertToEscPosImage(BufferedImage image) { int width = image.width int height = image.height // 计算每行需要的字节数(向上取整) int bytesPerLine = (width + 7) / 8 byte[] imageData = new byte[bytesPerLine * height] for (int y = 0; y < height; y++) { int byteIndex = y * bytesPerLine for (int x = 0; x < width; x++) { // 获取像素亮度,转为黑白(阈值128) int rgb = image.getRGB(x, y) int brightness = (rgb >> 16 & 0xFF) * 0.299 + (rgb >> 8 & 0xFF) * 0.587 + (rgb & 0xFF) * 0.114 boolean isBlack = brightness < 128 // 打包到字节中:每8个像素一个字节,高位对应左侧像素 int bitPosition = 7 - (x % 8) if (isBlack) { imageData[byteIndex + (x / 8)] |= (1 << bitPosition) } } } return imageData } // 发送ESC/POS图像打印指令 def void sendEscPosImage(OutputStream out, byte[] imageData, int width, int height) { byte m = 0x00 byte xL = (byte) (width & 0xFF) byte xH = (byte) ((width >> 8) & 0xFF) byte yL = (byte) (height & 0xFF) byte yH = (byte) ((height >> 8) & 0xFF) // 构造指令头 byte[] commandHeader = [0x1D, 0x76, 0x30, m, xL, xH, yL, yH] as byte[] out.write(commandHeader) // 发送图像数据 out.write(imageData) // 换行 out.write([0x0A] as byte[]) }
注意事项
- 若图像宽度不是8的倍数,转换时会自动补位(右侧补白),避免打印异常。
- Star MC-Print3支持的最大打印宽度为576点,若原图超过此宽度,需先缩放。
- 测试时建议先使用小尺寸图像,避免数据量过大导致打印卡顿。
内容的提问来源于stack exchange,提问作者Kamal Perera
相关产品推荐
相关产品推荐

