下面是打印所需要调用的代码:

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用于选择位图方式。

模式

纵向

横向

点数

分辨率

分辨率

数据个数(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个字节就够了。

打印出的效果还是很不错的。

C#并口热敏小票打印机打印位图包括芯片的写入的更多相关文章

  1. C#并口热敏小票打印机打印位图

    原文:C#并口热敏小票打印机打印位图 最近一直在研究并口小票打印机打印图片问题,这也是第一次和硬件打交道,不过还好,最终成功了.   这是DEMO的窗体:   下面是打印所需要调用的代码: class ...

  2. 转:C#并口热敏小票打印机打印位图

    最近一直在研究并口小票打印机打印图片问题,这也是第一次和硬件打交道,不过还好,最终成功了. 这是DEMO的窗体: 下面是打印所需要调用的代码: class LptControl { private s ...

  3. C# Lpt 并口热敏小票打印机打印位图

    class LptControl { private string LptStr = "lpt1"; public LptControl(string l_LPT_Str) { L ...

  4. C# 热敏打印机 小票打印机 打印图片

    最近一直在研究并口小票打印机打印图片问题,这也是第一次和硬件打交道,不过还好,最终成功了. 这是DEMO的窗体: 下面是打印所需要调用的代码: 因为我们这里主要是打印条形码和二维码,所以以条形码和二维 ...

  5. c#调用刀片小票打印机

    public static bool Print(int orderId, string orderTime) { bool b = true; string cut = ((char)29).ToS ...

  6. 按照已有的模板打印小票<二> ——调用windows打印机打印 可设置字体样式

    按照已有的模板打印小票<二> ——调用windows打印机打印 可设置字体样式 之前写过一篇文章<按照已有的模板输出一(如发票)>,是关于如何给已有的模板赋值.在项目的实践过程 ...

  7. C#热敏打印图片 串口打印图片

    原文:C#热敏打印图片 串口打印图片 如图,一步一步慢慢调出来的 //串口通信类 public System.IO.Ports.SerialPort serialPort = null; serial ...

  8. 通过快递100获取快递单号,结合c-lodop热敏纸打印 – 通过菜鸟ISV/自研ERP使用菜鸟电子面单

    https://www.1024cc.cn/index.php/2019/04/29/%E6%89%93%E5%8D%B0%E7%94%B5%E5%AD%90%E9%9D%A2%E5%8D%95/ 打 ...

  9. C#调用斑马打印机打印条码标签(支持COM、LPT、USB、TCP连接方式和ZPL、EPL、CPCL指令)【转】

    原文地址:http://blog.csdn.net/ldljlq/article/details/7338772 在批量打印商品标签时一般都要加上条码或图片,而这类应用大多是使用斑马打印机,所以我也遇 ...

随机推荐

  1. [蓝桥杯]ALGO-81.算法训练_动态数组使用

    从键盘读入n个整数,使用动态数组存储所读入的整数,并计算它们的和与平均值分别输出.要求尽可能使用函数实现程序代码.平均值为小数的只保留其整数部分. 样例输入: 样例输出: 样例输入: 样例输出: 题目 ...

  2. 使用jquery.mCustomScrollbar自定义滚动条(3)callback onCreate

    碰到了一个问题,想简洁,所以在页面上使用 <div class="div_box mCustomScrollbar" data-mcs-theme="dark-3& ...

  3. Java学习——多线程例子:李四王五

    package cys; public class Example9_2 { public static void main(String[] args) { // TODO Auto-generat ...

  4. DP Big Event in HDU

    Big Event in HDU Time Limit : 10000/5000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other) T ...

  5. Nodejs使用多个分隔符分隔字符串

    在nodejs中当需要使用多个分隔符分隔字符串时,可以使用正则表达式作为split函数的参数,具体使用如下: var str = "111@222#333 444@555# 666 777& ...

  6. 学习笔记之Python Crash Course

    Python Crash Course https://www.safaribooksonline.com/library/view/python-crash-course/9781457197185 ...

  7. folly无锁队列,尝试添加新的函数(续)

    基于上一篇文章,dropHead取出节点后,删除节点,会出现内存访问的问题.按照这个逻辑,如果将移出的节点保存到一个无锁队列中,然后在需要节点的时候,从这个备用的无锁队列中取出节点,那么应该就可以避开 ...

  8. MySQL学习----explain查看一条sql 的性能

    在开发的过程中,对于我们写的sql语句,我们有时候会考虑sql语句的性能,那么explain就是首选.Explain命令在解决数据库性能上是第一推荐使用命令,大部分的性能问题可以通过此命令来简单的解决 ...

  9. 关于git中自己的分支和主分支有冲突的解决方案(git和乌龟git)

    阐述一个案例,最近在开发中遇到一个问题.自己在代码的主分支拉了一个分支,开始快乐的开发修改了.同事小明也在主分支拉了一个分支,也在快乐的修改.小明的开发速度很快,一个问题很快就解决了,并且把自己的代码 ...

  10. [UE4]GameplayAbilities,技能系统插件

    Unreal Engine 4(虚幻UE4)GameplayAbilities 插件入门教程(七)Ability的信息传递等   Unreal Engine 4(虚幻UE4)GameplayAbili ...