Angular通过WebUSB API向MP-4200 TH发送ESC/POS指令实现打印切纸可行吗?
问题描述
我已在Angular应用中通过WebUSB API实现向MP-4200 TH热敏打印机打印纯文本,现希望通过该API向打印机发送ESC/POS指令,实现打印并让打印机自动完成切纸操作,请问是否可以实现?
现有代码
app.component.ts
@Component({ selector: 'app-root', templateUrl: './app.component.html' }) export class AppComponent { private usbDevice: any; private textToProint: any[] = [ 'SIZE 48 mm,25 mm', 'CLS', 'TEXT 30,10,"4",0,1,1,"HackerNoon"', 'TEXT 30,50,"2",0,1,1,"WebUSB API"', 'PRINT 1', 'END', ]; async connect() { try { this.usbDevice = await (navigator as any).usb.requestDevice({ filters: [{ VendorID: 0x0B1B, ProductID: 0x0003 }] }); console.log('Connected to USB device:', this.usbDevice); } catch (error) { console.error('Error connecting to USB device:', error); } } async disconnect() { try { if (this.usbDevice) { await this.usbDevice.close(); console.log('Disconnected from USB device.'); } } catch (error) { console.error('Error disconnecting from USB device:', error); } } async send() { console.log(this.usbDevice, 'Sending'); try { if (this.usbDevice) { console.log("USB device opened:", this.usbDevice.configuration.interfaces[1]); await this.usbDevice.open() .then(() => this.usbDevice.selectConfiguration(1)) .then(() => this.usbDevice.claimInterface(this.usbDevice.configuration.interfaces[1]?.interfaceNumber)) await this.usbDevice.transferOut( this.usbDevice.configuration.interfaces[1]?.alternate.endpoints.find((obj: any) => obj.direction === 'out').endpointNumber, new Uint8Array( new TextEncoder().encode(this.textToProint.join('\r\n')) ) ); await this.usbDevice.releaseInterface(0); await this.usbDevice.close(); console.log("Data sent to printer:"); } } catch (error) { console.error("Error connecting to printer:", error); } } }
app.component.html
<div> <body> <button style="background-color: blue; cursor: pointer; color: aliceblue; border-radius: 12px; margin: 2px; padding: 4px; align-items: center;" (click)="connect()">Connect to USB Device</button> <button style="padding: 4px; margin: 4px; cursor: pointer; border-radius: 12px; background-color: blueviolet; color: white;" (click)="send()">Send Data</button> <button style="padding: 4px; margin: 4px; cursor: pointer; border-radius: 12px; background-color: darkred; color: white;" (click)="disconnect()">Disconnect</button> </body> </div>
解答
完全可以实现。你当前代码使用的是打印机厂商自定义指令集(如SIZE、CLS、PRINT),而ESC/POS是热敏打印机通用指令标准,MP-4200 TH支持该标准,只需替换指令内容即可实现打印+自动切纸。
修改要点
- 构造ESC/POS二进制指令:ESC/POS指令由控制字符(如ESC
0x1B、GS0x1D)和参数组成,需直接构造Uint8Array字节数组,不能用TextEncoder转字符串(会丢失控制字符)。 - 核心ESC/POS指令:
- 初始化打印机:
ESC @(0x1B, 0x40) - 设置字体大小:
GS ! n(n为参数,控制字体倍宽倍高) - 自动切纸:
GS V 0(0x1D, 0x56, 0x00,全切纸)或ESC i(0x1B, 0x69,部分切纸,可根据打印机支持选择)
- 初始化打印机:
修改后的app.component.ts关键代码
export class AppComponent { private usbDevice: any; // 构造ESC/POS指令字节数组 private getEscPosData(): Uint8Array { const encoder = new TextEncoder(); const parts: Uint8Array[] = []; // 初始化打印机 parts.push(new Uint8Array([0x1B, 0x40])); // 设置字体为2倍宽高(GS ! 0x10) parts.push(new Uint8Array([0x1D, 0x21, 0x10])); // 打印标题文本 parts.push(encoder.encode("HackerNoon\n")); // 恢复默认字体大小 parts.push(new Uint8Array([0x1D, 0x21, 0x00])); // 打印副标题 parts.push(encoder.encode("WebUSB API\n")); // 空两行 parts.push(encoder.encode("\n\n")); // 全切纸指令(GS V 0) parts.push(new Uint8Array([0x1D, 0x56, 0x00])); // 合并所有字节数组 const totalLength = parts.reduce((sum, arr) => sum + arr.length, 0); const result = new Uint8Array(totalLength); let offset = 0; for (const arr of parts) { result.set(arr, offset); offset += arr.length; } return result; } async send() { console.log(this.usbDevice, 'Sending'); try { if (this.usbDevice) { await this.usbDevice.open() .then(() => this.usbDevice.selectConfiguration(1)) .then(() => this.usbDevice.claimInterface(this.usbDevice.configuration.interfaces[1]?.interfaceNumber)); const endpoint = this.usbDevice.configuration.interfaces[1]?.alternate.endpoints.find((obj: any) => obj.direction === 'out').endpointNumber; // 发送ESC/POS指令 await this.usbDevice.transferOut(endpoint, this.getEscPosData()); await this.usbDevice.releaseInterface(this.usbDevice.configuration.interfaces[1]?.interfaceNumber); await this.usbDevice.close(); console.log("ESC/POS指令已发送,打印机将执行打印并切纸"); } } catch (error) { console.error("打印机操作出错:", error); } } // connect和disconnect方法保持不变 async connect() { /* 原有代码 */ } async disconnect() { /* 原有代码 */ } }
注意事项
- 若
GS V 0切纸指令无效,可尝试替换为ESC i(0x1B, 0x69)实现部分切纸。 - 原代码中
releaseInterface(0)存在错误,应释放之前claimInterface获取的接口编号(即this.usbDevice.configuration.interfaces[1]?.interfaceNumber),否则可能导致后续连接失败。
内容的提问来源于stack exchange,提问作者Dhinakar
相关产品推荐
相关产品推荐

