BMP转数据流打印失败,遇strReadFile.BaseStream.ReadTimeout异常求助
问题分析与解决方案
核心问题1:用StreamReader读取二进制BMP文件
StreamReader是为文本文件设计的,会对字节进行编码转换,破坏BMP的二进制结构;同时访问其BaseStream.ReadTimeout会触发InvalidOperationException——因为FileStream的同步读取不支持超时属性,直接访问会抛出异常。必须用FileStream读取二进制数据。
核心问题2:文件删除时机错误
在调用paint()后立刻删除led.bmp,此时paint()可能还在读取该文件,会导致文件占用或找不到的问题,需在paint()执行完成后再删除。
核心问题3:DOWNLOAD命令的长度参数写死
打印机的DOWNLOAD命令需要传入图片的实际字节数,写死4094会导致数据长度不匹配,打印机无法正确解析图片。
额外优化:BMP像素格式兼容性
多数USB热敏/标签打印机仅支持单色(1bpp)BMP,24bpp的彩色BMP可能无法被识别,需转换为单色位图。
修改后的完整代码
1. 添加单色位图转换方法
private Bitmap ConvertToMonochrome(Bitmap original) { Bitmap monochrome = new Bitmap(original.Width, original.Height, PixelFormat.Format1bppIndexed); using (Graphics g = Graphics.FromImage(monochrome)) { // 灰度化矩阵,将彩色转为灰度后再转为单色 ColorMatrix colorMatrix = new ColorMatrix( new float[][] { new float[] {0.299f, 0.299f, 0.299f, 0, 0}, new float[] {0.587f, 0.587f, 0.587f, 0, 0}, new float[] {0.114f, 0.114f, 0.114f, 0, 0}, new float[] {0, 0, 0, 1, 0}, new float[] {0, 0, 0, 0, 1} }); ImageAttributes attributes = new ImageAttributes(); attributes.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); g.DrawImage(original, new Rectangle(0, 0, original.Width, original.Height), 0, 0, original.Width, original.Height, GraphicsUnit.Pixel, attributes); } return monochrome; }
2. 修改按钮点击事件(调整BMP保存与删除时机)
private void button3_Click(object sender, EventArgs e) { using (Bitmap bmp = new Bitmap(panel1.Width, panel1.Height, PixelFormat.Format24bppRgb)) { panel1.DrawToBitmap(bmp, new Rectangle(0, 0, panel1.Width, panel1.Height)); // 转换为单色BMP并保存 using (Bitmap monoBmp = ConvertToMonochrome(bmp)) { monoBmp.Save("led.bmp", ImageFormat.Bmp); } } paint(); // 等待打印逻辑完成后再删除文件 File.Delete("led.bmp"); }
3. 修改paint方法(修复文件读取与DOWNLOAD命令)
private void paint() { NewUsb.FindUSBPrinter(); for (int i = 0; i < NewUsb.USBPortCount; i++) { if (NewUsb.LinkUSB(i)) { SendData2USB("SIZE 58 mm,60 mm\r\n");//标签尺寸 SendData2USB("GAP 0 mm,0 mm\r\n");//间距为0 SendData2USB("CLS\r\n");//清空缓冲区 SendData2USB("DENSITY 7\r\n");//打印浓度 SendData2USB("REFERENCE 0,0\r\n"); SendData2USB("TEXT 15,10,\"1\",0,1,1,\"asdfggDDD\"\r\n"); SendData2USB("TEXT 15,60,\"TSS24.BF2\",0,1,1,\"简体字\"\r\n"); // 用FileStream读取二进制BMP文件 byte[] byteReadData; using (FileStream fs = new FileStream(@"./led.bmp", FileMode.Open, FileAccess.Read)) { byteReadData = new byte[fs.Length]; int bytesRead = 0; // 循环读取确保完整获取所有字节 while (bytesRead < byteReadData.Length) { bytesRead += fs.Read(byteReadData, bytesRead, byteReadData.Length - bytesRead); } } // 替换固定长度为实际字节数 SendData2USB($"DOWNLOAD \"led.bmp\",{byteReadData.Length},"); SendData2USB(byteReadData);//发送BMP二进制数据 SendData2USB("PUTBMP 14,110,\"led.bmp\"\r\n"); SendData2USB("PRINT 1\r\n"); NewUsb.CloseUSBPort(); } } }
4. 保留原有的SendData2USB方法
private void SendData2USB(byte[] str) { NewUsb.SendData2USB(str, str.Length); } private void SendData2USB(string str) { byte[] by_SendData = System.Text.Encoding.GetEncoding(54936).GetBytes(str); SendData2USB(by_SendData); }
额外检查点
- 确认打印机指令格式:部分打印机的
DOWNLOAD命令不需要末尾的逗号,若仍无法打印,可尝试修改为SendData2USB($"DOWNLOAD \"led.bmp\",{byteReadData.Length}\r\n");,再发送二进制数据。 - 检查PUTBMP的坐标:确保图片坐标在标签尺寸范围内(58mm×60mm),避免图片超出打印区域。
- 验证USB连接:确保
NewUsb.LinkUSB(i)成功连接到目标打印机,可添加日志输出确认连接状态。
内容的提问来源于stack exchange,提问作者Wenbin Geng
相关产品推荐
相关产品推荐

