在批量打印商品标签时一般都要加上条码或图片,而这类应用大多是使用斑马打印机,所以我也遇到了怎么打印的问题。
一种办法是用标签设计软件做好模板,在标签设计软件中打印,这种办法不用写代码,但对我来说觉得不能接受,所以尝试代码解决问题。
网上搜索一番,找不到什么资料,基本都是说发送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 {
-
-
-
- public static class ZebraPrintHelper {
-
- #region 定义私有字段
-
-
-
- private static object SyncRoot = new object();
-
-
-
- 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; }
-
-
-
- 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() {
-
-
- 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() {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 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,
- TcpPrinterDPI,
- (int)(TcpLabelMaxHeightCM / 2.54f * TcpPrinterDPI),
- Copies,
- RowRealBytesCount,
- GraphHeight,
- 0,
- 0,
- textHex
- );
- return Encoding.UTF8.GetBytes(text);
- }
- #endregion
-
- #region 获取单色位图数据
-
-
-
-
-
- public static Bitmap ConvertToGrayscale(Bitmap pimage) {
- Bitmap source = null;
-
-
- 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;
- }
-
-
- BitmapData sourceData = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
-
-
- int imageSize = sourceData.Stride * sourceData.Height;
- byte[] sourceBuffer = new byte[imageSize];
- Marshal.Copy(sourceData.Scan0, sourceBuffer, 0, imageSize);
-
-
- source.UnlockBits(sourceData);
-
-
- Bitmap destination = new Bitmap(source.Width, source.Height, PixelFormat.Format1bppIndexed);
-
-
- BitmapData destinationData = destination.LockBits(new Rectangle(0, 0, destination.Width, destination.Height), ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed);
-
-
- 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;
-
-
- for (int y = 0; y < height; y++) {
- sourceIndex = y * sourceData.Stride;
- destinationIndex = y * destinationData.Stride;
- destinationValue = 0;
- pixelValue = 128;
-
-
- for (int x = 0; x < width; x++) {
-
- 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;
- }
- }
-
-
- Marshal.Copy(destinationBuffer, 0, destinationData.Scan0, imageSize);
-
-
- destination.UnlockBits(destinationData);
-
-
- if (source != pimage) {
- source.Dispose();
- }
-
-
- return destination;
- }
-
-
-
-
- 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 = 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) {
-
- 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 {
-
|
请发表评论