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

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

本次使用打印机型号是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 convert
            if (pimage.PixelFormat != PixelFormat.Format32bppArgb)
            {
                source = new Bitmap(pimage.Width, pimage.Height, PixelFormat.Format32bppArgb);
                source.SetResolution(pimage.HorizontalResolution, pimage.VerticalResolution);
                using (Graphics g = Graphics.FromImage(source))
                {
                    g.DrawImageUnscaled(pimage, 0, 0);
                }
            }
            else
            {
                source = pimage;
            }

            // Lock source bitmap in memory
            BitmapData sourceData = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

            // Copy image data to binary array
            int imageSize = sourceData.Stride * sourceData.Height;
            byte[] sourceBuffer = new byte[imageSize];
            Marshal.Copy(sourceData.Scan0, sourceBuffer, 0, imageSize);

            // Unlock source bitmap
            source.UnlockBits(sourceData);

            // Create destination bitmap
            Bitmap destination = new Bitmap(source.Width, source.Height, PixelFormat.Format1bppIndexed);

            // Lock destination bitmap in memory
            BitmapData destinationData = destination.LockBits(new Rectangle(0, 0, destination.Width, destination.Height), ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed);

            // Create destination buffer
            imageSize = destinationData.Stride * destinationData.Height;
            byte[] destinationBuffer = new byte[imageSize];

            int sourceIndex = 0;
            int destinationIndex = 0;
            int pixelTotal = 0;
            byte destinationValue = 0;
            int pixelValue = 128;
            int height = source.Height;
            int width = source.Width;
            int threshold = 500;

            // Iterate lines
            for (int y = 0; y < height; y++)
            {
                sourceIndex = y * sourceData.Stride;
                destinationIndex = y * destinationData.Stride;
                destinationValue = 0;
                pixelValue = 128;

                // Iterate pixels
                for (int x = 0; x < width; x++)
                {
                    // Compute pixel brightness (i.e. total of Red, Green, and Blue values)
                    pixelTotal = sourceBuffer[sourceIndex + 1] + sourceBuffer[sourceIndex + 2] + sourceBuffer[sourceIndex + 3];
                    if (pixelTotal > threshold)
                    {
                        destinationValue += (byte)pixelValue;
                    }
                    if (pixelValue == 1)
                    {
                        destinationBuffer[destinationIndex] = destinationValue;
                        destinationIndex++;
                        destinationValue = 0;
                        pixelValue = 128;
                    }
                    else
                    {
                        pixelValue >>= 1;
                    }
                    sourceIndex += 4;
                }
                if (pixelValue != 128)
                {
                    destinationBuffer[destinationIndex] = destinationValue;
                }
            }

            // Copy binary image data to destination bitmap
            Marshal.Copy(destinationBuffer, 0, destinationData.Scan0, imageSize);

            // Unlock destination bitmap
            destination.UnlockBits(destinationData);

            // Dispose of source if not originally supplied bitmap
            if (source != pimage)
            {
                source.Dispose();
            }

            // Return
            return destination;
        }
        /// <summary>
        /// 获取单色位图数据(1bpp),不含文件头、信息头、调色板三类数据。
        /// </summary>
        /// <returns></returns>
        private static byte[] getBitmapData()
        {
            MemoryStream srcStream = new MemoryStream();
            MemoryStream dstStream = new MemoryStream();
            Bitmap srcBmp = null;
            Bitmap dstBmp = null;
            byte[] srcBuffer = null;
            byte[] dstBuffer = null;
            byte[] result = null;
            try
            {
                srcStream = new MemoryStream(GraphBuffer);
                srcBmp = Bitmap.FromStream(srcStream) as Bitmap;
                srcBuffer = srcStream.ToArray();
                GraphWidth = srcBmp.Width;
                GraphHeight = srcBmp.Height;
                //dstBmp = srcBmp.Clone(new Rectangle(0, 0, srcBmp.Width, srcBmp.Height), PixelFormat.Format1bppIndexed);
                dstBmp = ConvertToGrayscale(srcBmp);
                dstBmp.Save(dstStream, ImageFormat.Bmp);
                dstBuffer = dstStream.ToArray();

                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)
        {
            //创建Graphics
            Graphics 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条码显示
在这里插入图片描述
条码打印效果:

在这里插入图片描述

  • 5
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
### 回答1: c是计算机科学中常用的编程语言之一。它最初由丹尼斯·里奇在20世纪70年代早期在贝尔实验室开发,用于开发操作系统。与其他编程语言相比,c具有高效、结构化和可移植的特点。 c语言具有简洁而直观的语法规则,易于学习和理解。因此,它成为了许多编程领域的首选语言,包括系统编程、嵌入式系统、驱动程序开发等等。c语言可以直接访问硬件和内存,同时提供了丰富的算法和数据结构库,为程序员提供了灵活的编程环境。 c语言具有高效的执行速度和小的内存占用,这使得它在资源有限的环境下仍然能够有效运行。与其他高级编程语言相比,c语言更接近底层,因此程序员有更多的控制权。这也意味着程序员需要更多的关注细节和错误检查,但也为他们提供了更多的灵活性和自由度。 c语言是许多其他编程语言的基础,例如C++、Java和Python。学习c语言不仅可以为其他编程语言的学习打下坚实的基础,还可以提高编程思维和解决问题的能力。在当今科技发展迅猛的时代,掌握c语言能够为从事计算机相关行业的人提供更广泛的就业机会。 总之,c语言在计算机科学中具有重要地位,是很多程序员入门的首选语言。它的高效性、结构化特点以及广泛的应用领域使其成为编程世界中的重要工具。希望这个回答能帮助你更好地了解c语言的重要性和优势。 ### 回答2: c是一种非常重要的编程语言。它由贝尔实验室的丹尼斯·里奇于20世纪70年代初开发。c语言以其高效性和灵活性而闻名,并成为许多其他编程语言的基础。 c语言具有简洁的语法和强大的功能,使得它成为系统级编程和高性能应用程序开发的首选语言。它提供了许多重要的特性,如指针的概念,可以直接访问内存地址,使得c语言能够进行底层操作和直接硬件交互。 与其他编程语言相比,c语言的代执行效率很高。这是因为它能够直接与计算机的硬件进行交互,没有额外的运行时开销。此外,c语言的编译器也经过优化,生成高效的机器代。 c语言广泛应用于操作系统、编译器、嵌入式系统等领域。许多操作系统,如Unix、Linux等,都是用c语言编写的。c语言的编译器也是用c语言编写的,这充分展现了c语言的能力和灵活性。 对于初学者来说,c语言也是一种很好的入门语言。它的语法相对简单,易于理解。而且,c语言的基本概念和编程原则对于后续学习其他编程语言也很有帮助。 总之,c语言是一种强大而灵活的编程语言,具有高效性和广泛的应用领域。无论是作为系统级编程的工具,还是作为入门学习的语言,c语言都具有重要意义。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值