本案例已应用到项目中,做过相测试,可以保证打印稳定性。

本次使用打印机型号是ZDesigner ZD888-203dpi ZPL 需要安装斑马打印机相关驱动。本款打印机使用的USB口通讯,打印时通过上位机先绘制打印内容图像,转二进制写比特流的方式,再调用打印机专有指令发送给打印机进行打印。

需要用到的库:打印管理库函数winspool.Drv,这是个打印机底层驱动的包,windows底层API的调用库User32.dll,调用条码所需的库,这里选谷歌开源的zxing库.

1、结构和API声明

这里网上有现成的案例,这里不做多解释,了解一下即可。
StartDocPrinter 通知假脱机打印程序将在假脱机上打印一个文档
StartPagePrinter 通知假脱机打印程序将在给定打印机上打印一页
WritePrinter 通知假脱机打印程序应向给定的打印机写指定的数据
EndDocPrinter 终止给定打印机的一个打印作业
EndPagePrinter 指示一页的结束和下一页的开始
OpenPrinter 检取一个标识特定打印机或打印服务器的句柄并打开
ClosePrinter 关闭给定的打印机对象

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]public class DOCINFOA{[MarshalAs(UnmanagedType.LPStr)]public string pDocName;[MarshalAs(UnmanagedType.LPStr)]public string pOutputFile;[MarshalAs(UnmanagedType.LPStr)]public string pDataType;}[DllImport("winspool.Drv", EntryPoint = "OpenPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]public static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter, IntPtr pd);[DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]public static extern bool ClosePrinter(IntPtr hPrinter);[DllImport("winspool.Drv", EntryPoint = "StartDocPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]public static extern bool StartDocPrinter(IntPtr hPrinter, Int32 level, [In, MarshalAs(UnmanagedType.LPStruct)] DOCINFOA di);[DllImport("winspool.Drv", EntryPoint = "EndDocPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]public static extern bool EndDocPrinter(IntPtr hPrinter);[DllImport("winspool.Drv", EntryPoint = "StartPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]public static extern bool StartPagePrinter(IntPtr hPrinter);[DllImport("winspool.Drv", EntryPoint = "EndPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]public static extern bool EndPagePrinter(IntPtr hPrinter);[DllImport("winspool.Drv", EntryPoint = "WritePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, out Int32 dwWritten);

2、图像处理

把图像转换成斑马打印机的ZPL命令,这里也是参考网上已有代码类。

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;namespace ZebraPrintApplication
{/// <summary>/// 斑马工具类,把图像转换成斑马打印机的命令/// </summary>public class ZebraUnity{#region 定义私有字段/// <summary>/// 线程锁,防止多线程调用。/// </summary>private static object SyncRoot = new object();/// <summary>/// ZPL压缩字典/// </summary>private static List<KeyValuePair<char, int>> compressDictionary = new List<KeyValuePair<char, int>>();#endregion#region 构造方法static ZebraUnity(){InitCompressCode();}#endregion#region 定义属性/// <summary>/// 图像的二进制数据/// </summary>public static byte[] GraphBuffer { get; set; }/// <summary>/// 图像的宽度/// </summary>private static int GraphWidth { get; set; }/// <summary>/// 图像的高度/// </summary>private static int GraphHeight { get; set; }private static int RowSize{get{return (((GraphWidth) + 31) >> 5) << 2;}}/// <summary>/// 每行的字节数/// </summary>private static int RowRealBytesCount{get{if ((GraphWidth % 8) > 0){return GraphWidth / 8 + 1;}else{return GraphWidth / 8;}}}#endregion#region 位图转斑马指令字符串/// <summary>/// 位图转斑马指令字符串/// </summary>/// <param name="bitmap">位图数据</param>/// <param name="totalBytes">总共的字节数</param>/// <param name="rowBytes">每行的字节数</param>/// <returns>斑马ZPL 2命令</returns>public static string BmpToZpl(byte[] bitmap, out int totalBytes, out int rowBytes){try{GraphBuffer = bitmap;byte[] bmpData = getBitmapData();string textHex = BitConverter.ToString(bmpData).Replace("-", string.Empty);string textBitmap = CompressLZ77(textHex);totalBytes = GraphHeight * RowRealBytesCount;rowBytes = RowRealBytesCount;return textBitmap;}catch (Exception ex){throw ex;}}/// <summary>/// 位图转ZPL指令/// </summary>/// <param name="bitmap">位图</param>/// <param name="totalBytes">返回参数总共字节数</param>/// <param name="rowBytes">返回参数每行的字节数</param>/// <returns>ZPL命令</returns>public static string BmpToZpl(Image bitmap, out int totalBytes, out int rowBytes){using (MemoryStream stream = new MemoryStream()){bitmap.Save(stream, ImageFormat.Bmp);return BmpToZpl(stream.ToArray(), out totalBytes, out rowBytes);}}/// <summary>/// 根据图片生成图片的ASCII 十六进制/// </summary>/// <param name="sourceBmp">原始图片</param>/// <param name="totalBytes">总共字节数</param>/// <param name="rowBytes">每行的字节数</param>/// <returns>ASCII 十六进制</returns>public static string BitmapToHex(Image sourceBmp, out int totalBytes, out int rowBytes){// 转成单色图Bitmap grayBmp = ConvertToGrayscale(sourceBmp as Bitmap);// 锁定位图数据    Rectangle rect = new Rectangle(0, 0, grayBmp.Width, grayBmp.Height);System.Drawing.Imaging.BitmapData bmpData = grayBmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, grayBmp.PixelFormat);// 获取位图数据第一行的起始地址     IntPtr ptr = bmpData.Scan0;// 定义数组以存放位图的字节流数据      // 处理像素宽对应的字节数,如不为8的倍数,则对最后一个字节补0    int width = (int)Math.Ceiling(grayBmp.Width / 8.0);// 获取位图实际的字节宽,这个值因为要考虑4的倍数关系,可能大于width  int stride = Math.Abs(bmpData.Stride);// 计算位图数据实际所占的字节数,并定义数组      int bitmapDataLength = stride * grayBmp.Height;byte[] ImgData = new byte[bitmapDataLength];// 从位图文件复制图像数据到数组,从实际图像数据的第一行开始;因ptr指针而无需再考虑行倒序存储的处理          System.Runtime.InteropServices.Marshal.Copy(ptr, ImgData, 0, bitmapDataLength);// 计算异或操作数,以处理包含图像数据但又有补0操作的那个字节         byte mask = 0xFF;// 计算这个字节补0的个数       //int offset = 8 * width - grayBmp.Width;int offset = 8 - (grayBmp.Width % 8);//offset %= 8;offset = offset % 8;// 按补0个数对0xFF做相应位数的左移位操作           mask <<= (byte)offset;// 图像反色处理        for (int j = 0; j < grayBmp.Height; j++){for (int i = 0; i < stride; i++){if (i < width - 1) //无补0的图像数据{ImgData[j * stride + i] ^= 0xFF;}else if (i == width - 1) //有像素的最后一个字节,可能有补0   {ImgData[j * stride + i] ^= mask;}else  //为满足行字节宽为4的倍数而最后补的字节        {//ImgData[j * stride + i] = 0x00;ImgData[j * stride + i] ^= 0x00;}}}// 将位图数据转换为16进制的ASCII字符          string zplString = BitConverter.ToString(ImgData);zplString = CompressLZ77(zplString.Replace("-", string.Empty));totalBytes = bitmapDataLength;rowBytes = stride;return zplString;}#endregion#region 获取单色位图数据/// <summary>/// 获取单色位图数据/// </summary>/// <param name="pimage"></param>/// <returns></returns>public static Bitmap ConvertToGrayscale(Bitmap pimage){Bitmap source = null;// If original bitmap is not already in 32 BPP, ARGB format, then convertif (pimage.PixelFormat != PixelFormat.Format32bppArgb){source = new Bitmap(pimage.Width, pimage.Height, PixelFormat.Format32bppArgb);source.SetResolution(pimage.HorizontalResolution, pimage.VerticalResolution);using (Graphics g = Graphics.FromImage(source)){g.DrawImageUnscaled(pimage, 0, 0);}}else{source = pimage;}// Lock source bitmap in memoryBitmapData sourceData = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);// Copy image data to binary arrayint imageSize = sourceData.Stride * sourceData.Height;byte[] sourceBuffer = new byte[imageSize];Marshal.Copy(sourceData.Scan0, sourceBuffer, 0, imageSize);// Unlock source bitmapsource.UnlockBits(sourceData);// Create destination bitmapBitmap destination = new Bitmap(source.Width, source.Height, PixelFormat.Format1bppIndexed);// Lock destination bitmap in memoryBitmapData destinationData = destination.LockBits(new Rectangle(0, 0, destination.Width, destination.Height), ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed);// Create destination bufferimageSize = destinationData.Stride * destinationData.Height;byte[] destinationBuffer = new byte[imageSize];int sourceIndex = 0;int destinationIndex = 0;int pixelTotal = 0;byte destinationValue = 0;int pixelValue = 128;int height = source.Height;int width = source.Width;int threshold = 500;// Iterate linesfor (int y = 0; y < height; y++){sourceIndex = y * sourceData.Stride;destinationIndex = y * destinationData.Stride;destinationValue = 0;pixelValue = 128;// Iterate pixelsfor (int x = 0; x < width; x++){// Compute pixel brightness (i.e. total of Red, Green, and Blue values)pixelTotal = sourceBuffer[sourceIndex + 1] + sourceBuffer[sourceIndex + 2] + sourceBuffer[sourceIndex + 3];if (pixelTotal > threshold){destinationValue += (byte)pixelValue;}if (pixelValue == 1){destinationBuffer[destinationIndex] = destinationValue;destinationIndex++;destinationValue = 0;pixelValue = 128;}else{pixelValue >>= 1;}sourceIndex += 4;}if (pixelValue != 128){destinationBuffer[destinationIndex] = destinationValue;}}// Copy binary image data to destination bitmapMarshal.Copy(destinationBuffer, 0, destinationData.Scan0, imageSize);// Unlock destination bitmapdestination.UnlockBits(destinationData);// Dispose of source if not originally supplied bitmapif (source != pimage){source.Dispose();}// Returnreturn destination;}/// <summary>/// 获取单色位图数据(1bpp),不含文件头、信息头、调色板三类数据。/// </summary>/// <returns></returns>private static byte[] getBitmapData(){MemoryStream srcStream = new MemoryStream();MemoryStream dstStream = new MemoryStream();Bitmap srcBmp = null;Bitmap dstBmp = null;byte[] srcBuffer = null;byte[] dstBuffer = null;byte[] result = null;try{srcStream = new MemoryStream(GraphBuffer);srcBmp = Bitmap.FromStream(srcStream) as Bitmap;srcBuffer = srcStream.ToArray();GraphWidth = srcBmp.Width;GraphHeight = srcBmp.Height;//dstBmp = srcBmp.Clone(new Rectangle(0, 0, srcBmp.Width, srcBmp.Height), PixelFormat.Format1bppIndexed);dstBmp = ConvertToGrayscale(srcBmp);dstBmp.Save(dstStream, ImageFormat.Bmp);dstBuffer = dstStream.ToArray();result = dstBuffer;int bfOffBits = BitConverter.ToInt32(dstBuffer, 10);result = new byte[GraphHeight * RowRealBytesCount];读取时需要反向读取每行字节实现上下翻转的效果,打印机打印顺序需要这样读取。for (int i = 0; i < GraphHeight; i++){int sindex = bfOffBits + (GraphHeight - 1 - i) * RowSize;int dindex = i * RowRealBytesCount;Array.Copy(dstBuffer, sindex, result, dindex, RowRealBytesCount);}for (int i = 0; i < result.Length; i++){result[i] ^= 0xFF;}}catch (Exception ex){throw new Exception(ex.Message, ex);}finally{if (srcStream != null){srcStream.Dispose();srcStream = null;}if (dstStream != null){dstStream.Dispose();dstStream = null;}if (srcBmp != null){srcBmp.Dispose();srcBmp = null;}if (dstBmp != null){dstBmp.Dispose();dstBmp = null;}}return result;}#endregion#region LZ77图像字节流压缩方法public static string CompressLZ77(string text){//将转成16进制的文本进行压缩string result = string.Empty;char[] arrChar = text.ToCharArray();int count = 1;for (int i = 1; i < text.Length; i++){if (arrChar[i - 1] == arrChar[i]){count++;}else{result += convertNumber(count) + arrChar[i - 1];count = 1;}if (i == text.Length - 1){result += convertNumber(count) + arrChar[i];}}return result;}private static string DecompressLZ77(string text){string result = string.Empty;char[] arrChar = text.ToCharArray();int count = 0;for (int i = 0; i < arrChar.Length; i++){if (isHexChar(arrChar[i])){//十六进制值result += new string(arrChar[i], count == 0 ? 1 : count);count = 0;}else{//压缩码int value = GetCompressValue(arrChar[i]);count += value;}}return result;}private static int GetCompressValue(char c){int result = 0;for (int i = 0; i < compressDictionary.Count; i++){if (c == compressDictionary[i].Key){result = compressDictionary[i].Value;}}return result;}private static bool isHexChar(char c){return c > 47 && c < 58 || c > 64 && c < 71 || c > 96 && c < 103;}private static string convertNumber(int count){//将连续的数字转换成LZ77压缩代码,如000可用I0表示。string result = string.Empty;if (count > 1){while (count > 0){for (int i = compressDictionary.Count - 1; i >= 0; i--){if (count >= compressDictionary[i].Value){result += compressDictionary[i].Key;count -= compressDictionary[i].Value;break;}}}}return result;}private static void InitCompressCode(){//G H I J K L M N O P Q R S T U V W X Y        对应1,2,3,4……18,19。//g h i j k l m n o p q r s t u v w x y z      对应20,40,60,80……340,360,380,400。            for (int i = 0; i < 19; i++){compressDictionary.Add(new KeyValuePair<char, int>(Convert.ToChar(71 + i), i + 1));}for (int i = 0; i < 20; i++){compressDictionary.Add(new KeyValuePair<char, int>(Convert.ToChar(103 + i), (i + 1) * 20));}}#endregion}
}

3、数据发送及类型转换

 public bool SendStringToPrinter(string szPrinterName, string szString){try{IntPtr pBytes;Int32 dwCount;// 获取字符串长度  dwCount = szString.Length;// 将字符串复制到非托管 COM 任务分配的内存非托管内存块,并转换为 ANSI 文本pBytes = Marshal.StringToCoTaskMemAnsi(szString);// 将已转换的 ANSI 字符串发送到打印机bool res = SendBytesToPrinter(szPrinterName, pBytes, dwCount);// 释放先前分配的非托管内存Marshal.FreeCoTaskMem(pBytes);return res;}catch{//WriteLog(ex.Message);return false;}}public bool SendBytesToPrinter(string szPrinterName, IntPtr pBytes, Int32 dwCount){Int32 dwError = 0, dwWritten = 0;IntPtr hPrinter = new IntPtr(0);DOCINFOA di = new DOCINFOA();bool bSuccess = false; // 返回标志,默认失败di.pDocName = "My Zebra Print File";di.pDataType = "RAW";// 打开打印机if (OpenPrinter(szPrinterName.Normalize(), out hPrinter, IntPtr.Zero)){// 开始文档if (StartDocPrinter(hPrinter, 1, di)){// 开始页if (StartPagePrinter(hPrinter)){// 写比特流bSuccess = WritePrinter(hPrinter, pBytes, dwCount, out dwWritten);EndPagePrinter(hPrinter);}EndDocPrinter(hPrinter);}ClosePrinter(hPrinter);}// 如果不成功,写错误原因if (bSuccess == false){dwError = Marshal.GetLastWin32Error();}return bSuccess;}public string BitmapToHex(Image sourceBmp, out int totalBytes, out int rowBytes){//Bitmap map = new Bitmap(sourceBmp); 等同于sourceBmp as Bitmap// 转成单色图Bitmap grayBmp = ZebraUnity.ConvertToGrayscale(sourceBmp as Bitmap);// 锁定位图数据    Rectangle rect = new Rectangle(0, 0, grayBmp.Width, grayBmp.Height);BitmapData bmpData = grayBmp.LockBits(rect, ImageLockMode.ReadWrite, grayBmp.PixelFormat);// 获取位图数据第一行的起始地址     IntPtr ptr = bmpData.Scan0;// 定义数组以存放位图的字节流数据      // 处理像素宽对应的字节数,如不为8的倍数,则对最后一个字节补0    int width = (int)Math.Ceiling(grayBmp.Width / 8.0);// 获取位图实际的字节宽,这个值因为要考虑4的倍数关系,可能大于width  int stride = Math.Abs(bmpData.Stride);// 计算位图数据实际所占的字节数,并定义数组      int bitmapDataLength = stride * grayBmp.Height;byte[] ImgData = new byte[bitmapDataLength];// 从位图文件复制图像数据到数组,从实际图像数据的第一行开始;因ptr指针而无需再考虑行倒序存储的处理          Marshal.Copy(ptr, ImgData, 0, bitmapDataLength);// 计算异或操作数,以处理包含图像数据但又有补0操作的那个字节         byte mask = 0xFF;// 计算这个字节补0的个数       //int offset = 8 * width - grayBmp.Width;int offset = 8 - (grayBmp.Width % 8);//offset %= 8;offset = offset % 8;// 按补0个数对0xFF做相应位数的左移位操作           mask <<= (byte)offset;// 图像反色处理        for (int j = 0; j < grayBmp.Height; j++){for (int i = 0; i < stride; i++){if (i < width - 1) //无补0的图像数据{ImgData[j * stride + i] ^= 0xFF;}else if (i == width - 1) //有像素的最后一个字节,可能有补0   {ImgData[j * stride + i] ^= mask;}else  //为满足行字节宽为4的倍数而最后补的字节        {ImgData[j * stride + i] ^= 0x00;}}}// 将位图数据转换为16进制的ASCII字符          string zplString = BitConverter.ToString(ImgData);zplString = ZebraUnity.CompressLZ77(zplString.Replace("-", string.Empty));totalBytes = bitmapDataLength;rowBytes = stride;return zplString;}

4、建立UI界面

这里可以控制二维码的大小位置,以及二维码的类型。

5、实现绘制图像及打印方法

        private void button1_Click(object sender, EventArgs e){int total = 0;int row = 0;string hex = BitmapToHex(bitmap, out total, out row);string modecmd = "~DGR:ZLOGO.GRF," + total.ToString() + "," + row.ToString() + "," + hex;//将图片生成模板指令var printName = "ZDesigner ZD888-203dpi ZPL";if (textBox2.Text != ""){printName = textBox2.Text;}bool a = SendStringToPrinter(printName, modecmd);string cmd = "^XA^FO0,0^XGR:ZLOGO.GRF,1,1^FS^XZ";//调用该模板指令 ^FO是设置条码左上角的位置的,0,0代表完全不留边距.^FS表示换行bool b = SendStringToPrinter(printName, cmd);//发送调用模板指令if (a & b){MessageBox.Show("二维码打印成功","提示");}else{MessageBox.Show("二维码打印失败!", "警告");}}private void button2_Click(object sender, EventArgs e){//创建GraphicsGraphics graphics = Graphics.FromImage(bitmap);//呈现质量graphics.SmoothingMode = SmoothingMode.AntiAlias;//背景色graphics.Clear(Color.White);int codeSize = 300;string printContent = "";int printX = 140;int printY = 40;int CodeWidth = 100;int CodeHeigth = 100;try{codeSize = Convert.ToInt32(textBox1.Text);printX = Convert.ToInt32(textBox3X.Text);printY = Convert.ToInt32(textBox4Y.Text);CodeWidth = Convert.ToInt32(textBox3width.Text);CodeHeigth = Convert.ToInt32(textBox4heigth.Text);}catch{}//构造二维码写码器MultiFormatWriter mutiWriter = new MultiFormatWriter();ByteMatrix bm = null;if (comboBox1.Text=="Code39"){bm = mutiWriter.encode(InputtextBox.Text, BarcodeFormat.CODE_39, CodeWidth, CodeHeigth);}else if (comboBox1.Text == "QR_Code"){bm = mutiWriter.encode(InputtextBox.Text, BarcodeFormat.QR_CODE, CodeWidth, CodeHeigth);}else{try{bm = mutiWriter.encode(InputtextBox.Text, BarcodeFormat.EAN_13, CodeWidth, CodeHeigth);}catch{MessageBox.Show("请输入13为数字","警告");return;} }Bitmap img = bm.ToBitmap();string printtime = DateTime.Now.ToString("yyyy/MM/dd HH:mm");graphics.DrawString("日期时间:" + printtime, new Font("微软雅黑", 12, FontStyle.Bold), new SolidBrush(Color.Black), 0, 0 + codeSize);graphics.DrawString(printContent, new Font("微软雅黑", 12, FontStyle.Bold), new SolidBrush(Color.Black), 170, 188 + codeSize);graphics.DrawImage(img, printX, printY + codeSize, CodeWidth, CodeHeigth);//显示图形this.pictureBox1.Image = bitmap;}public bool SendStringToPrinter(string szPrinterName, string szString){try{IntPtr pBytes;Int32 dwCount;// 获取字符串长度  dwCount = szString.Length;// 将字符串复制到非托管 COM 任务分配的内存非托管内存块,并转换为 ANSI 文本pBytes = Marshal.StringToCoTaskMemAnsi(szString);// 将已转换的 ANSI 字符串发送到打印机bool res = SendBytesToPrinter(szPrinterName, pBytes, dwCount);// 释放先前分配的非托管内存Marshal.FreeCoTaskMem(pBytes);return res;}catch{return false;}}public bool SendBytesToPrinter(string szPrinterName, IntPtr pBytes, Int32 dwCount){Int32 dwError = 0, dwWritten = 0;IntPtr hPrinter = new IntPtr(0);DOCINFOA di = new DOCINFOA();bool bSuccess = false; // 返回标志,默认失败di.pDocName = "My Zebra Print File";di.pDataType = "RAW";// 打开打印机if (OpenPrinter(szPrinterName.Normalize(), out hPrinter, IntPtr.Zero)){// 开始文档if (StartDocPrinter(hPrinter, 1, di)){// 开始页if (StartPagePrinter(hPrinter)){// 写比特流bSuccess = WritePrinter(hPrinter, pBytes, dwCount, out dwWritten);EndPagePrinter(hPrinter);}EndDocPrinter(hPrinter);}ClosePrinter(hPrinter);}// 如果不成功,写错误原因if (bSuccess == false){dwError = Marshal.GetLastWin32Error();}return bSuccess;}public  string BitmapToHex(Image sourceBmp, out int totalBytes, out int rowBytes){//Bitmap map = new Bitmap(sourceBmp); 等同于sourceBmp as Bitmap// 转成单色图Bitmap grayBmp = ZebraUnity.ConvertToGrayscale(sourceBmp as Bitmap);// 锁定位图数据    Rectangle rect = new Rectangle(0, 0, grayBmp.Width, grayBmp.Height);BitmapData bmpData = grayBmp.LockBits(rect, ImageLockMode.ReadWrite, grayBmp.PixelFormat);// 获取位图数据第一行的起始地址     IntPtr ptr = bmpData.Scan0;// 定义数组以存放位图的字节流数据      // 处理像素宽对应的字节数,如不为8的倍数,则对最后一个字节补0    int width = (int)Math.Ceiling(grayBmp.Width / 8.0);// 获取位图实际的字节宽,这个值因为要考虑4的倍数关系,可能大于width  int stride = Math.Abs(bmpData.Stride);// 计算位图数据实际所占的字节数,并定义数组      int bitmapDataLength = stride * grayBmp.Height;byte[] ImgData = new byte[bitmapDataLength];// 从位图文件复制图像数据到数组,从实际图像数据的第一行开始;因ptr指针而无需再考虑行倒序存储的处理          Marshal.Copy(ptr, ImgData, 0, bitmapDataLength);// 计算异或操作数,以处理包含图像数据但又有补0操作的那个字节         byte mask = 0xFF;// 计算这个字节补0的个数       //int offset = 8 * width - grayBmp.Width;int offset = 8 - (grayBmp.Width % 8);//offset %= 8;offset = offset % 8;// 按补0个数对0xFF做相应位数的左移位操作           mask <<= (byte)offset;// 图像反色处理        for (int j = 0; j < grayBmp.Height; j++){for (int i = 0; i < stride; i++){if (i < width - 1) //无补0的图像数据{ImgData[j * stride + i] ^= 0xFF;}else if (i == width - 1) //有像素的最后一个字节,可能有补0   {ImgData[j * stride + i] ^= mask;}else  //为满足行字节宽为4的倍数而最后补的字节        {ImgData[j * stride + i] ^= 0x00;}}}// 将位图数据转换为16进制的ASCII字符          string zplString = BitConverter.ToString(ImgData);zplString = ZebraUnity.CompressLZ77(zplString.Replace("-", string.Empty));totalBytes = bitmapDataLength;rowBytes = stride;return zplString;}

6、图像显示及打印效果

Code39条码显示

QRCode二维码显示

EAN_13条码显示

条码打印效果:

C# 斑马打印机USB接口实现打印各种类型的码相关推荐

  1. 对接斑马打印机 usb模式+打印机共享模式

    对接斑马打印机 usb形式 Zebra.Sdk.Printer请使用低版本:2.14.1989 using System; using System.Collections.Generic; usin ...

  2. 发送ZPL指令到斑马打印机,并监控打印成功或者失败的状态信息

    Visual C# 入门 本文共分为两个部分: 第一部分:介绍如何与Zebar进行连接,把ZPL指令或者模板文件发送到斑马打印机进行打印. 第二部分:介绍如何接收Zebar进行打印之后如何得到斑马打印 ...

  3. 思科服务器连接无线打印机,经典解决方案 : 路由器直接连接打印机USB接口实现网络打印。...

    近看到很多人问怎么把打印机接到路由器上面做网络打印,一开始觉得这样子很不可思议.但问的人多了自己也就开始怀疑了.后来查阅了很多资料发现路由器的USB接口有两种一种是WCN-UFD技术(也就是快速网络设 ...

  4. 斑马打印机EPL2指令自动打印_配合扫描枪边扫边打

    在斑马便携式打印机中的语言大多是EPL2语言,当然很多机型支持的语言不止一种.在EPL2中可以是先一边扫描条码,一边把扫描到的数据打印出同一个条码出来.也可以扫描若干个条码然后打印出来,还可以设置每次 ...

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

    在批量打印商品标签时一般都要加上条码或图片,而这类应用大多是使用斑马打印机,所以我也遇到了怎么打印的问题. 一种办法是用标签设计软件做好模板,在标签设计软件中打印,这种办法不用写代码,但对我来说觉得不 ...

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

    在批量打印商品标签时一般都要加上条码或图片,而这类应用大多是使用斑马打印机,所以我也遇到了怎么打印的问题. 一种办法是用标签设计软件做好模板,在标签设计软件中打印,这种办法不用写代码,但对我来说觉得不 ...

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

    原文地址:http://blog.csdn.net/ldljlq/article/details/7338772 在批量打印商品标签时一般都要加上条码或图片,而这类应用大多是使用斑马打印机,所以我也遇 ...

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

    在批量打印商品标签时一般都要加上条码或图片,而这类应用大多是使用斑马打印机,所以我也遇到了怎么打印的问题. 一种办法是用标签设计软件做好模板,在标签设计软件中打印,这种办法不用写代码,但对我来说觉得不 ...

  9. 用VB开发USB接口POS打印机进行打印和弹钱箱

    用VB开发USB接口POS打印机进行打印和弹钱箱 原来并口打印机编写代码: Open "Lpt1" For Output As #1 Print #1, "打印的内容&q ...

  10. wincc脚本打印斑马打印机条码,斑马打印机接口

    服务介绍 远程调用斑马打印机打印标签!,例如wincc软件或者其他第三方软件 部署需要满足下面条件: 服务安装 双击打开 zebra_webapi.exe 初次会在根目录创建配置文件config.to ...

最新文章

  1. OSX操作技巧:快速锁定系统(类似Windows+L)
  2. php include传参数,浅谈php中include文件变量作用域
  3. mfc exe 在繁体系统 乱码_成都市招标文件编制及备案系统使用技巧问答
  4. Androud 如何有效减少重复代码
  5. java开源笔记软件下载_开发常用软件笔记 - ZhaoQian's Blog - OSCHINA - 中文开源技术交流社区...
  6. visualstudio2019 的报表技术rdlc在windows10上出现乱码的问题解决方法
  7. webservice发请求没有不成功也不返回什么异常_RPC是什么,看完你就知道了
  8. C/C++笔试经典程序(二)
  9. 各个 Maven仓库 镜像(包括国内)
  10. web制作、开发人员需知的Web缓存知识
  11. 网页打开html无法编辑,电脑浏览器网页无法输入文字该怎么办?
  12. 信息系统项目管理师快速记忆口诀
  13. DDR 参数 内存延迟时序“CL-tRCD-tRP-tRAS”
  14. 2020年408真题_2020年港澳台联考真题——化学!
  15. win10总是更新失败
  16. 通过构造方法创建一个正方形类
  17. windows实用键盘快捷键
  18. python----小计买书问题
  19. C语言 switch多分支语句实现根据等级划分分数段
  20. 男,40岁,总监,失业:职场中年人,愿你终能体面的离开

热门文章

  1. 串口收数数码管显示(串口带协议带校验)
  2. typecho插件编写教程6 - 调用接口
  3. BFS(广度优先算法)
  4. Python-爬虫抓取视频
  5. mac vs 返回上一步_mac 后退一步 快捷键
  6. windows下db2创建数据库
  7. 高清录播系统与流媒体服务器,校园高清一体式高清录播系统教学录播跟踪网络直播...
  8. oracle里round函数补0,Oracle的Round函数
  9. Java保留2位小数 JS保留2位小数 Java截取2位小数 Math.round((1.0/3)*100)/100.0
  10. 计算机网络教程网线制作,网线水晶头制作过程详解(视频+图文教程)