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

来源:互联网 发布:王小云 破解md5 算法 编辑:程序博客网 时间:2024/06/02 18:09

最近一直在研究并口小票打印机打印图片问题,这也是第一次和硬件打交道,不过还好,最终成功了。

 

这是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

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 电脑开机了出现一些英文单词怎么办 不懂法语想读法语书怎么办 大鱼号文章需要修改怎么办 过了上诉期怎么办申诉 法院判刑后被告逃亡监护人怎么办 二审判决后不服的怎么办 对树木对生物花草过敏怎么办 高一英语成绩差怎么办 文章被同时录用该怎么办 来不及开ei检索证明怎么办 淘宝生产许可编号一定要填怎么办 官网下单被砍单怎么办美卡美私 大学网络课程挂了怎么办 如果二审超过6个月还不判怎么办? sci的proof时间超了怎么办 合肥电大考试没过怎么办 社保账号密码忘记了怎么办 住房公积金账号密码忘记了怎么办 燃气费单子丢了怎么办 商标初审公告期内被异议怎么办 手被山药痒了怎么办 9个月宝宝不吃奶粉怎么办 八个月宝宝拉粑粑费劲怎么办? 两个月小孩不吃奶粉怎么办 两个月的小孩不吃奶粉怎么办 两个多月宝宝不吃奶怎么办 三个多月宝宝不爱吃奶怎么办 4个月宝宝不吃奶怎么办 5个月宝宝不爱吃奶怎么办 九个月宝宝一直流鼻涕怎么办 九个月宝宝一直咳嗽怎么办 宝宝3岁不爱喝水怎么办 1岁宝宝不肯喝水怎么办 三个月宝宝体检说严重缺钙怎么办 1岁半宝宝不吃药怎么办 1岁宝宝抗拒吃药怎么办 六个月宝宝不爱吃辅食怎么办 宝宝九个月了不爱吃辅食怎么办 八个月宝宝不喜欢吃辅食怎么办 小孩米粉吃多了怎么办 宝宝四个月了奶水不足怎么办