裁剪Canvas底部后转ESC/POS指令出现提前切纸问题求助
问题分析与修复
你的问题出在图像数据的字节数计算错误以及ESC/POS图像命令的宽度参数错误,导致打印机在处理图像数据时误读了后续的切纸命令,从而提前执行切纸操作。
核心问题点
- 每行字节数计算错误:当Canvas宽度不是8的倍数时,你使用
width >>3(向下取整)计算每行的字节数,但实际上需要向上取整到8的倍数(即Math.ceil(width/8)),否则每行的像素数据会被截断,总图像数据长度不足,打印机会将后续的切纸命令字节当成图像数据的一部分读取,触发提前切纸。 - 图像命令宽度参数错误:ESC/POS的
GS v 0命令要求传入的宽度参数是每行实际使用的字节数(向上取整后的值),而你传入的是向下取整的结果,导致打印机对图像数据的解析出现偏差。 - 像素越界读取:当处理最后一组不足8个像素的列时,代码会读取超出Canvas宽度范围的像素,引入错误数据。
修复后的代码
const canvasToEscpos = (canvas) => { const context = canvas.getContext("2d"); const { data } = context.getImageData(0, 0, canvas.width, canvas.height); let width = canvas.width; let height = canvas.height; // 裁剪底部连续空行逻辑(原逻辑保留) let emptyLines = 0; for (let y = height - 2; y >= 0; y--) { let empty = true; for (let x = 0; x < width; x++) { empty &&= data[(width * y + x) * 4] > 248; if (!empty) break; } if (empty) { emptyLines++; } else { break; } } console.log({ emptyLines }); height -= emptyLines + 1; // 修正:计算每行实际需要的字节数(向上取整到8的倍数) const bytesPerLine = (width + 7) >> 3; const bytes = new Uint8Array(bytesPerLine * height); // 修正:添加像素越界判断,超出宽度的像素视为白色 const readPixel = (x, y) => { if (x >= width) return 0; return data[(width * y + x) * 4] < 200 ? 1 : 0; }; for (let y = 0; y < height; y++) { for (let x = 0; x < width; x += 8) { const byteIndex = y * bytesPerLine + (x >> 3); for (let b = 0; b < 8; b++) { bytes[byteIndex] |= readPixel(x + b, y) << (7 - b); } } } const buffer = new Uint8Array(10 + bytes.length + 3); // 修正:图像命令中的宽度参数使用bytesPerLine buffer.set( [ 0x0a, 0x0d, 0x1d, 0x76, 0x30, 0x00, bytesPerLine & 0xff, (bytesPerLine >> 8) & 0xff, height & 0xff, (height >> 8) & 0xff, ], 0 ); buffer.set(bytes, 10); buffer.set([0x1d, 0x56, 0x00], buffer.length - 3); return buffer; };
修复说明
- 每行字节数修正:用
(width +7) >>3替代width>>3,实现向上取整计算每行所需字节数。 - 图像命令参数修正:将命令中的宽度参数改为
bytesPerLine,确保打印机正确解析每行数据长度。 - 像素越界处理:在
readPixel中添加x >= width的判断,超出范围的像素直接返回0(白色),避免读取错误数据。
这些修正会确保图像数据的长度与命令声明的参数完全匹配,打印机不会将切纸命令误判为图像数据,从而解决提前切纸的问题。
内容的提问来源于stack exchange,提问作者user9559682
相关产品推荐
相关产品推荐

