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 plain copy

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

调用例子代码:

[csharp] view plain copy

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

LocalReportHelper类代码:

[csharp] view plain copy

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

时间: 2024-10-24 06:03:38

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

【求助】关于.NET(C#)调用斑马打印机(ZDesigner GK888t (EPL))换页时退纸的问题

有解决过类似问题的大神请留步,救救我吧.-------分割-------最近在做一个快递标签打印系统,使用.NET(C#)调用斑马打印机[ZDesigner GK888t (EPL)]进行打印,程序实现的是连续打印,但实际打印机却是打一张,停一下,退一点纸,然后下一张,再停一下,...依此类推.因为是大批量的标签,所以这个间隔不能忍受,尝试了各种打印机属性和选项的设置都没有用.百度看到有人说换成海鸥的驱动,测试后果然不再中间停顿,但业务方不是很接受这个方案(机器较多,换驱动的工作量也蛮大的),没

.net 调用小票打印机 打印票据

public class PrintInvoice     { #region 01.获得打印机1获得吧台打印机2获得后厨打印机 /// <summary> /// 获得打印机1获得吧台打印机2获得后厨打印机 /// </summary> public TcpClient GetPrint(int n = 1) { var client = new System.Net.Sockets.TcpClient(); var bll = new PrintAndPlaceBll(); v

斑马打印机打印不出来字怎么解决

在条码打印软件中制作标签的时候,有的时候标签内容比较多,可能不注意就在标签上或者数据源中添加了一个空对象,也没预览,就直接连接斑马打印机进行打印了.最后发现,点击打印之后,斑马打印机没反应,咨询是怎么回来,今天我们一起来看下有关条码打印软件连接斑马打印机打印不出来字的解决方法.1.打开中琅条码打印软件,在软件中设置一下纸张和标签的尺寸.2.点击软件左侧的"实心A"按钮,在画布上绘制一个普通文本对象,双击普通文本,在图形属性-数据源中,点击"修改"按钮,数据对象类型选

基于C#在WPF中使用斑马打印机进行打印【转】

原文链接:http://ju.outofmemory.cn/entry/132476 最近在项目中接手了一个比较有挑战性的模块——用斑马打印机将需要打印的内容打印出来.苦苦折腾了两天,总算有所收获,就发到网上来骗骗分数-_-|| 项目中使用的打印机型号为GX430t的打印机,接手的时候,自己对于打印机这块儿是眼前一抹黑,啥都不知道.没办法一步步来. 首先尝试使用WPF中的PrintDialog里面的PrintVisual和PrintDocument方法,打印机是一点反应都没有,最后得到的结论是:

基于C#在WPF中使用斑马打印机进行打印

最近在项目中接手了一个比较有挑战性的模块——用斑马打印机将需要打印的内容打印出来.苦苦折腾了两天,总算有所收获,就发到网上来骗骗分数-_-|| 项目中使用的打印机型号为GX430t的打印机,接手的时候,自己对于打印机这块儿是眼前一抹黑,啥都不知道.没办法一步步来. 首先尝试使用WPF中的PrintDialog里面的PrintVisual和PrintDocument方法,打印机是一点反应都没有,最后得到的结论是:斑马打印机不支持MS的XPS文档格式,所以使用WPF来排版后进行驱动打印就不要想了,不

斑马打印机客户端GET和POST,以及后端两种打印方式。

背景环境:打印机安装在客户端外网.当用户登录时,通过ajax取服务器数据,返回打印机命令,然后客户端通过JS发送给斑马打印机. 1.使用Get方式打印 1.1 前端页面js代码 jQuery(function () { $("#btnRePrint").click(function () { //var cartonId = "450002241530221"; var cartonId = ""; if ($("input[name=

Java jacob调用打印机打印word文档

前面说了Java如何生成复杂的Word文档,今年记录下Java如何调用打印机打印word文档. 起初用的是自带的PrintJob,但是系统提供的打印机制比不成熟完整.网上的代码也是千篇一律,在我的打印设备Canon iR2525/2530 UFRII LT上,我能获取到打印机的各属性,当前任务数.但是打印机没反应. 可参考这两篇文章: http://www.360doc.com/content/05/0916/11/332_12789.shtml http://www.ibm.com/devel

Winform将DataGridView导出Excel,调用打印机打印DataGridView

DataGridView导出Excel (这个需要 Microsoft.Office.Interop.Excel.dll  在网上下载就可以) public static void ExportExcel(string fileName, DataGridView myDGV) { string saveFileName = ""; SaveFileDialog saveDialog = new SaveFileDialog(); saveDialog.DefaultExt = &qu

C# 调用打印机打印文件

C# 调用打印机打印文件,通常情况下,例如Word.Excel.PDF等可以使用一些对应的组件进行打印,另一个通用的方式是直接启用一个打印的进程进行打印.示例代码如下: using System.Diagnostics; string filePath = "文件路径"; string printer = "打印机"; ProcessStartInfo info = new ProcessStartInfo(); info.Arguments = "\&q