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

简介: 原文:C#并口热敏小票打印机打印位图 最近一直在研究并口小票打印机打印图片问题,这也是第一次和硬件打交道,不过还好,最终成功了。
原文: 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用于选择位图方式。

 

模式

纵向

横向

点数

分辨率

分辨率

数据个数(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是一个长度为3byte数组,这个data在打印中起到什么作用呢?

在打印机m=33的模式纵向每次是打印24个点,也就是说,而byte8个字节,所以需要3byte类型的树才能完成模式为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

目录
相关文章
|
算法 NoSQL C#
C#位图BitArray 小试牛刀
难缠的布隆过滤器,这次终于通透了
C#位图BitArray 小试牛刀
|
C#
C#热敏打印图片 串口打印图片
原文:C#热敏打印图片 串口打印图片 如图,一步一步慢慢调出来的 //串口通信类 public System.
1188 0
|
C#
C# 热敏打印机 Socket 网络链接 打印 图片
C# 热敏打印机 Socket 网络链接 打印 图片 (一) http://www.cnblogs.com/rinack/p/4838211.html   C# 热敏打印机 Socket 网络链接 打印 图片 (二) http://www.
1438 0
|
测试技术 C#
C# 热敏打印机 小票打印机 打印图片
这两天一直在研究热敏小票打印机打印图片的问题,在经过痛苦的找资料过程后,终于实验成功了。经过一番测试和修改,代码终于出炉了,这次打印条形码、二维码、Logo就方便多了。
2361 0
|
7月前
|
开发框架 前端开发 .NET
C#编程与Web开发
【4月更文挑战第21天】本文探讨了C#在Web开发中的应用,包括使用ASP.NET框架、MVC模式、Web API和Entity Framework。C#作为.NET框架的主要语言,结合这些工具,能创建动态、高效的Web应用。实际案例涉及企业级应用、电子商务和社交媒体平台。尽管面临竞争和挑战,但C#在Web开发领域的前景将持续拓展。
209 3
|
7月前
|
SQL 开发框架 安全
C#编程与多线程处理
【4月更文挑战第21天】探索C#多线程处理,提升程序性能与响应性。了解C#中的Thread、Task类及Async/Await关键字,掌握线程同步与安全,实践并发计算、网络服务及UI优化。跟随未来发展趋势,利用C#打造高效应用。
204 3
|
1月前
|
C# 开发者
C# 一分钟浅谈:Code Contracts 与契约编程
【10月更文挑战第26天】本文介绍了 C# 中的 Code Contracts,这是一个强大的工具,用于通过契约编程增强代码的健壮性和可维护性。文章从基本概念入手,详细讲解了前置条件、后置条件和对象不变量的使用方法,并通过具体代码示例进行了说明。同时,文章还探讨了常见的问题和易错点,如忘记启用静态检查、过度依赖契约和性能影响,并提供了相应的解决建议。希望读者能通过本文更好地理解和应用 Code Contracts。
33 3
|
27天前
|
设计模式 C# 图形学
Unity 游戏引擎 C# 编程:一分钟浅谈
本文介绍了在 Unity 游戏开发中使用 C# 的基础知识和常见问题。从 `MonoBehavior` 类的基础用法,到变量和属性的管理,再到空引用异常、资源管理和性能优化等常见问题的解决方法。文章还探讨了单例模式、事件系统和数据持久化等高级话题,旨在帮助开发者避免常见错误,提升游戏开发效率。
39 4
|
3月前
|
API C#
C# 一分钟浅谈:文件系统编程
在软件开发中,文件系统操作至关重要。本文将带你快速掌握C#中文件系统编程的基础知识,涵盖基本概念、常见问题及解决方法。文章详细介绍了`System.IO`命名空间下的关键类库,并通过示例代码展示了路径处理、异常处理、并发访问等技巧,还提供了异步API和流压缩等高级技巧,帮助你写出更健壮的代码。
47 2
|
2月前
|
安全 C# 数据安全/隐私保护
实现C#编程文件夹加锁保护
【10月更文挑战第16天】本文介绍了两种用 C# 实现文件夹保护的方法:一是通过设置文件系统权限,阻止普通用户访问;二是使用加密技术,对文件夹中的文件进行加密,防止未授权访问。提供了示例代码和使用方法,适用于不同安全需求的场景。
131 0