Android蓝牙连接ESC/POS打印机 如何调小字号并取消下划线打印
核心问题定位
从你提供的代码和打印表现,两个异常(字号过大、全文本带下划线)都是指令参数不符合ESC/POS标准导致的:
下划线无法消除的根源
- 你的
PrinterCommands类完全没有定义下划线控制指令,整个打印流程也从未下发过「关闭下划线」的指令,打印机保留了默认的下划线开启状态,所有打印内容自然带线。 - 标准ESC/POS协议中,控制下划线的指令为
ESC - n:参数n=0x00表示完全关闭下划线,n=0x01/0x02表示开启1点/2点宽度的下划线。
字号过大的根源
- 你用来设置字号的
ESC ! n指令(即代码中0x1B, 0x21, 参数值)完全用错了参数位定义:标准
ESC ! n的位功能定义:- bit 0(对应值0x01):切换A/B字体
- bit 3(对应值0x08):开启/关闭垂直倍高
- bit 4(对应值0x10):开启/关闭水平倍宽
- 你代码里size=0(预期普通字号)时发送的参数是0x03,同时触发了两个非预期的位效果,根本不是正常字号;用来对应大字号的参数0x10只单独开启了水平倍宽,没有匹配你预期的字号层级。
- 另外你
resetPrint方法里的FS_FONT_ALIGN指令参数错误,给汉字模式强行开启了倍高效果,进一步放大了实际打印的字号。
具体修改方案
1. 补全并修正PrinterCommands类的指令定义
删掉原有错误的指令,替换为符合协议的版本:
public class PrinterCommands { public static final byte LF = 0x0A; public static byte[] FEED_LINE = {10}; public static final byte[] ESC_FONT_COLOR_DEFAULT = new byte[] { 0x1B, 'r',0x00 }; // 替换原有错误的FS_FONT_ALIGN,改为汉字模式重置指令 public static final byte[] FS_FONT_RESET = new byte[] { 0x1C, 0x21, 0x00 }; public static final byte[] ESC_ALIGN_LEFT = new byte[] { 0x1b, 'a', 0x00 }; public static final byte[] ESC_ALIGN_RIGHT = new byte[] { 0x1b, 'a', 0x02 }; public static final byte[] ESC_ALIGN_CENTER = new byte[] { 0x1b, 'a', 0x01 }; public static final byte[] ESC_CANCEL_BOLD = new byte[] { 0x1B, 0x45, 0 }; // 新增:关闭下划线的标准指令 public static final byte[] ESC_CANCEL_UNDERLINE = new byte[] { 0x1B, 0x2D, 0x00 }; }
2. 修正初始化重置逻辑,从打印开头就关闭错误格式
把原有resetPrint方法中的错误逻辑替换掉,每次打印前就强制清掉残留的格式设置:
public void resetPrint() { try{ // 打印前依次下发全量格式重置指令 outputStream.write(PrinterCommands.ESC_CANCEL_UNDERLINE); outputStream.write(PrinterCommands.FS_FONT_RESET); outputStream.write(PrinterCommands.ESC_ALIGN_LEFT); outputStream.write(PrinterCommands.ESC_CANCEL_BOLD); // 强制将默认字号设置为普通大小 outputStream.write(new byte[]{0x1B, 0x21, 0x00}); outputStream.write(PrinterCommands.LF); } catch (IOException e) { e.printStackTrace(); } }
3. 修正printCustom方法的字号参数,适配58mm打印纸
结合58mm纸的可打印宽度(约32个普通英文字符位),把原有错误的字号参数替换为协议标准值:
private void printCustom(String msg, int size, int align) { try { // 按需求匹配对应字号的标准参数 switch (size){ case 0: // 普通正文:无倍高/倍宽,适配常规文本 outputStream.write(new byte[]{0x1B, 0x21, 0x00}); break; case 1: // 中号文本:仅垂直倍高,适合地址、联系方式 outputStream.write(new byte[]{0x1B, 0x21, 0x08}); break; case 2: // 大号标题:垂直+水平倍宽,适合店名 outputStream.write(new byte[]{0x1B, 0x21, 0x18}); break; case 3: // 特大号文本:双倍高+双倍宽,适合主标题 outputStream.write(new byte[]{0x1B, 0x21, 0x18}); break; } // 原有的对齐逻辑保持不变即可 switch (align){ case 0: outputStream.write(PrinterCommands.ESC_ALIGN_LEFT); break; case 1: outputStream.write(PrinterCommands.ESC_ALIGN_CENTER); break; case 2: outputStream.write(PrinterCommands.ESC_ALIGN_RIGHT); break; } // 每段打印前强制确认下划线关闭,避免状态漂移 outputStream.write(PrinterCommands.ESC_CANCEL_UNDERLINE); outputStream.write(msg.getBytes()); outputStream.write(PrinterCommands.LF); } catch (IOException e) { e.printStackTrace(); Toast.makeText(this,e.getLocalizedMessage(),Toast.LENGTH_SHORT).show(); } }
落地注意事项
- 你代码中直接调用的
printText方法(用来打印订单明细、总金额的逻辑),需要在方法开头同样下发ESC_CANCEL_UNDERLINE和普通字号指令,不然这些文本会继承默认的格式状态,依然出现大字号、带下划线的问题。 - 58mm宽度的打印纸,不建议设置超过2倍倍宽的字号,不然打印内容会超出纸边被截断。
- 打印机的格式状态是持久保存的,不会在每次打印后自动复位,所以一定要在每次打印流程的最开头下发全量重置指令,避免上一次打印的格式残留到本次输出。
内容的提问来源于stack exchange,提问作者Dhiru
相关产品推荐
相关产品推荐

