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

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

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

    网上搜索一番,找不到什么资料,基本都是说发送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类代码:

    [csharp] view plaincopy
     
    1. using System;  
    2. using System.Collections.Generic;  
    3. using System.Drawing;  
    4. using System.Drawing.Imaging;  
    5. using System.IO;  
    6. using System.IO.Ports;  
    7. using System.Net.Sockets;  
    8. using System.Runtime.InteropServices;  
    9. using System.Text;  
    10.   
    11. namespace Umisky.BarcodePrint.Core {  
    12.     /// <summary>  
    13.     /// 斑马打印助手,支持LPT/COM/USB/TCP四种模式,适用于标签、票据、条码打印。  
    14.     /// </summary>  
    15.     public static class ZebraPrintHelper {  
    16.  
    17.         #region 定义私有字段  
    18.         /// <summary>  
    19.         /// 线程锁,防止多线程调用。  
    20.         /// </summary>  
    21.         private static object SyncRoot = new object();  
    22.         /// <summary>  
    23.         /// ZPL压缩字典  
    24.         /// </summary>  
    25.         private static List<KeyValue> compressDictionary = new List<KeyValue>();  
    26.         #endregion  
    27.  
    28.         #region 定义属性  
    29.         public static float TcpLabelMaxHeightCM { get; set; }  
    30.         public static int TcpPrinterDPI { get; set; }  
    31.         public static string TcpIpAddress { get; set; }  
    32.         public static int TcpPort { get; set; }  
    33.         public static int Copies { get; set; }  
    34.         public static int Port { get; set; }  
    35.         public static string PrinterName { get; set; }  
    36.         public static bool IsWriteLog { get; set; }  
    37.         public static DeviceType PrinterType { get; set; }  
    38.         public static ProgrammingLanguage PrinterProgrammingLanguage { get; set; }  
    39.         /// <summary>  
    40.         /// 日志保存目录,WEB应用注意不能放在BIN目录下。  
    41.         /// </summary>  
    42.         public static string LogsDirectory { get; set; }  
    43.         public static byte[] GraphBuffer { get; set; }  
    44.         private static int GraphWidth { get; set; }  
    45.         private static int GraphHeight { get; set; }  
    46.         private static int RowSize {  
    47.             get {  
    48.                 return (((GraphWidth) + 31) >> 5) << 2;  
    49.             }  
    50.         }  
    51.         private static int RowRealBytesCount {  
    52.             get {  
    53.                 if ((GraphWidth % 8) > 0) {  
    54.                     return GraphWidth / 8 + 1;  
    55.                 }  
    56.                 else {  
    57.                     return GraphWidth / 8;  
    58.                 }  
    59.             }  
    60.         }  
    61.         #endregion  
    62.  
    63.         #region 静态构造方法  
    64.         static ZebraPrintHelper() {  
    65.             initCompressCode();  
    66.             Port = 1;  
    67.             GraphBuffer = new byte[0];  
    68.             IsWriteLog = false;  
    69.             LogsDirectory = "logs";  
    70.             PrinterProgrammingLanguage = ProgrammingLanguage.ZPL;  
    71.         }  
    72.   
    73.         private static void initCompressCode() {  
    74.             //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。  
    75.             //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。              
    76.             for (int i = 0; i < 19; i++) {  
    77.                 compressDictionary.Add(new KeyValue() { Key = Convert.ToChar(71 + i), Value = i + 1 });  
    78.             }  
    79.             for (int i = 0; i < 20; i++) {  
    80.                 compressDictionary.Add(new KeyValue() { Key = Convert.ToChar(103 + i), Value = (i + 1) * 20 });  
    81.             }  
    82.         }  
    83.         #endregion  
    84.  
    85.         #region 日志记录方法  
    86.         private static void WriteLog(string text, LogType logType) {  
    87.             string endTag = string.Format(" {0} ", new string('=', 80));  
    88.             string path = string.Format("{0}\{1}-{2}.log", LogsDirectory, DateTime.Now.ToString("yyyy-MM-dd"), logType);  
    89.             if (!Directory.Exists(LogsDirectory)) {  
    90.                 Directory.CreateDirectory(LogsDirectory);  
    91.             }  
    92.             if (logType == LogType.Error) {  
    93.                 File.AppendAllText(path, string.Format("{0}{1}", text, endTag), Encoding.UTF8);  
    94.             }  
    95.             if (logType == LogType.Print) {  
    96.                 File.AppendAllText(path, string.Format("{0}{1}", text, endTag), Encoding.UTF8);  
    97.             }  
    98.         }  
    99.   
    100.         private static void WriteLog(byte[] bytes, LogType logType) {  
    101.             string endTag = string.Format(" {0} ", new string('=', 80));  
    102.             string path = string.Format("{0}\{1}-{2}.log", LogsDirectory, DateTime.Now.ToString("yyyy-MM-dd"), logType);  
    103.             if (!Directory.Exists(LogsDirectory)) {  
    104.                 Directory.CreateDirectory(LogsDirectory);  
    105.             }  
    106.             if (logType == LogType.Error) {  
    107.                 File.AppendAllText(path, string.Format("{0}{1}", Encoding.UTF8.GetString(bytes), endTag), Encoding.UTF8);  
    108.             }  
    109.             if (logType == LogType.Print) {  
    110.                 File.AppendAllText(path, string.Format("{0}{1}", Encoding.UTF8.GetString(bytes), endTag), Encoding.UTF8);  
    111.             }  
    112.         }  
    113.         #endregion  
    114.  
    115.         #region 封装方法,方便调用。  
    116.         public static bool PrintWithCOM(string cmd, int port, bool isWriteLog) {  
    117.             PrinterType = DeviceType.COM;  
    118.             Port = port;  
    119.             IsWriteLog = isWriteLog;  
    120.             return PrintCommand(cmd);  
    121.         }  
    122.   
    123.         public static bool PrintWithCOM(byte[] bytes, int port, bool isWriteLog) {  
    124.             PrinterType = DeviceType.COM;  
    125.             Port = port;  
    126.             IsWriteLog = isWriteLog;  
    127.             return PrintGraphics(bytes);  
    128.         }  
    129.   
    130.         public static bool PrintWithLPT(string cmd, int port, bool isWriteLog) {  
    131.             PrinterType = DeviceType.LPT;  
    132.             Port = port;  
    133.             IsWriteLog = isWriteLog;  
    134.             return PrintCommand(cmd);  
    135.         }  
    136.   
    137.         public static bool PrintWithLPT(byte[] bytes, int port, bool isWriteLog) {  
    138.             PrinterType = DeviceType.LPT;  
    139.             Port = port;  
    140.             IsWriteLog = isWriteLog;  
    141.             return PrintGraphics(bytes);  
    142.         }  
    143.   
    144.         public static bool PrintWithTCP(string cmd, bool isWriteLog) {  
    145.             PrinterType = DeviceType.TCP;  
    146.             IsWriteLog = isWriteLog;  
    147.             return PrintCommand(cmd);  
    148.         }  
    149.   
    150.         public static bool PrintWithTCP(byte[] bytes, bool isWriteLog) {  
    151.             PrinterType = DeviceType.TCP;  
    152.             IsWriteLog = isWriteLog;  
    153.             return PrintGraphics(bytes);  
    154.         }  
    155.   
    156.         public static bool PrintWithDRV(string cmd, string printerName, bool isWriteLog) {  
    157.             PrinterType = DeviceType.DRV;  
    158.             PrinterName = printerName;  
    159.             IsWriteLog = isWriteLog;  
    160.             return PrintCommand(cmd);  
    161.         }  
    162.   
    163.         public static bool PrintWithDRV(byte[] bytes, string printerName, bool isWriteLog) {  
    164.             PrinterType = DeviceType.DRV;  
    165.             PrinterName = printerName;  
    166.             IsWriteLog = isWriteLog;  
    167.             return PrintGraphics(bytes);  
    168.         }  
    169.         #endregion  
    170.  
    171.         #region 打印ZPL、EPL、CPCL、TCP指令  
    172.         public static bool PrintCommand(string cmd) {  
    173.             lock (SyncRoot) {  
    174.                 bool result = false;  
    175.                 try {  
    176.                     switch (PrinterType) {  
    177.                         case DeviceType.COM:  
    178.                             result = comPrint(Encoding.Default.GetBytes(cmd));  
    179.                             break;  
    180.                         case DeviceType.LPT:  
    181.                             result = lptPrint(Encoding.Default.GetBytes(cmd));  
    182.                             break;  
    183.                         case DeviceType.DRV:  
    184.                             result = drvPrint(Encoding.Default.GetBytes(cmd));  
    185.                             break;  
    186.                         case DeviceType.TCP:  
    187.                             result = tcpPrint(Encoding.Default.GetBytes(cmd));  
    188.                             break;  
    189.                     }  
    190.                     if (!string.IsNullOrEmpty(cmd) && IsWriteLog) {  
    191.                         WriteLog(cmd, LogType.Print);  
    192.                     }  
    193.                 }  
    194.                 catch (Exception ex) {  
    195.                     //记录日志  
    196.                     if (IsWriteLog) {  
    197.                         WriteLog(string.Format("{0} => {1} {2}", DateTime.Now, ex.Message, ex), LogType.Error);  
    198.                     }  
    199.                     throw new Exception(ex.Message, ex);  
    200.                 }  
    201.                 finally {  
    202.                     GraphBuffer = new byte[0];  
    203.                 }  
    204.                 return result;  
    205.             }  
    206.         }  
    207.         #endregion  
    208.  
    209.         #region 打印图像  
    210.         public static bool PrintGraphics(byte[] graph) {  
    211.             lock (SyncRoot) {  
    212.                 bool result = false;  
    213.                 try {  
    214.                     GraphBuffer = graph;  
    215.                     byte[] cmdBytes = new byte[0];  
    216.                     switch (PrinterProgrammingLanguage) {  
    217.                         case ProgrammingLanguage.ZPL:  
    218.                             cmdBytes = getZPLBytes();  
    219.                             break;  
    220.                         case ProgrammingLanguage.EPL:  
    221.                             cmdBytes = getEPLBytes();  
    222.                             break;  
    223.                         case ProgrammingLanguage.CPCL:  
    224.                             cmdBytes = getCPCLBytes();  
    225.                             break;  
    226.                     }  
    227.                     switch (PrinterType) {  
    228.                         case DeviceType.COM:  
    229.                             result = comPrint(cmdBytes);  
    230.                             break;  
    231.                         case DeviceType.LPT:  
    232.                             result = lptPrint(cmdBytes);  
    233.                             break;  
    234.                         case DeviceType.DRV:  
    235.                             result = drvPrint(cmdBytes);  
    236.                             break;  
    237.                         case DeviceType.TCP:  
    238.                             result = tcpPrint(cmdBytes);  
    239.                             break;  
    240.                     }  
    241.                     if (cmdBytes.Length > 0 && IsWriteLog) {  
    242.                         WriteLog(cmdBytes, LogType.Print);  
    243.                     }  
    244.                 }  
    245.                 catch (Exception ex) {  
    246.                     //记录日志  
    247.                     if (IsWriteLog) {  
    248.                         WriteLog(string.Format("{0} => {1} {2}", DateTime.Now, ex.Message, ex), LogType.Error);  
    249.                     }  
    250.                     throw new Exception(ex.Message, ex);  
    251.                 }  
    252.                 finally {  
    253.                     GraphBuffer = new byte[0];  
    254.                 }  
    255.                 return result;  
    256.             }  
    257.         }  
    258.         #endregion  
    259.  
    260.         #region 打印指令  
    261.         private static bool drvPrint(byte[] cmdBytes) {  
    262.             bool result = false;  
    263.             try {  
    264.                 if (!string.IsNullOrEmpty(PrinterName)) {  
    265.                     result = WinDrvPort.SendBytesToPrinter(PrinterName, cmdBytes);  
    266.                 }  
    267.             }  
    268.             catch (Exception ex) {  
    269.                 throw new Exception(ex.Message, ex);  
    270.             }  
    271.             return result;  
    272.         }  
    273.   
    274.         private static bool comPrint(byte[] cmdBytes) {  
    275.             bool result = false;  
    276.             SerialPort com = new SerialPort(string.Format("{0}{1}", PrinterType, Port), 9600, Parity.None, 8, StopBits.One);  
    277.             try {  
    278.                 com.Open();  
    279.                 com.Write(cmdBytes, 0, cmdBytes.Length);  
    280.                 result = true;  
    281.             }  
    282.             catch (Exception ex) {  
    283.                 throw new Exception(ex.Message, ex);  
    284.             }  
    285.             finally {  
    286.                 if (com.IsOpen) {  
    287.                     com.Close();  
    288.                 }  
    289.             }  
    290.             return result;  
    291.         }  
    292.   
    293.         private static bool lptPrint(byte[] cmdBytes) {  
    294.             return LptPort.Write(string.Format("{0}{1}", PrinterType, Port), cmdBytes);  
    295.         }  
    296.   
    297.         private static bool tcpPrint(byte[] cmdBytes) {  
    298.             bool result = false;  
    299.             TcpClient tcp = null;  
    300.             try {  
    301.                 tcp = TimeoutSocket.Connect(string.Empty, TcpIpAddress, TcpPort, 1000);  
    302.                 tcp.SendTimeout = 1000;  
    303.                 tcp.ReceiveTimeout = 1000;  
    304.                 if (tcp.Connected) {  
    305.                     tcp.Client.Send(cmdBytes);  
    306.                     result = true;  
    307.                 }  
    308.             }  
    309.             catch (Exception ex) {  
    310.                 throw new Exception("打印失败,请检查打印机或网络设置。", ex);  
    311.             }  
    312.             finally {  
    313.                 if (tcp != null) {  
    314.                     if (tcp.Client != null) {  
    315.                         tcp.Client.Close();  
    316.                         tcp.Client = null;  
    317.                     }  
    318.                     tcp.Close();  
    319.                     tcp = null;  
    320.                 }  
    321.             }  
    322.             return result;  
    323.         }  
    324.         #endregion  
    325.  
    326.         #region 生成ZPL图像打印指令  
    327.         private static byte[] getZPLBytes() {  
    328.             byte[] bmpData = getBitmapData();  
    329.             int bmpDataLength = bmpData.Length;  
    330.             for (int i = 0; i < bmpDataLength; i++) {  
    331.                 bmpData[i] ^= 0xFF;  
    332.             }  
    333.             string textBitmap = string.Empty, copiesString = string.Empty;  
    334.             string textHex = BitConverter.ToString(bmpData).Replace("-", string.Empty);  
    335.             textBitmap = CompressLZ77(textHex);  
    336.             for (int i = 0; i < Copies; i++) {  
    337.                 copiesString += "^XA^FO0,0^XGR:IMAGE.GRF,1,1^FS^XZ";  
    338.             }  
    339.             string text = string.Format("~DGR:IMAGE.GRF,{0},{1},{2}{3}^IDR:IMAGE.GRF",  
    340.                 GraphHeight * RowRealBytesCount,  
    341.                 RowRealBytesCount,  
    342.                 textBitmap,  
    343.                 copiesString);  
    344.             return Encoding.UTF8.GetBytes(text);  
    345.         }  
    346.         #endregion  
    347.  
    348.         #region 生成EPL图像打印指令  
    349.         private static byte[] getEPLBytes() {  
    350.             byte[] buffer = getBitmapData();  
    351.             string text = string.Format("N GW{0},{1},{2},{3},{4} P{5},1 ",  
    352.                 0,  
    353.                 0,  
    354.                 RowRealBytesCount,  
    355.                 GraphHeight,  
    356.                 Encoding.GetEncoding("iso-8859-1").GetString(buffer),  
    357.                 Copies);  
    358.             return Encoding.GetEncoding("iso-8859-1").GetBytes(text);  
    359.         }  
    360.         #endregion  
    361.  
    362.         #region 生成CPCL图像打印指令  
    363.         public static byte[] getCPCLBytes() {  
    364.             //GRAPHICS Commands  
    365.             //Bit-mapped graphics can be printed by using graphics commands. ASCII hex (hexadecimal) is  
    366.             //used for expanded graphics data (see example). Data size can be reduced to one-half by utilizing the  
    367.             //COMPRESSED-GRAPHICS commands with the equivalent binary character(s) of the hex data. When  
    368.             //using CG, a single 8 bit character is sent for every 8 bits of graphics data. When using EG two characters  
    369.             //(16 bits) are used to transmit 8 bits of graphics data, making EG only half as efficient. Since this data is  
    370.             //character data, however, it can be easier to handle and transmit than binary data.  
    371.             //Format:  
    372.             //{command} {width} {height} {x} {y} {data}  
    373.             //where:  
    374.             //{command}: Choose from the following:  
    375.             //EXPANDED-GRAPHICS (or EG): Prints expanded graphics horizontally.  
    376.             //VEXPANDED-GRAPHICS (or VEG): Prints expanded graphics vertically.  
    377.             //COMPRESSED-GRAPHICS (or CG): Prints compressed graphics horizontally.  
    378.             //VCOMPRESSED-GRAPHICS (or VCG): Prints compressed graphics vertically.  
    379.             //{width}: Byte-width of image.  
    380.             //{height} Dot-height of image.  
    381.             //{x}: Horizontal starting position.  
    382.             //{y}: Vertical starting position.  
    383.             //{data}: Graphics data.  
    384.             //Graphics command example  
    385.             //Input:  
    386.             //! 0 200 200 210 1  
    387.             //EG 2 16 90 45 F0F0F0F0F0F0F0F00F0F0F0F0F0F0F0F  
    388.             //F0F0F0F0F0F0F0F00F0F0F0F0F0F0F0F  
    389.             //FORM  
    390.             //PRINT  
    391.   
    392.             byte[] bmpData = getBitmapData();  
    393.             int bmpDataLength = bmpData.Length;  
    394.             for (int i = 0; i < bmpDataLength; i++) {  
    395.                 bmpData[i] ^= 0xFF;  
    396.             }  
    397.             string textHex = BitConverter.ToString(bmpData).Replace("-", string.Empty);  
    398.             string text = string.Format("! {0} {1} {2} {3} {4} EG {5} {6} {7} {8} {9} FORM PRINT ",  
    399.                 0, //水平偏移量  
    400.                 TcpPrinterDPI, //横向DPI  
    401.                 TcpPrinterDPI, //纵向DPI  
    402.                 (int)(TcpLabelMaxHeightCM / 2.54f * TcpPrinterDPI), //标签最大像素高度=DPI*标签纸高度(英寸)  
    403.                 Copies, //份数  
    404.                 RowRealBytesCount, //图像的字节宽度  
    405.                 GraphHeight, //图像的像素高度  
    406.                 0, //横向的开始位置  
    407.                 0, //纵向的开始位置  
    408.                 textHex  
    409.                 );  
    410.             return Encoding.UTF8.GetBytes(text);  
    411.         }  
    412.         #endregion  
    413.  
    414.         #region 获取单色位图数据  
    415.         /// <summary>  
    416.         ///   
    417.         /// </summary>  
    418.         /// <param name="pimage"></param>  
    419.         /// <returns></returns>  
    420.         public static Bitmap ConvertToGrayscale(Bitmap pimage) {  
    421.             Bitmap source = null;  
    422.   
    423.             // If original bitmap is not already in 32 BPP, ARGB format, then convert  
    424.             if (pimage.PixelFormat != PixelFormat.Format32bppArgb) {  
    425.                 source = new Bitmap(pimage.Width, pimage.Height, PixelFormat.Format32bppArgb);  
    426.                 source.SetResolution(pimage.HorizontalResolution, pimage.VerticalResolution);  
    427.                 using (Graphics g = Graphics.FromImage(source)) {  
    428.                     g.DrawImageUnscaled(pimage, 0, 0);  
    429.                 }  
    430.             }  
    431.             else {  
    432.                 source = pimage;  
    433.             }  
    434.   
    435.             // Lock source bitmap in memory  
    436.             BitmapData sourceData = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);  
    437.   
    438.             // Copy image data to binary array  
    439.             int imageSize = sourceData.Stride * sourceData.Height;  
    440.             byte[] sourceBuffer = new byte[imageSize];  
    441.             Marshal.Copy(sourceData.Scan0, sourceBuffer, 0, imageSize);  
    442.   
    443.             // Unlock source bitmap  
    444.             source.UnlockBits(sourceData);  
    445.   
    446.             // Create destination bitmap  
    447.             Bitmap destination = new Bitmap(source.Width, source.Height, PixelFormat.Format1bppIndexed);  
    448.   
    449.             // Lock destination bitmap in memory  
    450.             BitmapData destinationData = destination.LockBits(new Rectangle(0, 0, destination.Width, destination.Height), ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed);  
    451.   
    452.             // Create destination buffer  
    453.             imageSize = destinationData.Stride * destinationData.Height;  
    454.             byte[] destinationBuffer = new byte[imageSize];  
    455.   
    456.             int sourceIndex = 0;  
    457.             int destinationIndex = 0;  
    458.             int pixelTotal = 0;  
    459.             byte destinationValue = 0;  
    460.             int pixelValue = 128;  
    461.             int height = source.Height;  
    462.             int width = source.Width;  
    463.             int threshold = 500;  
    464.   
    465.             // Iterate lines  
    466.             for (int y = 0; y < height; y++) {  
    467.                 sourceIndex = y * sourceData.Stride;  
    468.                 destinationIndex = y * destinationData.Stride;  
    469.                 destinationValue = 0;  
    470.                 pixelValue = 128;  
    471.   
    472.                 // Iterate pixels  
    473.                 for (int x = 0; x < width; x++) {  
    474.                     // Compute pixel brightness (i.e. total of Red, Green, and Blue values)  
    475.                     pixelTotal = sourceBuffer[sourceIndex + 1] + sourceBuffer[sourceIndex + 2] + sourceBuffer[sourceIndex + 3];  
    476.                     if (pixelTotal > threshold) {  
    477.                         destinationValue += (byte)pixelValue;  
    478.                     }  
    479.                     if (pixelValue == 1) {  
    480.                         destinationBuffer[destinationIndex] = destinationValue;  
    481.                         destinationIndex++;  
    482.                         destinationValue = 0;  
    483.                         pixelValue = 128;  
    484.                     }  
    485.                     else {  
    486.                         pixelValue >>= 1;  
    487.                     }  
    488.                     sourceIndex += 4;  
    489.                 }  
    490.                 if (pixelValue != 128) {  
    491.                     destinationBuffer[destinationIndex] = destinationValue;  
    492.                 }  
    493.             }  
    494.   
    495.             // Copy binary image data to destination bitmap  
    496.             Marshal.Copy(destinationBuffer, 0, destinationData.Scan0, imageSize);  
    497.   
    498.             // Unlock destination bitmap  
    499.             destination.UnlockBits(destinationData);  
    500.   
    501.             // Dispose of source if not originally supplied bitmap  
    502.             if (source != pimage) {  
    503.                 source.Dispose();  
    504.             }  
    505.   
    506.             // Return  
    507.             return destination;  
    508.         }  
    509.         /// <summary>  
    510.         /// 获取单色位图数据(1bpp),不含文件头、信息头、调色板三类数据。  
    511.         /// </summary>  
    512.         /// <returns></returns>  
    513.         private static byte[] getBitmapData() {  
    514.             MemoryStream srcStream = new MemoryStream();  
    515.             MemoryStream dstStream = new MemoryStream();  
    516.             Bitmap srcBmp = null;  
    517.             Bitmap dstBmp = null;  
    518.             byte[] srcBuffer = null;  
    519.             byte[] dstBuffer = null;  
    520.             byte[] result = null;  
    521.             try {  
    522.                 srcStream = new MemoryStream(GraphBuffer);  
    523.                 srcBmp = Bitmap.FromStream(srcStream) as Bitmap;  
    524.                 srcBuffer = srcStream.ToArray();  
    525.                 GraphWidth = srcBmp.Width;  
    526.                 GraphHeight = srcBmp.Height;  
    527.                 //dstBmp = srcBmp.Clone(new Rectangle(0, 0, srcBmp.Width, srcBmp.Height), PixelFormat.Format1bppIndexed);  
    528.                 dstBmp = ConvertToGrayscale(srcBmp);  
    529.                 dstBmp.Save(dstStream, ImageFormat.Bmp);  
    530.                 dstBuffer = dstStream.ToArray();  
    531.   
    532.                 int bfOffBits = BitConverter.ToInt32(dstBuffer, 10);  
    533.                 result = new byte[GraphHeight * RowRealBytesCount];  
    534.   
    535.                 //读取时需要反向读取每行字节实现上下翻转的效果,打印机打印顺序需要这样读取。  
    536.                 for (int i = 0; i < GraphHeight; i++) {  
    537.                     Array.Copy(dstBuffer, bfOffBits + (GraphHeight - 1 - i) * RowSize, result, i * RowRealBytesCount, RowRealBytesCount);  
    538.                 }  
    539.             }  
    540.             catch (Exception ex) {  
    541.                 throw new Exception(ex.Message, ex);  
    542.             }  
    543.             finally {  
    544.                 if (srcStream != null) {  
    545.                     srcStream.Dispose();  
    546.                     srcStream = null;  
    547.                 }  
    548.                 if (dstStream != null) {  
    549.                     dstStream.Dispose();  
    550.                     dstStream = null;  
    551.                 }  
    552.                 if (srcBmp != null) {  
    553.                     srcBmp.Dispose();  
    554.                     srcBmp = null;  
    555.                 }  
    556.                 if (dstBmp != null) {  
    557.                     dstBmp.Dispose();  
    558.                     dstBmp = null;  
    559.                 }  
    560.             }  
    561.             return result;  
    562.         }  
    563.         #endregion  
    564.  
    565.         #region LZ77图像字节流压缩方法  
    566.         public static string CompressLZ77(string text) {  
    567.             //将转成16进制的文本进行压缩  
    568.             string result = string.Empty;  
    569.             char[] arrChar = text.ToCharArray();  
    570.             int count = 1;  
    571.             for (int i = 1; i < text.Length; i++) {  
    572.                 if (arrChar[i - 1] == arrChar[i]) {  
    573.                     count++;  
    574.                 }  
    575.                 else {  
    576.                     result += convertNumber(count) + arrChar[i - 1];  
    577.                     count = 1;  
    578.                 }  
    579.                 if (i == text.Length - 1) {  
    580.                     result += convertNumber(count) + arrChar[i];  
    581.                 }  
    582.             }  
    583.             return result;  
    584.         }  
    585.   
    586.         public static string DecompressLZ77(string text) {  
    587.             string result = string.Empty;  
    588.             char[] arrChar = text.ToCharArray();  
    589.             int count = 0;  
    590.             for (int i = 0; i < arrChar.Length; i++) {  
    591.                 if (isHexChar(arrChar[i])) {  
    592.                     //十六进制值  
    593.                     result += new string(arrChar[i], count == 0 ? 1 : count);  
    594.                     count = 0;  
    595.                 }  
    596.                 else {  
    597.                     //压缩码  
    598.                     int value = GetCompressValue(arrChar[i]);  
    599.                     count += value;  
    600.                 }  
    601.             }  
    602.             return result;  
    603.         }  
    604.   
    605.         private static int GetCompressValue(char c) {  
    606.             int result = 0;  
    607.             for (int i = 0; i < compressDictionary.Count; i++) {  
    608.                 if (c == compressDictionary[i].Key) {  
    609.                     result = compressDictionary[i].Value;  
    610.                 }  
    611.             }  
    612.             return result;  
    613.         }  
    614.   
    615.         private static bool isHexChar(char c) {  
    616.             return c > 47 && c < 58 || c > 64 && c < 71 || c > 96 && c < 103;  
    617.         }  
    618.   
    619.         private static string convertNumber(int count) {  
    620.             //将连续的数字转换成LZ77压缩代码,如000可用I0表示。  
    621.             string result = string.Empty;  
    622.             if (count > 1) {  
    623.                 while (count > 0) {  
    624.                     for (int i = compressDictionary.Count - 1; i >= 0; i--) {  
    625.                         if (count >= compressDictionary[i].Value) {  
    626.                             result += compressDictionary[i].Key;  
    627.                             count -= compressDictionary[i].Value;  
    628.                             break;  
    629.                         }  
    630.                     }  
    631.                 }  
    632.             }  
    633.             return result;  
    634.         }  
    635.         #endregion  
    636.     }  
    637. }  

    调用例子代码:

    [csharp] view plaincopy
     
    1. private void BackgroundWorkerPrint_DoWork(object sender, DoWorkEventArgs e) {  
    2.     BackgroundWorker worker = sender as BackgroundWorker;  
    3.   
    4.     int i = 0, nextRemainder = 0, count = this._listBarcodeData.Count;  
    5.     bool flag = true;  
    6.     float pageWidth, pageHeight;  
    7.     int dpiX, dpiY, perPaperFactor;  
    8.     string reportPath = string.Format(@"{0}/Reports/{1}", Application.StartupPath, this._modelType);  
    9.     PrintLog printLog = new PrintLog() { Operater = LoginName };  
    10.     PrinterSettings printerSettings = new PrinterSettings() { PrinterName = PrintParam, Copies = 1 };  
    11.   
    12.     using (StreamReader tr = new StreamReader(this.ModelFilePath)) {  
    13.         XElement xe = XDocument.Load(tr).Root.Elements()  
    14.             .Elements(XName.Get("ModelType")).First(x => x.Value == this._modelType).Parent;  
    15.         pageWidth = float.Parse(xe.Elements(XName.Get("PageWidth")).First().Value);  
    16.         pageHeight = float.Parse(xe.Elements(XName.Get("PageHeight")).First().Value);  
    17.         dpiX = int.Parse(xe.Elements(XName.Get("DotPerInchX")).First().Value);  
    18.         dpiY = int.Parse(xe.Elements(XName.Get("DotPerInchY")).First().Value);  
    19.         perPaperFactor = int.Parse(xe.Elements(XName.Get("PerPaperFactor")).First().Value);  
    20.         this._no = int.Parse(xe.Elements(XName.Get("NO")).First().Value);  
    21.     }  
    22.   
    23.     using (LocalReportHelper printHelper = new LocalReportHelper(reportPath)) {  
    24.         printHelper.PrintTypeNO = this._no;  
    25.         printHelper.PrintLogInformation = printLog;  
    26.         printHelper.ExportImageDeviceInfo.DpiX = dpiX;  
    27.         printHelper.ExportImageDeviceInfo.DpiY = dpiY;  
    28.         printHelper.ExportImageDeviceInfo.PageWidth = pageWidth;  
    29.         printHelper.ExportImageDeviceInfo.PageHeight = pageHeight;  
    30.         foreach (BarcodeData bdCurrent in this._listBarcodeData) {  
    31.             if (worker.CancellationPending == true) {  
    32.                 e.Cancel = true;  
    33.                 break;  
    34.             }  
    35.             else {  
    36.                 try {  
    37.                     DataSet dsCurrent = this.GetDataForPrinterByBarcode(bdCurrent.Barcode, bdCurrent.IncreaseType);  
    38.                     DataSet dsNext = null, dsPrevious = dsCurrent.Copy();  
    39.   
    40.                     int amount = this._printType == 0 ? 1 : bdCurrent.Amount - nextRemainder;  
    41.                     int copies = amount / perPaperFactor;  
    42.                     int remainder = nextRemainder = amount % perPaperFactor;  
    43.   
    44.                     Action<DataSet, int, string, int> actPrint = (ds, duplicates, barcodes, amountForLog) => {  
    45.                         printHelper.PrintLogInformation.Barcode = barcodes;  
    46.                         printHelper.PrintLogInformation.Amount = amountForLog;  
    47.                         if (this.PrintType == 0 && DeviceType == DeviceType.DRV) {  
    48.                             printerSettings.Copies = (short)duplicates;  
    49.                             printHelper.WindowsDriverPrint(printerSettings, dpiX, ds);  
    50.                         }  
    51.                         else {  
    52.                             printHelper.OriginalPrint(DeviceType, ds, duplicates, PrintParam);  
    53.                         }  
    54.                     };  
    55.   
    56.                     if (copies > 0) {  
    57.                         int amountForCopy = copies;  
    58.                         if (perPaperFactor > 1) {  
    59.                             DataSet dsCurrentCopy = dsCurrent.CopyForBarcode();  
    60.                             dsCurrent.Merge(dsCurrentCopy);  
    61.                             amountForCopy = copies * perPaperFactor;  
    62.                         }  
    63.   
    64.                         actPrint.Invoke(dsCurrent, copies, bdCurrent.Barcode, amountForCopy);  
    65.                     }  
    66.                     if (remainder > 0) {  
    67.                         int nextIndex = i + 1;  
    68.                         string barcodes = bdCurrent.Barcode;  
    69.                         if (nextIndex < count) {  
    70.                             BarcodeData bdNext = this._listBarcodeData[nextIndex];  
    71.                             dsNext = this.GetDataForPrinterByBarcode(bdNext.Barcode, bdNext.IncreaseType);  
    72.                             dsPrevious.Merge(dsNext);  
    73.                             barcodes += "," + bdNext.Barcode;  
    74.                         }  
    75.                         actPrint.Invoke(dsPrevious, 1, barcodes, 1);  
    76.                     }  
    77.                     worker.ReportProgress(i++, string.Format("正在生成 {0} 并输送往打印机...", bdCurrent.Barcode));  
    78.   
    79.                     if (this._printType == 0) {  
    80.                         count = 1;  
    81.                         flag = true;  
    82.                         break;  
    83.                     }  
    84.                 }  
    85.                 catch (Exception ex) {  
    86.                     flag = false;  
    87.                     e.Result = ex.Message;  
    88.                     break;  
    89.                 }  
    90.             }  
    91.         }  
    92.         if (!e.Cancel && flag) {  
    93.             e.Result = string.Format("打印操作成功完成,共处理条码 {0} 条", count);  
    94.         }  
    95.     }  
    96. }  

    LocalReportHelper类代码:

    [csharp] view plaincopy
     
    1. using System;  
    2. using System.Configuration;  
    3. using System.Data;  
    4. using System.Drawing;  
    5. using System.Drawing.Imaging;  
    6. using System.Drawing.Printing;  
    7. using System.IO;  
    8. using System.Text;  
    9. using System.Windows.Forms;  
    10. using Microsoft.Reporting.WinForms;  
    11. using Umisky.BarcodePrint.Core;  
    12.   
    13. namespace Umisky.BarcodePrint.Codes {  
    14.     public class LocalReportHelper : IDisposable {  
    15.  
    16.         #region Properties  
    17.   
    18.         public String LocalReportPath { get; set; }  
    19.         public LocalReport LocalReportInstance { get; private set; }  
    20.         public GraphDeviceInfo ExportImageDeviceInfo { get; set; }  
    21.         public PrintLog PrintLogInformation { get; set; }  
    22.         public int PrintTypeNO { get; set; }  
    23.  
    24.         #endregion  
    25.   
    26.         private Stream _stream;  
    27.         private int _bmpDPI;  
    28.         private DataSet _ds;  
    29.   
    30.         public LocalReportHelper(String reportPath)  
    31.             : this(reportPath, new GraphDeviceInfo() {  
    32.                 ColorDepth = 1,  
    33.                 DpiX = 203,  
    34.                 DpiY = 203,  
    35.                 PageWidth = 8f,  
    36.                 PageHeight = 12.2f,  
    37.                 MarginTop = 0.2f  
    38.             }) { }  
    39.   
    40.         public LocalReportHelper(String reportPath, GraphDeviceInfo deviceInfo) {  
    41.             this._bmpDPI = 96;  
    42.   
    43.             this.LocalReportPath = reportPath;  
    44.             this.ExportImageDeviceInfo = deviceInfo;  
    45.             this.LocalReportInstance = new LocalReport() { ReportPath = reportPath };  
    46.             this.LocalReportInstance.SubreportProcessing += new SubreportProcessingEventHandler(LocalReportInstance_SubreportProcessing);  
    47.         }  
    48.   
    49.         private void LocalReportInstance_SubreportProcessing(object sender, SubreportProcessingEventArgs e) {  
    50.             foreach (DataTable dt in this._ds.Tables) {  
    51.                 e.DataSources.Add(new ReportDataSource(dt.TableName, dt));  
    52.             }  
    53.         }  
    54.   
    55.         public void Dispose() {  
    56.             this.ExportImageDeviceInfo = null;  
    57.             this.LocalReportInstance = null;  
    58.             this.LocalReportPath = null;  
    59.   
    60.             this._ds = null;  
    61.         }  
    62.   
    63.         public void AddReportParameter(string paramName, string value) {  
    64.             this.LocalReportInstance.SetParameters(new ReportParameter(paramName, value));  
    65.         }  
    66.  
    67.         #region Export hang title image by reporting services  
    68.   
    69.         private void AddWashIcones() {  
    70.             this.LocalReportInstance.EnableExternalImages = true;  
    71.             this.LocalReportInstance.SetParameters(new ReportParameter("AppPath", Application.StartupPath));  
    72.         }  
    73.   
    74.         private void AddBarcodesAssembly() {  
    75.             this.LocalReportInstance.AddTrustedCodeModuleInCurrentAppDomain(ConfigurationManager.AppSettings["BarcodesAssembly"]);  
    76.         }  
    77.   
    78.         private Stream CreateStreamCallBack(string name, string fileNameExtension, Encoding encoding, string mimeType, bool willSeek) {  
    79.             string tempFolderPath = string.Concat(Environment.GetEnvironmentVariable("TEMP"), "/");  
    80.             this._stream = new FileStream(string.Concat(tempFolderPath, name, ".", fileNameExtension), FileMode.Create);  
    81.             return this._stream;  
    82.         }  
    83.         private void Export() {  
    84.             if (string.IsNullOrEmpty(this.LocalReportPath) ||  
    85.                 this.LocalReportInstance == null ||  
    86.                 this.ExportImageDeviceInfo == null) {  
    87.                 throw new InvalidExpressionException("Invalid parameters");  
    88.             }  
    89.             if (this.PrintTypeNO >= -1 || this.PrintTypeNO == -3) {  
    90.                 this.AddBarcodesAssembly();  
    91.                 if (this.PrintTypeNO >= 0) {  
    92.                     this.AddWashIcones();  
    93.                 }  
    94.             }  
    95.             if (this.PrintTypeNO >= 0) {  
    96.                 this.LocalReportInstance.DataSources.Clear();  
    97.                 foreach (DataTable dt in this._ds.Tables) {  
    98.                     this.LocalReportInstance.DataSources.Add(new ReportDataSource(dt.TableName, dt));  
    99.                 }  
    100.             }  
    101.             this.LocalReportInstance.Refresh();  
    102.   
    103.             if (this._stream != null) {  
    104.                 this._stream.Close();  
    105.                 this._stream = null;  
    106.             }  
    107.             Warning[] warnings;  
    108.             this.LocalReportInstance.Render(  
    109.                 "Image",  
    110.                 this.ExportImageDeviceInfo.ToString(),  
    111.                 PageCountMode.Actual,  
    112.                 CreateStreamCallBack,  
    113.                 out warnings);  
    114.             this._stream.Position = 0;  
    115.         }  
    116.         private void SaveLog() {  
    117.             using (Bitmap image = (Bitmap)Image.FromStream(this._stream)) {  
    118.                 image.SetResolution(96, 96);  
    119.                 using (MemoryStream ms = new MemoryStream()) {  
    120.                     image.Save(ms, ImageFormat.Jpeg);  
    121.                     this.PrintLogInformation.BarcodeImage = ms.ToArray();  
    122.                 }  
    123.             }  
    124.             LogHelper.AddLog(this.PrintLogInformation);  
    125.             if (this._stream != null) {  
    126.                 this._stream.Close();  
    127.                 this._stream = null;  
    128.             }  
    129.         }  
    130.  
    131.         #endregion  
    132.  
    133.         #region Windows driver print  
    134.   
    135.         private void PrintPage(object sender, PrintPageEventArgs ev) {  
    136.             Bitmap bmp = (Bitmap)Image.FromStream(this._stream);  
    137.             bmp.SetResolution(this._bmpDPI, this._bmpDPI);  
    138.             ev.Graphics.DrawImage(bmp, 0, 0);  
    139.             ev.HasMorePages = false;  
    140.         }  
    141.         /// <summary>  
    142.         /// Print by windows driver  
    143.         /// </summary>  
    144.         /// <param name="printerSettings">.net framework PrinterSettings class, including some printer information</param>  
    145.         /// <param name="bmpDPI">the bitmap image resoluation, dots per inch</param>  
    146.         public void WindowsDriverPrint(PrinterSettings printerSettings, int bmpDPI, DataSet ds) {  
    147.             this._ds = ds;  
    148.             this.Export();  
    149.             if (this._stream == null) {  
    150.                 return;  
    151.             }  
    152.             this._bmpDPI = bmpDPI;  
    153.   
    154.             PrintDocument printDoc = new PrintDocument();  
    155.             printDoc.DocumentName = "条码打印";  
    156.             printDoc.PrinterSettings = printerSettings;  
    157.             printDoc.PrintController = new StandardPrintController();  
    158.             if (!printDoc.PrinterSettings.IsValid) {  
    159.                 if (this._stream != null) {  
    160.                     this._stream.Close();  
    161.                     this._stream = null;  
    162.                 }  
    163.                 MessageBox.Show("Printer found errors, Please contact your administrators!", "Print Error");  
    164.                 return;  
    165.             }  
    166.             printDoc.PrintPage += new PrintPageEventHandler(PrintPage);  
    167.             printDoc.Print();  
    168.             this.SaveLog();  
    169.         }  
    170.  
    171.         #endregion  
    172.  
    173.         #region Original print  
    174.   
    175.         /// <summary>  
    176.         /// Send the file to the printer or use the printer command  
    177.         /// </summary>  
    178.         /// <param name="deviceType">The port(LPT,COM,DRV) which the device connecting</param>  
    179.         /// <param name="copies">Total number for print</param>  
    180.         /// <param name="ds">The report datasource</param>  
    181.         /// <param name="printParam">Print parameters</param>  
    182.         /// <param name="printLanguage">The built-in printer programming language, you can choose EPL or ZPL</param>  
    183.         public void OriginalPrint(DeviceType deviceType,  
    184.             DataSet ds,  
    185.             int copies = 1,  
    186.             string printParam = null,  
    187.             ProgrammingLanguage printLanguage = ProgrammingLanguage.ZPL) {  
    188.             this._ds = ds;  
    189.             this.Export();  
    190.             if (this._stream == null) {  
    191.                 return;  
    192.             }  
    193.             int port = 1;  
    194.             int.TryParse(printParam, out port);  
    195.             int length = (int)this._stream.Length;  
    196.             byte[] bytes = new byte[length];  
    197.             this._stream.Read(bytes, 0, length);  
    198.             ZebraPrintHelper.Copies = copies;  
    199.             ZebraPrintHelper.PrinterType = deviceType;  
    200.             ZebraPrintHelper.PrinterName = printParam;  
    201.             ZebraPrintHelper.Port = port;  
    202.             ZebraPrintHelper.PrinterProgrammingLanguage = printLanguage;  
    203.             ZebraPrintHelper.PrintGraphics(bytes);  
    204.             this.SaveLog();  
    205.         }  
    206.  
    207.         #endregion  
    208.   
    209.     }  
    210. }  



     


     

  • 相关阅读:
    50个提高PHP程序运行效率的方法
    虚拟主机FTP上传文件为什么要用二进制上传
    Status Bar 总结
    TableView 总结
    阿里Java开发手册(泰山版)个人记录
    下载excel模板
    微信公众号-发送模板消息
    ffmpeg获取视频时长
    微信公众号授权
    根据word模板生成word、转换成pdf、打成war包
  • 原文地址:https://www.cnblogs.com/Alex80/p/4530697.html
Copyright © 2011-2022 走看看