转:C#并口热敏小票打印机打印位图
最近一直在研究并口小票打印机打印图片问题,这也是第一次和硬件打交道,不过还好,最终成功了。
这是DEMO的窗体:
下面是打印所需要调用的代码:
- class LptControl
- {
- private string LptStr = "lpt1";
- public LptControl(string l_LPT_Str)
- {
- LptStr = l_LPT_Str;
- }
- [StructLayout(LayoutKind.Sequential)]
- private struct OVERLAPPED
- {
- int Internal;
- int InternalHigh;
- int Offset;
- int OffSetHigh;
- int hEvent;
- }
- //调用DLL.
- [DllImport("kernel32.dll")]
- private static extern int CreateFile(string lpFileName, uint dwDesiredAccess, int dwShareMode, int lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, int hTemplateFile);
- [DllImport("kernel32.dll")]
- private static extern bool WriteFile(int hFile, byte[] lpBuffer, int nNumberOfBytesToWrite, ref int lpNumberOfBytesWritten, ref OVERLAPPED lpOverlapped);
- [DllImport("kernel32.dll")]
- private static extern bool CloseHandle(int hObject);
- private int iHandle;
- /// <summary>
- /// 打开端口
- /// </summary>
- /// <returns></returns>
- public bool Open()
- {
- iHandle = CreateFile(LptStr, 0x40000000, 0, 0, 3, 0, 0);
- // iHandle = CreateFile(LptStr, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
- if (iHandle != -1)
- {
- return true;
- }
- else
- {
- return false;
- }
- }
- /// <summary>
- /// 打印字符串,通过调用该方法可以打印需要的字符串
- /// </summary>
- /// <param name="Mystring"></param>
- /// <returns></returns>
- public bool Write(String Mystring)
- {
- //如果端口为打开,则提示,打开,则打印
- if (iHandle != -1)
- {
- OVERLAPPED x = new OVERLAPPED();
- int i = 0;
- //byte[] mybyte = System.Text.Encoding.Default.GetBytes(Mystring);
- byte[] mybyte = Encoding.GetEncoding("GB2312").GetBytes(Mystring);
- bool b = WriteFile(iHandle, mybyte, mybyte.Length, ref i, ref x);
- return b;
- }
- else
- {
- throw new Exception("不能连接到打印机!");
- }
- }
- /// <summary>
- /// 打印命令,通过参数,可以打印小票打印机的一些命令,比如换行,行间距,打印位图等。
- /// </summary>
- /// <param name="mybyte"></param>
- /// <returns></returns>
- public bool Write(byte[] mybyte)
- {
- //如果端口为打开,则提示,打开,则打印
- if (iHandle != -1)
- {
- OVERLAPPED x = new OVERLAPPED();
- int i = 0;
- return WriteFile(iHandle, mybyte, mybyte.Length, ref i, ref x);
- }
- else
- {
- throw new Exception("不能连接到打印机!");
- }
- }
- /// <summary>
- /// 关闭端口
- /// </summary>
- /// <returns></returns>
- public bool Close()
- {
- return CloseHandle(iHandle);
- }
- }
因为我们这里主要是打印条形码和二维码,所以以条形码和二维码为例,写了一个小的调用程序(这里把打印图片的方法贴出来):
- /// <summary>
- /// 打印图片方法
- /// </summary>
- public void PrintOne()
- {
- //获取图片
- Bitmap bmp = new Bitmap(pictureBox1.Image);
- //设置字符行间距为n点行
- //byte[] data = new byte[] { 0x1B, 0x33, 0x00 };
- string send = "" + (char)(27) + (char)(51) + (char)(0);
- byte[] data = new byte[send.Length];
- for (int i = 0; i < send.Length; i++)
- {
- data[i] = (byte)send[i];
- }
- lc.Write(data);
- data[0] = (byte)'\x00';
- data[1] = (byte)'\x00';
- data[2] = (byte)'\x00'; // Clear to Zero.
- Color pixelColor;
- //ESC * m nL nH d1…dk 选择位图模式
- // ESC * m nL nH
- byte[] escBmp = new byte[] { 0x1B, 0x2A, 0x00, 0x00, 0x00 };
- escBmp[2] = (byte)'\x21';
- //nL, nH
- escBmp[3] = (byte)(bmp.Width % 256);
- escBmp[4] = (byte)(bmp.Width / 256);
- //循环图片像素打印图片
- //循环高
- for (int i = 0; i < (bmp.Height / 24 + 1); i++)
- {
- //设置模式为位图模式
- lc.Write(escBmp);
- //循环宽
- for (int j = 0; j < bmp.Width; j++)
- {
- for (int k = 0; k < 24; k++)
- {
- if (((i * 24) + k) < bmp.Height) // if within the BMP size
- {
- pixelColor = bmp.GetPixel(j, (i * 24) + k);
- if (pixelColor.R == 0)
- {
- data[k / 8] += (byte)(128 >> (k % 8));
- }
- }
- }
- //一次写入一个data,24个像素
- lc.Write(data);
- data[0] = (byte)'\x00';
- data[1] = (byte)'\x00';
- data[2] = (byte)'\x00'; // Clear to Zero.
- }
- //换行,打印第二行
- byte[] data2 = { 0xA };
- lc.Write(data2);
- } // data
- lc.Write("\n\n");
- }
在打印过程中,出现一个比较低级的错误,因为小票打印机是并口的,而我电脑是串口的,
所以一直远程在另一台电脑上测试,所以打印出来的图片中间多了一条横线,这个问题解决了多半天,因为我一直考虑到是打印图片中可能少一层循环的问题,所以
顺便把打印图片的原理整理了一下(之前的循环是从网上找到的,感觉应该没问题就没有细研究)。下面分享一下我的理解:
这是打印位图的命令(每一个打印机都会给出这样的说明,可以直接下载到的):
1. ESC* m nL nH d1…dk 选择位图模式
格式: ASCII: ESC * m nL nH d1…dk
十进制: [27] [42] m nL nH d1…dk
十六进制: [1BH][2AH] m nL nH d1…dk
说明:
.设定位图方式(用m)、点数(用nL,nH)以及位图内容(用dk)。
.m=0,1,32,33;0≤nL≤255,0≤nH≤3,0≤d≤255。
k=nL+nH×256(m=0,1);k=(nL+nH×256)×3(m=32,33)。
.水平方向点数为(nL+nH×256)。
.如果点数超过一行,超过其最大点数(与选择的位图方式有关,详 见下表)的部分被忽略。
.d为位图数据字节,对应位为1则表示该点打印,对应位为0,则 表示该点不打印。(k表示数据个数)
.m用于选择位图方式。
m |
模式 |
纵向 |
横向 |
||
点数 |
分辨率 |
分辨率 |
数据个数(k) |
||
0 |
8点单密度 |
8 |
67 DPI |
100 DPI |
nL+nH×256 |
1 |
8点双密度 |
8 |
67 DPI |
200 DPI |
nL+nH×256 |
32 |
24点单密度 |
24 |
200 DPI |
100 DPI |
(nL+nH×256)×3 |
33 |
24点双密度 |
24 |
200 DPI |
200 DPI |
(nL+nH×256)×3 |
这次用的打印机打印是24点双密度的,所以我这里就只解释下m=33的情况。
从代码中可以看出,打印图片过程主要是通过循环一点点打印的,通过
lc.Write(data);
循环写入,当然前面的lc.Write(escBmp)主要是些ESC * m三个参数很容易理解就不多解释了。而data是一个长度为3的byte数组,这个data在打印中起到什么作用呢?
在打印机m=33的模式纵向每次是打印24个点,也就是说,而byte为8个字节,所以需要3个byte类型的树才能完成模式为24点双密码的位图打印方式,通过三个字符来平凑一个像素宽24个像素长的图片,然后循环宽度,来打印图片宽度大小24个像素高度的图片,在通过每次循环24个像素的高度,最终打印出完成的图片。
需要打印的图片:
第一次循环先是高位24像素
然后把宽度分解开,循环每一像素的宽度,然后打印每一像素宽度的图片:
举个例子,假设数组data[d1,d2,d3],d1= 00000111,d2=11111111,d3 =11111111,所以打印出的一个像素宽,24像素高的图片为:
最终通过循环宽度与高度,把最终的位图画出来。
这里我举的是24点密度的例子,通过,如果您有兴趣研究的话,也经常看到这样的代码:
- for (int i = 0; i < ((bmp.Height + 7) / 8); i++)
- {
- _serialPort.Write(escBmp, 0, escBmp.Length);
- for (int j = 0; j < bmp.Width; j++)
- {
- for (int k = 0; k < 8; k++)
- {
- if (((i * 8) + k) < bmp.Height) // if within the BMP size
- {
- pixelColor = bmp.GetPixel(j, (i * 8) + k);
- if (pixelColor.R == 0)
- {
- data[0] += (byte)(128 >> k);
- }
- }
- }
- _serialPort.Write(data, 0, 1);
- data[0] = (byte)'\x00'; // Clear to Zero.
- }
这个很明显就是8点密度的模式,所以他的data长度为1,即需要8个字节就够了。
打印出的效果还是很不错的。
如果大家有兴趣研究网络打印,请参加小崔的博客:http://blog.csdn.net/xiaoxian8023/article/details/8440625#comments
转:C#并口热敏小票打印机打印位图的更多相关文章
- C#并口热敏小票打印机打印位图
原文:C#并口热敏小票打印机打印位图 最近一直在研究并口小票打印机打印图片问题,这也是第一次和硬件打交道,不过还好,最终成功了. 这是DEMO的窗体: 下面是打印所需要调用的代码: class ...
- C#并口热敏小票打印机打印位图包括芯片的写入
下面是打印所需要调用的代码: class LptControl { private string LptStr = "lpt1"; public LptControl(string ...
- C# Lpt 并口热敏小票打印机打印位图
class LptControl { private string LptStr = "lpt1"; public LptControl(string l_LPT_Str) { L ...
- C# 热敏打印机 小票打印机 打印图片
最近一直在研究并口小票打印机打印图片问题,这也是第一次和硬件打交道,不过还好,最终成功了. 这是DEMO的窗体: 下面是打印所需要调用的代码: 因为我们这里主要是打印条形码和二维码,所以以条形码和二维 ...
- c#调用刀片小票打印机
public static bool Print(int orderId, string orderTime) { bool b = true; string cut = ((char)29).ToS ...
- 小票打印机指令集封装(支持EPSON指令)
最近写了一些关于小票打印机的程序,不难,但是记录下来,作为足迹吧. 现在市场上的小票机基本都支持EPSON指令.指令集文档 对指令集进行了自己的封装,方便以后调用: package aheiziUti ...
- 让 Odoo POS 支持廉价小票打印机
为了测试 Odoo 在实际业务中的实施,我们开了一家(马上要开第二家分店)猪肉店.由于预算有限,在实施 Odoo PoS 的时候采购了一台价格为 85 元的爱宝热敏打印机,结果连上 Odoo Posb ...
- 按照已有的模板打印小票<二> ——调用windows打印机打印 可设置字体样式
按照已有的模板打印小票<二> ——调用windows打印机打印 可设置字体样式 之前写过一篇文章<按照已有的模板输出一(如发票)>,是关于如何给已有的模板赋值.在项目的实践过程 ...
- C#热敏打印图片 串口打印图片
原文:C#热敏打印图片 串口打印图片 如图,一步一步慢慢调出来的 //串口通信类 public System.IO.Ports.SerialPort serialPort = null; serial ...
随机推荐
- mac系统快捷键大全详细介绍(全部)
对于使用苹果电脑的操作系统的新人来说,快捷键是个很麻烦的问题,要一个个的找到快捷键也不是很容易的问题,今天这篇文章就解决了到处找快捷键的麻烦. 第一种分类:启用快捷键 按下按键或组合键,直到所需的功能 ...
- UVa-1368-DNA序列
这题的话,我们每次统计的话,是以列为外层循环,以行为内层循环,逐一按列进行比较. 统计完了之后,题目中要求说到要hamming值最小的,那我们就选用该列最多的字母就可以了,如果有数目相等的字母,那就按 ...
- PHP调用新浪API 生成短链接
我们经常收到类似于这样的短信(如下图),发现其中的链接并不是常规的网址链接,而是个短小精悍的短链接,产品中经常需要这样的需求,如果在给用户下发的短信中是一个很长的连接,用户体验肯定很差,因此我们需要实 ...
- 如何创作用纯 CSS 绘制一支栩栩如生的铅笔
效果预览 在线演示 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/PaZYBw 可交互视频教 ...
- IE8 png图片黑色阴影的解决方案!
以前都没有留意这个问题,最近开发中才发现. 什么情况下会出现黑边? PNG透明图片,同时有阴影,具备着两个IE8是不会有问题的,再加上使用了 “渐变显示”,就会出现了. 解决方法: img{displ ...
- 【curl】【php】curl报错,错误代码77,CURLE_SSL_CACERT_BADFILE (77)解决方法
CURLE_SSL_CACERT_BADFILE (77) - 读取 SSL CA 证书时遇到问题(可能是路径错误或访问权限问题) 在微信接口相关开发时容易出现此问题 这一般是因为服务更新了相关的软件 ...
- 【转】ERROR 1819 (HY000): Your password does not satisfy the current policy requirements
为了加强安全性,MySQL5.7为root用户随机生成了一个密码,在error log中,关于error log的位置,如果安装的是RPM包,则默认是/var/log/mysqld.log. 一般可通 ...
- 20181121笔记(for,数字类型和字符串类型的内置方法)
1.for循环 for循环可以遍历任何序列的项目,如一个列表或者一个字符串. for循环字典时默认取出key: dic={'x':111,'y':222,'z:333'}for k in dic: ...
- Python9-继承2-day25(大年初二)
继承:什么是什么关系组合:什么有什么关系单继承 先抽象再继承,几个类直接的相同代码抽象出来,成为父类 子类自己没有的名字可以使用父类的方法和属性 如果子类自己有,一定先用自己的 在类中使用self的时 ...
- Objective-C 正则表达式使用(1)
学习了一下OC的正则表达式备忘一下 使用正则表达式的步骤: 创建一个一个正则表达式对象:定义规则. 利用正则表达式对象测试,相应的字符串. NSString *userName = @"12 ...