@自嗨的江江

爱生活爱叽歪

C#驱动热敏打印机打印小票

      最近由于做叽歪助手项目(一个基于微信的自助点餐系统)需要打印小票,公司的小同志门用JS调用Word控件去打印小票,功能是可以实现,不过通过Word控制格式,动态加载小票内容,还是挺麻烦的,而且稳定性很差,是真的很差,用Word的ActiveX控件打印的话,必须将*.doc,*.docx格式的打印模版下载到客户端本地,Word才能读(如果服务端要换模版,怎么办?),关键在打印的时候,ActiveX控件都要打开这个doc的模版文档,如果同事有多个打印启动on个怎么办?挂掉!还有,用Word如何在打印小票里面加一个二维码图片?一直找不到方法,或者说js读图片在客户端并插入到doc的模版,这个想法就是有毛病......
      没办法,只能考虑自己做浏览器的插件或者自定义的ActiveX控件(如何做插件和控件这里不扯了),要做自己定定义的打印控件的话,就得一并解决这么几个问题:

1、易于控制内容和格式模版
2、解决并行打印问题(后来发现这不是个问题)
3、拆入图片二维码
      
      为了解决这个问题,就找资料研究了下打印机,结论方案是:
1、用txt文档作为打印模版文档,可以从服务端直接读取文本内容,无需下载,易于部署和更新
2、自己做一个简单的模版标签解析,可以简单解决打印内容的动态变化,未来在基本不用改变C#代码的情况下,通过前端传递的名-值对参数,进行参数动态加载和替换。
3、将打印的图片文本直接画成图形,在从服务端读取动态的订单二维码图片留,插入到打印的图形
哦了,理论加时间,经过几轮调试,完美实现,并在产品项目中已经实施,非常好用。遗憾的是,现在只是实现ActiveX的控件,只能在IE里面跑~

下面放代码:

public partial class ClientPrinter: UserControl,IObjectSafety
    {
        private PrintDocument doc = new PrintDocument();

        private string orderData;
        private string templateStr;
        private string imgSrc;
        private int rowY = 0;
        public ClientPrinter()
        {
            InitializeComponent();
            this.doc.PrintPage += Doc_PrintPage;
        }

        public void DoPrint(string inData,string imgUrl,string tempUrl)
        {
            this.orderData = inData;
            this.templateStr = this.getFileByText(tempUrl,"utf-8");
            this.imgSrc = imgUrl;
            this.doc.DefaultPageSettings.Margins = new Margins(0, 0, 0, 0);
            //this.doc.DefaultPageSettings.PaperSize = new PaperSize("Custum", 300,300);
            PrintController printController = new StandardPrintController();
            this.doc.PrintController = printController;

#if DEBUG
            PrintPreviewDialog dialog = new PrintPreviewDialog();
            dialog.Document = doc;
            DialogResult res = dialog.ShowDialog();
#endif
            this.doc.Print();
        }

        private void Doc_PrintPage(object sender, PrintPageEventArgs e)
        {
            Font font = new Font(new FontFamily("黑体"), 8);
            Font fontL = new Font(new FontFamily("黑体"), 12);

            string[] parseData = this.orderData.Split('&');//把所有主体打印数据按key=value分段到数组
            string[] proList;
            Dictionary<string, string> contentData = new Dictionary<string, string>();//创建内容主体内容的Key,Value对象集合
            List<Dictionary<string, string>> productData = new List<Dictionary<string, string>>();//创建订单详情信息的集合列表

            //解析名值数组
            foreach (string d in parseData)
            {
                if (d.Contains(","))//解析有多个产品的订单详情
                {
                    if (d.Contains(";"))
                    {
                        proList = d.Split(';');
                        foreach (string p in proList)
                        {
                            string[] itemData = p.Split(',');
                            Dictionary<string, string> item = new Dictionary<string, string>();
                            foreach (string itemStr in itemData)
                            {
                                string[] iStr = itemStr.Split('=');
                                item.Add(iStr[0], iStr[1]);
                            }
                            productData.Add(item);
                        }
                    }
                    else//解析单一产品的订单详情
                    {
                        string[] itemData = d.Split(',');
                        Dictionary<string, string> item = new Dictionary<string, string>();
                        foreach (string itemStr in itemData)
                        {
                            string[] iStr = itemStr.Split('=');
                            item.Add(iStr[0], iStr[1]);
                        }
                        productData.Add(item);

                    }
                }
                else//基本订单信息
                {
                    string[] oStr = d.Split('=');
                    contentData.Add(oStr[0], oStr[1]);
                }
            }

            //根据名值对替换订单基本信息
            foreach (KeyValuePair<string, string> item in contentData)
            {
                this.templateStr = this.templateStr.Replace("{"+item.Key+"}",item.Value);
            }

            string[] stringArr = this.templateStr.Split('\n');//将已经替换基本订单信息的打印模版列表拆分行
            //遍历信息行,逐行建立打印图形内容
            foreach (string s in stringArr)
            {
                //遇到标记二维码行替换打印二维码,并进入下一行
                if (s.StartsWith("{qrcode}"))
                {
                    //s.Replace("{qrcode}", "");
                    Image img = this.getImage(this.imgSrc);
                    e.Graphics.DrawImage(img, 40, getY(this.rowY));
                    continue;
                }

                //处理订单详情的行信息
                if (s.StartsWith("#"))
                {
                    string lineStr = s.Replace("#", "");
                    string outStr = "";
                    foreach (Dictionary<string, string> dic in productData)
                    {
                        outStr = lineStr;
                        foreach (KeyValuePair<string, string> item in dic)
                        {
                            outStr = outStr.Replace("{" + item.Key.ToLower() + "}", item.Value);
                        }
                        e.Graphics.DrawString(outStr, font, Brushes.Black, 10, getY(this.rowY));
                    }
                    continue;
                }

                if (this.rowY == 0)
                    e.Graphics.DrawString(s, fontL, Brushes.Black, 10, getY(this.rowY));
                else
                    e.Graphics.DrawString(s, font, Brushes.Black, 10, getY(this.rowY));

            }
        }


        private string getFileByText(string Url, string FileEncoding)
        {
            string sRslt = null;
            WebResponse oWebRps = null;
            WebRequest oWebRqst = WebRequest.Create(Url);
            oWebRqst.Timeout = 50000;
            oWebRps = oWebRqst.GetResponse();
            StreamReader oStreamRd = new StreamReader(oWebRps.GetResponseStream(), Encoding.GetEncoding(FileEncoding));
            sRslt = oStreamRd.ReadToEnd();
            oStreamRd.Close();
            oWebRps.Close();
            return sRslt;
        }


        private Image getImage(string Url)
        {
            WebRequest myrequest = WebRequest.Create(Url);
            WebResponse myresponse = myrequest.GetResponse();
            Stream imgstream = myresponse.GetResponseStream();
            System.Drawing.Image img = System.Drawing.Image.FromStream(imgstream);
            return this.ToThumbnailImages(100, img);
            //return img;

        }

        private Image ToThumbnailImages(int w, Image SrcImage)
        {
            int oWidth = w;
            int oHeight = (SrcImage.Height * oWidth) / SrcImage.Width;
            Image NewImage = SrcImage.GetThumbnailImage(oWidth, oHeight,new Image.GetThumbnailImageAbort(ThumbnailCallback), IntPtr.Zero);
            return NewImage;
        }

        private bool ThumbnailCallback()
        {
            return false;
        }

        private float getY(int i)
        {
            string f = i.ToString() + ".00";
            float row = float.Parse(f);
            this.rowY++;
            return (float)(18.00 *row);
        }
}
}

前端JS的调用以及传参数:

function doTest()  
{  
  var obj = document.getElementById("printer");   
        obj.DoPrint(
            "title=茉莉咖啡&flag=001&ordertime=17/07/02 19:34&orderprice=100.00&paymoney=95.00&savemoney=5.00&orderid=ASFAFADAFASAFSASDFA&productname=娃哈哈,num=3,price=1.00;productname=娃哈哈,num=3,price=1.00;productname=娃哈哈,num=3,price=1.00",
            "http://stg.wx.jonvie.com/staticfiles/qrcode?codeurl=http://stg.wx.jonvie.com/gyzhushou",
            "http://stg.wx.jonvie.com/Test/print.txt"
        );  
}  

打印的TXT模版:

{title}
===============================
标识:{flag}  日期:{ordertime}
产品              单价   数量
===============================
#{productname}   {price} x {num}
总价:{orderprice}          实付:{paymoney}
优惠:{savemoney}
===============================
{orderid}
{qrcode}


 


        小票当天有效
.

 

不允许评论