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

来源:互联网 发布:网络推广金融好做么 编辑:程序博客网 时间:2024/06/11 04:16

 在批量打印商品标签时一般都要加上条码或图片,而这类应用大多是使用斑马打印机,所以我也遇到了怎么打印的问题。

一种办法是用标签设计软件做好模板,在标签设计软件中打印,这种办法不用写代码,但对我来说觉得不能接受,所以尝试代码解决问题。

网上搜索一番,找不到什么资料,基本都是说发送ZPL、EPL指令到打印机,而且还是COM/LPT口连接打印机。后来研究.net的打印类库,发现是用绘图方式打印至打印机的,也叫GDI打印,于是思路有了点突破,那我可以用报表工具画好标签,运行报表时,把结果输出位图,再发送至打印机。

后来又找到一种更好的办法,利用标签设计软件做好模板,打印至本地文件,把其中的ZPL、EPL指令拷贝出来,替换其中动态变化的内容为变量名,做成一个模板文本,在代码中动态替换变量,再把指令输出至打印机。

折腾了几天,终于把这两种思路都实现了,顺便解决了USB接口打印机的ZPL、EPL指令发送问题。

今天有点困,改天再详细讲解一下这两种思路的具体实现。

==============================================================================================================
如何获取标签设计软件输出至打印的ZPL指令?安装好打印机驱动,修改打印机端口,新建一个打印机端口,类型为本地端口,端口名称设置为C:\printer.log,再用标签设计软件打印一次,此文件中就有ZPL指令了。

 ==============================================================================================================

2012-06-02:发布代码ZebraPrintHelper.cs。

==============================================================================================================

2013-01-17:发布代码ZebraPrintHelper.cs,修正BUG,新增TCP打印支持Zebra无线打印QL320+系列打印机。已经生产环境实际应用,支持POS小票、吊牌、洗水唛、条码、文本混合标签打印。因涉及公司源码,只能截图VS解决方案给大家看。

==============================================================================================================

 

 ZebraPrintHelper类代码:

using System;using System.Collections.Generic;using System.Drawing;using System.Drawing.Imaging;using System.IO;using System.IO.Ports;using System.Net.Sockets;using System.Runtime.InteropServices;using System.Text;namespace Umisky.BarcodePrint.Core {    /// <summary>    /// 斑马打印助手,支持LPT/COM/USB/TCP四种模式,适用于标签、票据、条码打印。    /// </summary>    public static class ZebraPrintHelper {        #region 定义私有字段        /// <summary>        /// 线程锁,防止多线程调用。        /// </summary>        private static object SyncRoot = new object();        /// <summary>        /// ZPL压缩字典        /// </summary>        private static List<KeyValue> compressDictionary = new List<KeyValue>();        #endregion        #region 定义属性        public static float TcpLabelMaxHeightCM { get; set; }        public static int TcpPrinterDPI { get; set; }        public static string TcpIpAddress { get; set; }        public static int TcpPort { get; set; }        public static int Copies { get; set; }        public static int Port { get; set; }        public static string PrinterName { get; set; }        public static bool IsWriteLog { get; set; }        public static DeviceType PrinterType { get; set; }        public static ProgrammingLanguage PrinterProgrammingLanguage { get; set; }        /// <summary>        /// 日志保存目录,WEB应用注意不能放在BIN目录下。        /// </summary>        public static string LogsDirectory { get; set; }        public static byte[] GraphBuffer { get; set; }        private static int GraphWidth { get; set; }        private static int GraphHeight { get; set; }        private static int RowSize {            get {                return (((GraphWidth) + 31) >> 5) << 2;            }        }        private static int RowRealBytesCount {            get {                if ((GraphWidth % 8) > 0) {                    return GraphWidth / 8 + 1;                }                else {                    return GraphWidth / 8;                }            }        }        #endregion        #region 静态构造方法        static ZebraPrintHelper() {            initCompressCode();            Port = 1;            GraphBuffer = new byte[0];            IsWriteLog = false;            LogsDirectory = "logs";            PrinterProgrammingLanguage = ProgrammingLanguage.ZPL;        }        private static void initCompressCode() {            //G H I J K L M N O P Q R S T U V W X Y        对应1,2,3,4……18,19。            //g h i j k l m n o p q r s t u v w x y z      对应20,40,60,80……340,360,380,400。                        for (int i = 0; i < 19; i++) {                compressDictionary.Add(new KeyValue() { Key = Convert.ToChar(71 + i), Value = i + 1 });            }            for (int i = 0; i < 20; i++) {                compressDictionary.Add(new KeyValue() { Key = Convert.ToChar(103 + i), Value = (i + 1) * 20 });            }        }        #endregion        #region 日志记录方法        private static void WriteLog(string text, LogType logType) {            string endTag = string.Format("\r\n{0}\r\n", new string('=', 80));            string path = string.Format("{0}\\{1}-{2}.log", LogsDirectory, DateTime.Now.ToString("yyyy-MM-dd"), logType);            if (!Directory.Exists(LogsDirectory)) {                Directory.CreateDirectory(LogsDirectory);            }            if (logType == LogType.Error) {                File.AppendAllText(path, string.Format("{0}{1}", text, endTag), Encoding.UTF8);            }            if (logType == LogType.Print) {                File.AppendAllText(path, string.Format("{0}{1}", text, endTag), Encoding.UTF8);            }        }        private static void WriteLog(byte[] bytes, LogType logType) {            string endTag = string.Format("\r\n{0}\r\n", new string('=', 80));            string path = string.Format("{0}\\{1}-{2}.log", LogsDirectory, DateTime.Now.ToString("yyyy-MM-dd"), logType);            if (!Directory.Exists(LogsDirectory)) {                Directory.CreateDirectory(LogsDirectory);            }            if (logType == LogType.Error) {                File.AppendAllText(path, string.Format("{0}{1}", Encoding.UTF8.GetString(bytes), endTag), Encoding.UTF8);            }            if (logType == LogType.Print) {                File.AppendAllText(path, string.Format("{0}{1}", Encoding.UTF8.GetString(bytes), endTag), Encoding.UTF8);            }        }        #endregion        #region 封装方法,方便调用。        public static bool PrintWithCOM(string cmd, int port, bool isWriteLog) {            PrinterType = DeviceType.COM;            Port = port;            IsWriteLog = isWriteLog;            return PrintCommand(cmd);        }        public static bool PrintWithCOM(byte[] bytes, int port, bool isWriteLog) {            PrinterType = DeviceType.COM;            Port = port;            IsWriteLog = isWriteLog;            return PrintGraphics(bytes);        }        public static bool PrintWithLPT(string cmd, int port, bool isWriteLog) {            PrinterType = DeviceType.LPT;            Port = port;            IsWriteLog = isWriteLog;            return PrintCommand(cmd);        }        public static bool PrintWithLPT(byte[] bytes, int port, bool isWriteLog) {            PrinterType = DeviceType.LPT;            Port = port;            IsWriteLog = isWriteLog;            return PrintGraphics(bytes);        }        public static bool PrintWithTCP(string cmd, bool isWriteLog) {            PrinterType = DeviceType.TCP;            IsWriteLog = isWriteLog;            return PrintCommand(cmd);        }        public static bool PrintWithTCP(byte[] bytes, bool isWriteLog) {            PrinterType = DeviceType.TCP;            IsWriteLog = isWriteLog;            return PrintGraphics(bytes);        }        public static bool PrintWithDRV(string cmd, string printerName, bool isWriteLog) {            PrinterType = DeviceType.DRV;            PrinterName = printerName;            IsWriteLog = isWriteLog;            return PrintCommand(cmd);        }        public static bool PrintWithDRV(byte[] bytes, string printerName, bool isWriteLog) {            PrinterType = DeviceType.DRV;            PrinterName = printerName;            IsWriteLog = isWriteLog;            return PrintGraphics(bytes);        }        #endregion        #region 打印ZPL、EPL、CPCL、TCP指令        public static bool PrintCommand(string cmd) {            lock (SyncRoot) {                bool result = false;                try {                    switch (PrinterType) {                        case DeviceType.COM:                            result = comPrint(Encoding.Default.GetBytes(cmd));                            break;                        case DeviceType.LPT:                            result = lptPrint(Encoding.Default.GetBytes(cmd));                            break;                        case DeviceType.DRV:                            result = drvPrint(Encoding.Default.GetBytes(cmd));                            break;                        case DeviceType.TCP:                            result = tcpPrint(Encoding.Default.GetBytes(cmd));                            break;                    }                    if (!string.IsNullOrEmpty(cmd) && IsWriteLog) {                        WriteLog(cmd, LogType.Print);                    }                }                catch (Exception ex) {                    //记录日志                    if (IsWriteLog) {                        WriteLog(string.Format("{0} => {1}\r\n{2}", DateTime.Now, ex.Message, ex), LogType.Error);                    }                    throw new Exception(ex.Message, ex);                }                finally {                    GraphBuffer = new byte[0];                }                return result;            }        }        #endregion        #region 打印图像        public static bool PrintGraphics(byte[] graph) {            lock (SyncRoot) {                bool result = false;                try {                    GraphBuffer = graph;                    byte[] cmdBytes = new byte[0];                    switch (PrinterProgrammingLanguage) {                        case ProgrammingLanguage.ZPL:                            cmdBytes = getZPLBytes();                            break;                        case ProgrammingLanguage.EPL:                            cmdBytes = getEPLBytes();                            break;                        case ProgrammingLanguage.CPCL:                            cmdBytes = getCPCLBytes();                            break;                    }                    switch (PrinterType) {                        case DeviceType.COM:                            result = comPrint(cmdBytes);                            break;                        case DeviceType.LPT:                            result = lptPrint(cmdBytes);                            break;                        case DeviceType.DRV:                            result = drvPrint(cmdBytes);                            break;                        case DeviceType.TCP:                            result = tcpPrint(cmdBytes);                            break;                    }                    if (cmdBytes.Length > 0 && IsWriteLog) {                        WriteLog(cmdBytes, LogType.Print);                    }                }                catch (Exception ex) {                    //记录日志                    if (IsWriteLog) {                        WriteLog(string.Format("{0} => {1}\r\n{2}", DateTime.Now, ex.Message, ex), LogType.Error);                    }                    throw new Exception(ex.Message, ex);                }                finally {                    GraphBuffer = new byte[0];                }                return result;            }        }        #endregion        #region 打印指令        private static bool drvPrint(byte[] cmdBytes) {            bool result = false;            try {                if (!string.IsNullOrEmpty(PrinterName)) {                    result = WinDrvPort.SendBytesToPrinter(PrinterName, cmdBytes);                }            }            catch (Exception ex) {                throw new Exception(ex.Message, ex);            }            return result;        }        private static bool comPrint(byte[] cmdBytes) {            bool result = false;            SerialPort com = new SerialPort(string.Format("{0}{1}", PrinterType, Port), 9600, Parity.None, 8, StopBits.One);            try {                com.Open();                com.Write(cmdBytes, 0, cmdBytes.Length);                result = true;            }            catch (Exception ex) {                throw new Exception(ex.Message, ex);            }            finally {                if (com.IsOpen) {                    com.Close();                }            }            return result;        }        private static bool lptPrint(byte[] cmdBytes) {            return LptPort.Write(string.Format("{0}{1}", PrinterType, Port), cmdBytes);        }        private static bool tcpPrint(byte[] cmdBytes) {            bool result = false;            TcpClient tcp = null;            try {                tcp = TimeoutSocket.Connect(string.Empty, TcpIpAddress, TcpPort, 1000);                tcp.SendTimeout = 1000;                tcp.ReceiveTimeout = 1000;                if (tcp.Connected) {                    tcp.Client.Send(cmdBytes);                    result = true;                }            }            catch (Exception ex) {                throw new Exception("打印失败,请检查打印机或网络设置。", ex);            }            finally {                if (tcp != null) {                    if (tcp.Client != null) {                        tcp.Client.Close();                        tcp.Client = null;                    }                    tcp.Close();                    tcp = null;                }            }            return result;        }        #endregion        #region 生成ZPL图像打印指令        private static byte[] getZPLBytes() {            byte[] bmpData = getBitmapData();            int bmpDataLength = bmpData.Length;            for (int i = 0; i < bmpDataLength; i++) {                bmpData[i] ^= 0xFF;            }            string textBitmap = string.Empty, copiesString = string.Empty;            string textHex = BitConverter.ToString(bmpData).Replace("-", string.Empty);            textBitmap = CompressLZ77(textHex);            for (int i = 0; i < Copies; i++) {                copiesString += "^XA^FO0,0^XGR:IMAGE.GRF,1,1^FS^XZ";            }            string text = string.Format("~DGR:IMAGE.GRF,{0},{1},{2}{3}^IDR:IMAGE.GRF",                GraphHeight * RowRealBytesCount,                RowRealBytesCount,                textBitmap,                copiesString);            return Encoding.UTF8.GetBytes(text);        }        #endregion        #region 生成EPL图像打印指令        private static byte[] getEPLBytes() {            byte[] buffer = getBitmapData();            string text = string.Format("N\r\nGW{0},{1},{2},{3},{4}\r\nP{5},1\r\n",                0,                0,                RowRealBytesCount,                GraphHeight,                Encoding.GetEncoding("iso-8859-1").GetString(buffer),                Copies);            return Encoding.GetEncoding("iso-8859-1").GetBytes(text);        }        #endregion        #region 生成CPCL图像打印指令        public static byte[] getCPCLBytes() {            //GRAPHICS Commands            //Bit-mapped graphics can be printed by using graphics commands. ASCII hex (hexadecimal) is            //used for expanded graphics data (see example). Data size can be reduced to one-half by utilizing the            //COMPRESSED-GRAPHICS commands with the equivalent binary character(s) of the hex data. When            //using CG, a single 8 bit character is sent for every 8 bits of graphics data. When using EG two characters            //(16 bits) are used to transmit 8 bits of graphics data, making EG only half as efficient. Since this data is            //character data, however, it can be easier to handle and transmit than binary data.            //Format:            //{command} {width} {height} {x} {y} {data}            //where:            //{command}: Choose from the following:            //EXPANDED-GRAPHICS (or EG): Prints expanded graphics horizontally.            //VEXPANDED-GRAPHICS (or VEG): Prints expanded graphics vertically.            //COMPRESSED-GRAPHICS (or CG): Prints compressed graphics horizontally.            //VCOMPRESSED-GRAPHICS (or VCG): Prints compressed graphics vertically.            //{width}: Byte-width of image.            //{height} Dot-height of image.            //{x}: Horizontal starting position.            //{y}: Vertical starting position.            //{data}: Graphics data.            //Graphics command example            //Input:            //! 0 200 200 210 1            //EG 2 16 90 45 F0F0F0F0F0F0F0F00F0F0F0F0F0F0F0F            //F0F0F0F0F0F0F0F00F0F0F0F0F0F0F0F            //FORM            //PRINT            byte[] bmpData = getBitmapData();            int bmpDataLength = bmpData.Length;            for (int i = 0; i < bmpDataLength; i++) {                bmpData[i] ^= 0xFF;            }            string textHex = BitConverter.ToString(bmpData).Replace("-", string.Empty);            string text = string.Format("! {0} {1} {2} {3} {4}\r\nEG {5} {6} {7} {8} {9}\r\nFORM\r\nPRINT\r\n",                0, //水平偏移量                TcpPrinterDPI, //横向DPI                TcpPrinterDPI, //纵向DPI                (int)(TcpLabelMaxHeightCM / 2.54f * TcpPrinterDPI), //标签最大像素高度=DPI*标签纸高度(英寸)                Copies, //份数                RowRealBytesCount, //图像的字节宽度                GraphHeight, //图像的像素高度                0, //横向的开始位置                0, //纵向的开始位置                textHex                );            return Encoding.UTF8.GetBytes(text);        }        #endregion        #region 获取单色位图数据        /// <summary>        ///         /// </summary>        /// <param name="pimage"></param>        /// <returns></returns>        public static Bitmap ConvertToGrayscale(Bitmap pimage) {            Bitmap source = null;            // If original bitmap is not already in 32 BPP, ARGB format, then convert            if (pimage.PixelFormat != PixelFormat.Format32bppArgb) {                source = new Bitmap(pimage.Width, pimage.Height, PixelFormat.Format32bppArgb);                source.SetResolution(pimage.HorizontalResolution, pimage.VerticalResolution);                using (Graphics g = Graphics.FromImage(source)) {                    g.DrawImageUnscaled(pimage, 0, 0);                }            }            else {                source = pimage;            }            // Lock source bitmap in memory            BitmapData sourceData = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);            // Copy image data to binary array            int imageSize = sourceData.Stride * sourceData.Height;            byte[] sourceBuffer = new byte[imageSize];            Marshal.Copy(sourceData.Scan0, sourceBuffer, 0, imageSize);            // Unlock source bitmap            source.UnlockBits(sourceData);            // Create destination bitmap            Bitmap destination = new Bitmap(source.Width, source.Height, PixelFormat.Format1bppIndexed);            // Lock destination bitmap in memory            BitmapData destinationData = destination.LockBits(new Rectangle(0, 0, destination.Width, destination.Height), ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed);            // Create destination buffer            imageSize = destinationData.Stride * destinationData.Height;            byte[] destinationBuffer = new byte[imageSize];            int sourceIndex = 0;            int destinationIndex = 0;            int pixelTotal = 0;            byte destinationValue = 0;            int pixelValue = 128;            int height = source.Height;            int width = source.Width;            int threshold = 500;            // Iterate lines            for (int y = 0; y < height; y++) {                sourceIndex = y * sourceData.Stride;                destinationIndex = y * destinationData.Stride;                destinationValue = 0;                pixelValue = 128;                // Iterate pixels                for (int x = 0; x < width; x++) {                    // Compute pixel brightness (i.e. total of Red, Green, and Blue values)                    pixelTotal = sourceBuffer[sourceIndex + 1] + sourceBuffer[sourceIndex + 2] + sourceBuffer[sourceIndex + 3];                    if (pixelTotal > threshold) {                        destinationValue += (byte)pixelValue;                    }                    if (pixelValue == 1) {                        destinationBuffer[destinationIndex] = destinationValue;                        destinationIndex++;                        destinationValue = 0;                        pixelValue = 128;                    }                    else {                        pixelValue >>= 1;                    }                    sourceIndex += 4;                }                if (pixelValue != 128) {                    destinationBuffer[destinationIndex] = destinationValue;                }            }            // Copy binary image data to destination bitmap            Marshal.Copy(destinationBuffer, 0, destinationData.Scan0, imageSize);            // Unlock destination bitmap            destination.UnlockBits(destinationData);            // Dispose of source if not originally supplied bitmap            if (source != pimage) {                source.Dispose();            }            // Return            return destination;        }        /// <summary>        /// 获取单色位图数据(1bpp),不含文件头、信息头、调色板三类数据。        /// </summary>        /// <returns></returns>        private static byte[] getBitmapData() {            MemoryStream srcStream = new MemoryStream();            MemoryStream dstStream = new MemoryStream();            Bitmap srcBmp = null;            Bitmap dstBmp = null;            byte[] srcBuffer = null;            byte[] dstBuffer = null;            byte[] result = null;            try {                srcStream = new MemoryStream(GraphBuffer);                srcBmp = Bitmap.FromStream(srcStream) as Bitmap;                srcBuffer = srcStream.ToArray();                GraphWidth = srcBmp.Width;                GraphHeight = srcBmp.Height;                //dstBmp = srcBmp.Clone(new Rectangle(0, 0, srcBmp.Width, srcBmp.Height), PixelFormat.Format1bppIndexed);                dstBmp = ConvertToGrayscale(srcBmp);                dstBmp.Save(dstStream, ImageFormat.Bmp);                dstBuffer = dstStream.ToArray();                int bfOffBits = BitConverter.ToInt32(dstBuffer, 10);                result = new byte[GraphHeight * RowRealBytesCount];                //读取时需要反向读取每行字节实现上下翻转的效果,打印机打印顺序需要这样读取。                for (int i = 0; i < GraphHeight; i++) {                    Array.Copy(dstBuffer, bfOffBits + (GraphHeight - 1 - i) * RowSize, result, i * RowRealBytesCount, RowRealBytesCount);                }            }            catch (Exception ex) {                throw new Exception(ex.Message, ex);            }            finally {                if (srcStream != null) {                    srcStream.Dispose();                    srcStream = null;                }                if (dstStream != null) {                    dstStream.Dispose();                    dstStream = null;                }                if (srcBmp != null) {                    srcBmp.Dispose();                    srcBmp = null;                }                if (dstBmp != null) {                    dstBmp.Dispose();                    dstBmp = null;                }            }            return result;        }        #endregion        #region LZ77图像字节流压缩方法        public static string CompressLZ77(string text) {            //将转成16进制的文本进行压缩            string result = string.Empty;            char[] arrChar = text.ToCharArray();            int count = 1;            for (int i = 1; i < text.Length; i++) {                if (arrChar[i - 1] == arrChar[i]) {                    count++;                }                else {                    result += convertNumber(count) + arrChar[i - 1];                    count = 1;                }                if (i == text.Length - 1) {                    result += convertNumber(count) + arrChar[i];                }            }            return result;        }        public static string DecompressLZ77(string text) {            string result = string.Empty;            char[] arrChar = text.ToCharArray();            int count = 0;            for (int i = 0; i < arrChar.Length; i++) {                if (isHexChar(arrChar[i])) {                    //十六进制值                    result += new string(arrChar[i], count == 0 ? 1 : count);                    count = 0;                }                else {                    //压缩码                    int value = GetCompressValue(arrChar[i]);                    count += value;                }            }            return result;        }        private static int GetCompressValue(char c) {            int result = 0;            for (int i = 0; i < compressDictionary.Count; i++) {                if (c == compressDictionary[i].Key) {                    result = compressDictionary[i].Value;                }            }            return result;        }        private static bool isHexChar(char c) {            return c > 47 && c < 58 || c > 64 && c < 71 || c > 96 && c < 103;        }        private static string convertNumber(int count) {            //将连续的数字转换成LZ77压缩代码,如000可用I0表示。            string result = string.Empty;            if (count > 1) {                while (count > 0) {                    for (int i = compressDictionary.Count - 1; i >= 0; i--) {                        if (count >= compressDictionary[i].Value) {                            result += compressDictionary[i].Key;                            count -= compressDictionary[i].Value;                            break;                        }                    }                }            }            return result;        }        #endregion    }}


 

调用例子代码:

        private void BackgroundWorkerPrint_DoWork(object sender, DoWorkEventArgs e) {            BackgroundWorker worker = sender as BackgroundWorker;            int i = 0, nextRemainder = 0, count = this._listBarcodeData.Count;            bool flag = true;            float pageWidth, pageHeight;            int dpiX, dpiY, perPaperFactor;            string reportPath = string.Format(@"{0}/Reports/{1}", Application.StartupPath, this._modelType);            PrintLog printLog = new PrintLog() { Operater = LoginName };            PrinterSettings printerSettings = new PrinterSettings() { PrinterName = PrintParam, Copies = 1 };            using (StreamReader tr = new StreamReader(this.ModelFilePath)) {                XElement xe = XDocument.Load(tr).Root.Elements()                    .Elements(XName.Get("ModelType")).First(x => x.Value == this._modelType).Parent;                pageWidth = float.Parse(xe.Elements(XName.Get("PageWidth")).First().Value);                pageHeight = float.Parse(xe.Elements(XName.Get("PageHeight")).First().Value);                dpiX = int.Parse(xe.Elements(XName.Get("DotPerInchX")).First().Value);                dpiY = int.Parse(xe.Elements(XName.Get("DotPerInchY")).First().Value);                perPaperFactor = int.Parse(xe.Elements(XName.Get("PerPaperFactor")).First().Value);                this._no = int.Parse(xe.Elements(XName.Get("NO")).First().Value);            }            using (LocalReportHelper printHelper = new LocalReportHelper(reportPath)) {                printHelper.PrintTypeNO = this._no;                printHelper.PrintLogInformation = printLog;                printHelper.ExportImageDeviceInfo.DpiX = dpiX;                printHelper.ExportImageDeviceInfo.DpiY = dpiY;                printHelper.ExportImageDeviceInfo.PageWidth = pageWidth;                printHelper.ExportImageDeviceInfo.PageHeight = pageHeight;                foreach (BarcodeData bdCurrent in this._listBarcodeData) {                    if (worker.CancellationPending == true) {                        e.Cancel = true;                        break;                    }                    else {                        try {                            DataSet dsCurrent = this.GetDataForPrinterByBarcode(bdCurrent.Barcode, bdCurrent.IncreaseType);                            DataSet dsNext = null, dsPrevious = dsCurrent.Copy();                            int amount = this._printType == 0 ? 1 : bdCurrent.Amount - nextRemainder;                            int copies = amount / perPaperFactor;                            int remainder = nextRemainder = amount % perPaperFactor;                            Action<DataSet, int, string, int> actPrint = (ds, duplicates, barcodes, amountForLog) => {                                printHelper.PrintLogInformation.Barcode = barcodes;                                printHelper.PrintLogInformation.Amount = amountForLog;                                if (this.PrintType == 0 && DeviceType == DeviceType.DRV) {                                    printerSettings.Copies = (short)duplicates;                                    printHelper.WindowsDriverPrint(printerSettings, dpiX, ds);                                }                                else {                                    printHelper.OriginalPrint(DeviceType, ds, duplicates, PrintParam);                                }                            };                            if (copies > 0) {                                int amountForCopy = copies;                                if (perPaperFactor > 1) {                                    DataSet dsCurrentCopy = dsCurrent.CopyForBarcode();                                    dsCurrent.Merge(dsCurrentCopy);                                    amountForCopy = copies * perPaperFactor;                                }                                actPrint.Invoke(dsCurrent, copies, bdCurrent.Barcode, amountForCopy);                            }                            if (remainder > 0) {                                int nextIndex = i + 1;                                string barcodes = bdCurrent.Barcode;                                if (nextIndex < count) {                                    BarcodeData bdNext = this._listBarcodeData[nextIndex];                                    dsNext = this.GetDataForPrinterByBarcode(bdNext.Barcode, bdNext.IncreaseType);                                    dsPrevious.Merge(dsNext);                                    barcodes += "," + bdNext.Barcode;                                }                                actPrint.Invoke(dsPrevious, 1, barcodes, 1);                            }                            worker.ReportProgress(i++, string.Format("正在生成 {0} 并输送往打印机...", bdCurrent.Barcode));                            if (this._printType == 0) {                                count = 1;                                flag = true;                                break;                            }                        }                        catch (Exception ex) {                            flag = false;                            e.Result = ex.Message;                            break;                        }                    }                }                if (!e.Cancel && flag) {                    e.Result = string.Format("打印操作成功完成,共处理条码 {0} 条", count);                }            }        }

 

LocalReportHelper类代码:

using System;using System.Configuration;using System.Data;using System.Drawing;using System.Drawing.Imaging;using System.Drawing.Printing;using System.IO;using System.Text;using System.Windows.Forms;using Microsoft.Reporting.WinForms;using Umisky.BarcodePrint.Core;namespace Umisky.BarcodePrint.Codes {    public class LocalReportHelper : IDisposable {        #region Properties        public String LocalReportPath { get; set; }        public LocalReport LocalReportInstance { get; private set; }        public GraphDeviceInfo ExportImageDeviceInfo { get; set; }        public PrintLog PrintLogInformation { get; set; }        public int PrintTypeNO { get; set; }        #endregion        private Stream _stream;        private int _bmpDPI;        private DataSet _ds;        public LocalReportHelper(String reportPath)            : this(reportPath, new GraphDeviceInfo() {                ColorDepth = 1,                DpiX = 203,                DpiY = 203,                PageWidth = 8f,                PageHeight = 12.2f,                MarginTop = 0.2f            }) { }        public LocalReportHelper(String reportPath, GraphDeviceInfo deviceInfo) {            this._bmpDPI = 96;            this.LocalReportPath = reportPath;            this.ExportImageDeviceInfo = deviceInfo;            this.LocalReportInstance = new LocalReport() { ReportPath = reportPath };            this.LocalReportInstance.SubreportProcessing += new SubreportProcessingEventHandler(LocalReportInstance_SubreportProcessing);        }        private void LocalReportInstance_SubreportProcessing(object sender, SubreportProcessingEventArgs e) {            foreach (DataTable dt in this._ds.Tables) {                e.DataSources.Add(new ReportDataSource(dt.TableName, dt));            }        }        public void Dispose() {            this.ExportImageDeviceInfo = null;            this.LocalReportInstance = null;            this.LocalReportPath = null;            this._ds = null;        }        public void AddReportParameter(string paramName, string value) {            this.LocalReportInstance.SetParameters(new ReportParameter(paramName, value));        }        #region Export hang title image by reporting services        private void AddWashIcones() {            this.LocalReportInstance.EnableExternalImages = true;            this.LocalReportInstance.SetParameters(new ReportParameter("AppPath", Application.StartupPath));        }        private void AddBarcodesAssembly() {            this.LocalReportInstance.AddTrustedCodeModuleInCurrentAppDomain(ConfigurationManager.AppSettings["BarcodesAssembly"]);        }        private Stream CreateStreamCallBack(string name, string fileNameExtension, Encoding encoding, string mimeType, bool willSeek) {            string tempFolderPath = string.Concat(Environment.GetEnvironmentVariable("TEMP"), "/");            this._stream = new FileStream(string.Concat(tempFolderPath, name, ".", fileNameExtension), FileMode.Create);            return this._stream;        }        private void Export() {            if (string.IsNullOrEmpty(this.LocalReportPath) ||                this.LocalReportInstance == null ||                this.ExportImageDeviceInfo == null) {                throw new InvalidExpressionException("Invalid parameters");            }            if (this.PrintTypeNO >= -1 || this.PrintTypeNO == -3) {                this.AddBarcodesAssembly();                if (this.PrintTypeNO >= 0) {                    this.AddWashIcones();                }            }            if (this.PrintTypeNO >= 0) {                this.LocalReportInstance.DataSources.Clear();                foreach (DataTable dt in this._ds.Tables) {                    this.LocalReportInstance.DataSources.Add(new ReportDataSource(dt.TableName, dt));                }            }            this.LocalReportInstance.Refresh();            if (this._stream != null) {                this._stream.Close();                this._stream = null;            }            Warning[] warnings;            this.LocalReportInstance.Render(                "Image",                this.ExportImageDeviceInfo.ToString(),                PageCountMode.Actual,                CreateStreamCallBack,                out warnings);            this._stream.Position = 0;        }        private void SaveLog() {            using (Bitmap image = (Bitmap)Image.FromStream(this._stream)) {                image.SetResolution(96, 96);                using (MemoryStream ms = new MemoryStream()) {                    image.Save(ms, ImageFormat.Jpeg);                    this.PrintLogInformation.BarcodeImage = ms.ToArray();                }            }            LogHelper.AddLog(this.PrintLogInformation);            if (this._stream != null) {                this._stream.Close();                this._stream = null;            }        }        #endregion        #region Windows driver print        private void PrintPage(object sender, PrintPageEventArgs ev) {            Bitmap bmp = (Bitmap)Image.FromStream(this._stream);            bmp.SetResolution(this._bmpDPI, this._bmpDPI);            ev.Graphics.DrawImage(bmp, 0, 0);            ev.HasMorePages = false;        }        /// <summary>        /// Print by windows driver        /// </summary>        /// <param name="printerSettings">.net framework PrinterSettings class, including some printer information</param>        /// <param name="bmpDPI">the bitmap image resoluation, dots per inch</param>        public void WindowsDriverPrint(PrinterSettings printerSettings, int bmpDPI, DataSet ds) {            this._ds = ds;            this.Export();            if (this._stream == null) {                return;            }            this._bmpDPI = bmpDPI;            PrintDocument printDoc = new PrintDocument();            printDoc.DocumentName = "条码打印";            printDoc.PrinterSettings = printerSettings;            printDoc.PrintController = new StandardPrintController();            if (!printDoc.PrinterSettings.IsValid) {                if (this._stream != null) {                    this._stream.Close();                    this._stream = null;                }                MessageBox.Show("Printer found errors, Please contact your administrators!", "Print Error");                return;            }            printDoc.PrintPage += new PrintPageEventHandler(PrintPage);            printDoc.Print();            this.SaveLog();        }        #endregion        #region Original print        /// <summary>        /// Send the file to the printer or use the printer command        /// </summary>        /// <param name="deviceType">The port(LPT,COM,DRV) which the device connecting</param>        /// <param name="copies">Total number for print</param>        /// <param name="ds">The report datasource</param>        /// <param name="printParam">Print parameters</param>        /// <param name="printLanguage">The built-in printer programming language, you can choose EPL or ZPL</param>        public void OriginalPrint(DeviceType deviceType,            DataSet ds,            int copies = 1,            string printParam = null,            ProgrammingLanguage printLanguage = ProgrammingLanguage.ZPL) {            this._ds = ds;            this.Export();            if (this._stream == null) {                return;            }            int port = 1;            int.TryParse(printParam, out port);            int length = (int)this._stream.Length;            byte[] bytes = new byte[length];            this._stream.Read(bytes, 0, length);            ZebraPrintHelper.Copies = copies;            ZebraPrintHelper.PrinterType = deviceType;            ZebraPrintHelper.PrinterName = printParam;            ZebraPrintHelper.Port = port;            ZebraPrintHelper.PrinterProgrammingLanguage = printLanguage;            ZebraPrintHelper.PrintGraphics(bytes);            this.SaveLog();        }        #endregion    }}