将Base64编码的PNG图像发送到斑马打印机

5
我是一名有用的助手,可以为您翻译文本。

我尝试在 Zebra LP-2844-Z 打印机中使用 C# 打印一个 base64 PNG 图像。

我需要任何可以帮助我继续编写代码的澄清或文档。

https://support.zebra.com/cpws/docs/zpl/zpl_manual.pdf

我已尝试以下代码:

var zplImageData = string.Empty;
            var filePath = @"C:\Users\user1\desktop\LABEL.PNG";
            byte[] binaryData = System.IO.File.ReadAllBytes(filePath);
            foreach (Byte b in binaryData)
            {
                string hexRep = String.Format("{0:X}", b);  
                if (hexRep.Length == 1)                                  
                    hexRep = "0" + hexRep;
                zplImageData += hexRep;
            }
            string zplToSend = "^XA" + "^MNN" + "^LL500" + "~DYE:LABEL,P,P," + binaryData.Length + ",," + zplImageData + "^XZ";
            string printImage = "^XA^FO115,50^IME:LABEL.PNG^FS^XZ";

            // test
            RawPrint.SendStringToPrinter(printer.WindowsName, zplToSend, "Raw");
            RawPrint.SendStringToPrinter(printer.WindowsName, printImage, "Raw");

我尝试使用此链接中的代码: 将PNG图像打印到Zebra网络打印机

RawPrint方法:

Public Class RawPrint
' Structure and API declarions:
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> _
Structure DOCINFOW
    <MarshalAs(UnmanagedType.LPWStr)> Public pDocName As String
    <MarshalAs(UnmanagedType.LPWStr)> Public pOutputFile As String
    <MarshalAs(UnmanagedType.LPWStr)> Public pDataType As String
End Structure

<DllImport("winspool.Drv", EntryPoint:="OpenPrinterW", _
   SetLastError:=True, CharSet:=CharSet.Unicode, _
   ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function OpenPrinter(ByVal src As String, ByRef hPrinter As IntPtr, ByVal pd As Int32) As Boolean
End Function
<DllImport("winspool.Drv", EntryPoint:="ClosePrinter", _
   SetLastError:=True, CharSet:=CharSet.Unicode, _
   ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function ClosePrinter(ByVal hPrinter As IntPtr) As Boolean
End Function
<DllImport("winspool.Drv", EntryPoint:="StartDocPrinterW", _
   SetLastError:=True, CharSet:=CharSet.Unicode, _
   ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function StartDocPrinter(ByVal hPrinter As IntPtr, ByVal level As Int32, ByRef pDI As DOCINFOW) As Boolean
End Function
<DllImport("winspool.Drv", EntryPoint:="EndDocPrinter", _
   SetLastError:=True, CharSet:=CharSet.Unicode, _
   ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function EndDocPrinter(ByVal hPrinter As IntPtr) As Boolean
End Function
<DllImport("winspool.Drv", EntryPoint:="StartPagePrinter", _
   SetLastError:=True, CharSet:=CharSet.Unicode, _
   ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function StartPagePrinter(ByVal hPrinter As IntPtr) As Boolean
End Function
<DllImport("winspool.Drv", EntryPoint:="EndPagePrinter", _
   SetLastError:=True, CharSet:=CharSet.Unicode, _
   ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function EndPagePrinter(ByVal hPrinter As IntPtr) As Boolean
End Function
<DllImport("winspool.Drv", EntryPoint:="WritePrinter", _
   SetLastError:=True, CharSet:=CharSet.Unicode, _
   ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function WritePrinter(ByVal hPrinter As IntPtr, ByVal pBytes As IntPtr, ByVal dwCount As Int32, ByRef dwWritten As Int32) As Boolean
End Function

' SendBytesToPrinter()
' When the function is given a printer name and an unmanaged array of  
' bytes, the function sends those bytes to the print queue.
' Returns True on success or False on failure.
Public Shared Function SendBytesToPrinter(ByVal szPrinterName As String, ByVal pBytes As IntPtr, ByVal dwCount As Int32, Optional ByVal docName As String = "Raw Document") As Boolean
    Dim hPrinter As IntPtr          ' The printer handle.
    Dim dwError As Int32            ' Last error - in case there was trouble.
    Dim di As DOCINFOW = Nothing    ' Describes your document (name, port, data type).
    Dim dwWritten As Int32          ' The number of bytes written by WritePrinter().
    Dim bSuccess As Boolean         ' Your success code.

    ' Set up the DOCINFO structure.
    With di
        .pDocName = docName
        .pDataType = "RAW"
    End With
    ' Assume failure unless you specifically succeed.
    bSuccess = False
    If OpenPrinter(szPrinterName, hPrinter, 0) Then
        If StartDocPrinter(hPrinter, 1, di) Then
            If StartPagePrinter(hPrinter) Then
                ' Write your printer-specific bytes to the printer.
                bSuccess = WritePrinter(hPrinter, pBytes, dwCount, dwWritten)
                EndPagePrinter(hPrinter)
            End If
            EndDocPrinter(hPrinter)
        End If
        ClosePrinter(hPrinter)
    End If
    ' If you did not succeed, GetLastError may give more information
    ' about why not.
    If bSuccess = False Then
        dwError = Marshal.GetLastWin32Error()
    End If
    Return bSuccess
End Function ' SendBytesToPrinter()

' SendFileToPrinter()
' When the function is given a file name and a printer name, 
' the function reads the contents of the file and sends the
' contents to the printer.
' Presumes that the file contains printer-ready data.
' Shows how to use the SendBytesToPrinter function.
' Returns True on success or False on failure.
Public Shared Function SendFileToPrinter(ByVal szPrinterName As String, ByVal szFileName As String, Optional ByVal docName As String = "Raw Document") As Boolean
    ' Open the file.
    Dim fs As New FileStream(szFileName, FileMode.Open)
    ' Create a BinaryReader on the file.
    Dim br As New BinaryReader(fs)
    ' Dim an array of bytes large enough to hold the file's contents.
    Dim bytes(fs.Length) As Byte
    Dim bSuccess As Boolean
    ' Your unmanaged pointer.
    Dim pUnmanagedBytes As IntPtr

    ' Read the contents of the file into the array.
    bytes = br.ReadBytes(fs.Length)
    ' Allocate some unmanaged memory for those bytes.
    pUnmanagedBytes = Marshal.AllocCoTaskMem(fs.Length)
    ' Copy the managed byte array into the unmanaged array.
    Marshal.Copy(bytes, 0, pUnmanagedBytes, fs.Length)
    ' Send the unmanaged bytes to the printer.
    bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes, fs.Length, docName)
    ' Free the unmanaged memory that you allocated earlier.
    Marshal.FreeCoTaskMem(pUnmanagedBytes)
    Return bSuccess
End Function ' SendFileToPrinter()

' When the function is given a string and a printer name,
' the function sends the string to the printer as raw bytes.
Public Shared Sub SendStringToPrinter(ByVal szPrinterName As String, ByVal szString As String, ByVal DocName As String)
    Dim pBytes As IntPtr
    Dim dwCount As Int32
    ' How many characters are in the string?
    dwCount = szString.Length()
    ' Assume that the printer is expecting ANSI text, and then convert
    ' the string to ANSI text.
    pBytes = Marshal.StringToCoTaskMemAnsi(szString)
    ' Send the converted ANSI string to the printer.
    SendBytesToPrinter(szPrinterName, pBytes, dwCount, DocName)
    Marshal.FreeCoTaskMem(pBytes)
End Sub
End Class

但是它没有起作用,有人知道如何做吗?
1个回答

3
我找到了一种完美且经过优化的解决方案,可以将BASE64/PNG图像打印到ZPL打印机(ZEBRA)上:
    public class ZPLHelper
    {
        static Regex regexFilename = new Regex("^[REBA]:[A-Z0-9]{1,8}\\.GRF$");

        public static bool PrintLabelBase64Image(string printerName, string base64Image, string jobName = "label")
        {
            try
            {
                var bmpLabel = Base64ToBitmap(base64Image);
                var baseStream = new MemoryStream();
                var tw = new StreamWriter(baseStream, Encoding.UTF8);
                tw.WriteLine(GetGrfStoreCommand("R:LBLRA2.GRF", bmpLabel));
                tw.WriteLine(GetGrfPrintCommand("R:LBLRA2.GRF"));
                tw.WriteLine(GetGrfDeleteCommand("R:LBLRA2.GRF"));
                tw.Flush();
                baseStream.Position = 0;

                var gdipj = new GdiPrintJob(printerName, GdiPrintJobDataType.Raw, jobName, null);
                gdipj.WritePage(baseStream);
                gdipj.CompleteJob();

                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }
        public static bool PrintLabelZpl(string printerName, string zplCommand, string jobName = "label")
        {
            var baseStream = new MemoryStream();
            var tw = new StreamWriter(baseStream, Encoding.UTF8);
            tw.WriteLine(zplCommand);
            tw.Flush();
            baseStream.Position = 0;

            var gdiJob = new GdiPrintJob(printerName, GdiPrintJobDataType.Raw, jobName, null);
            gdiJob.WritePage(baseStream);
            gdiJob.CompleteJob();

            return true;
        }

        private static Bitmap Base64ToBitmap(string base64Image)
        {
            Image image;
            using (var ms = new MemoryStream(Convert.FromBase64String(base64Image)))
            {
                image = Image.FromStream(ms);
            }

            return new Bitmap(image);
        }
        public static string GetGrfStoreCommand(string filename, Bitmap bmpSource)
        {
            if (bmpSource == null)
            {
                throw new ArgumentNullException("bmpSource");
            }
            validateFilename(filename);

            var dim = new Rectangle(Point.Empty, bmpSource.Size);
            var stride = ((dim.Width + 7) / 8);
            var bytes = stride * dim.Height;

            using (var bmpCompressed = bmpSource.Clone(dim, PixelFormat.Format1bppIndexed))
            {
                var result = new StringBuilder();

                result.AppendFormat("^XA~DG{2},{0},{1},", stride * dim.Height, stride, filename);
                byte[][] imageData = GetImageData(dim, stride, bmpCompressed);

                byte[] previousRow = null;
                foreach (var row in imageData)
                {
                    appendLine(row, previousRow, result);
                    previousRow = row;
                }
                result.Append(@"^FS^XZ");

                return result.ToString();
            }
        }
        public static string GetGrfDeleteCommand(string filename)
        {
            validateFilename(filename);

            return string.Format("^XA^ID{0}^FS^XZ", filename);
        }
        public static string GetGrfPrintCommand(string filename)
        {
            validateFilename(filename);

            return string.Format("^XA^FO0,0^XG{0},1,1^FS^XZ", filename);
        }

        private static void validateFilename(string filename)
        {
            if (!regexFilename.IsMatch(filename))
            {
                throw new ArgumentException("Filename must be in the format "
                    + "R:XXXXXXXX.GRF.  Drives are R, E, B, A.  Filename can "
                    + "be alphanumeric between 1 and 8 characters.", "filename");
            }
        }
        unsafe private static byte[][] GetImageData(Rectangle dim, int stride, Bitmap bmpCompressed)
        {
            byte[][] imageData;
            var data = bmpCompressed.LockBits(dim, ImageLockMode.ReadOnly, PixelFormat.Format1bppIndexed);
            try
            {
                byte* pixelData = (byte*)data.Scan0.ToPointer();
                byte rightMask = (byte)(0xff << (data.Stride * 8 - dim.Width));
                imageData = new byte[dim.Height][];

                for (int row = 0; row < dim.Height; row++)
                {
                    byte* rowStart = pixelData + row * data.Stride;
                    imageData[row] = new byte[stride];

                    for (int col = 0; col < stride; col++)
                    {
                        byte f = (byte)(0xff ^ rowStart[col]);
                        f = (col == stride - 1) ? (byte)(f & rightMask) : f;
                        imageData[row][col] = f;
                    }
                }
            }
            finally
            {
                bmpCompressed.UnlockBits(data);
            }
            return imageData;
        }
        private static void appendLine(byte[] row, byte[] previousRow, StringBuilder baseStream)
        {
            if (row.All(r => r == 0))
            {
                baseStream.Append(",");
                return;
            }

            if (row.All(r => r == 0xff))
            {
                baseStream.Append("!");
                return;
            }

            if (previousRow != null && MatchByteArray(row, previousRow))
            {
                baseStream.Append(":");
                return;
            }

            byte[] nibbles = new byte[row.Length * 2];
            for (int i = 0; i < row.Length; i++)
            {
                nibbles[i * 2] = (byte)(row[i] >> 4);
                nibbles[i * 2 + 1] = (byte)(row[i] & 0x0f);
            }

            for (int i = 0; i < nibbles.Length; i++)
            {
                byte cPixel = nibbles[i];

                int repeatCount = 0;
                for (int j = i; j < nibbles.Length && repeatCount <= 400; j++)
                {
                    if (cPixel == nibbles[j])
                    {
                        repeatCount++;
                    }
                    else
                    {
                        break;
                    }
                }

                if (repeatCount > 2)
                {
                    if (repeatCount == nibbles.Length - i
                        && (cPixel == 0 || cPixel == 0xf))
                    {
                        if (cPixel == 0)
                        {
                            if (i % 2 == 1)
                            {
                                baseStream.Append("0");
                            }
                            baseStream.Append(",");
                            return;
                        }
                        else if (cPixel == 0xf)
                        {
                            if (i % 2 == 1)
                            {
                                baseStream.Append("F");
                            }
                            baseStream.Append("!");
                            return;
                        }
                    }
                    else
                    {
                        baseStream.Append(getRepeatCode(repeatCount));
                        i += repeatCount - 1;
                    }
                }
                baseStream.Append(cPixel.ToString("X"));
            }
        }
        private static string getRepeatCode(int repeatCount)
        {
            if (repeatCount > 419)
                throw new ArgumentOutOfRangeException();

            int high = repeatCount / 20;
            int low = repeatCount % 20;

            const string lowString = " GHIJKLMNOPQRSTUVWXY";
            const string highString = " ghijklmnopqrstuvwxyz";

            string repeatStr = "";
            if (high > 0)
            {
                repeatStr += highString[high];
            }
            if (low > 0)
            {
                repeatStr += lowString[low];
            }

            return repeatStr;
        }
        private static bool MatchByteArray(byte[] row, byte[] previousRow)
        {
            for (int i = 0; i < row.Length; i++)
            {
                if (row[i] != previousRow[i])
                {
                    return false;
                }
            }

            return true;
        }
    }

    internal static class NativeMethods
    {
        #region winspool.drv

        #region P/Invokes

        [DllImport("winspool.Drv", SetLastError = true, CharSet = CharSet.Unicode)]
        internal static extern bool OpenPrinter(string szPrinter, out IntPtr hPrinter, IntPtr pd);

        [DllImport("winspool.Drv", SetLastError = true, CharSet = CharSet.Unicode)]
        internal static extern bool ClosePrinter(IntPtr hPrinter);

        [DllImport("winspool.Drv", SetLastError = true, CharSet = CharSet.Unicode)]
        internal static extern UInt32 StartDocPrinter(IntPtr hPrinter, Int32 level, IntPtr di);

        [DllImport("winspool.Drv", SetLastError = true, CharSet = CharSet.Unicode)]
        internal static extern bool EndDocPrinter(IntPtr hPrinter);

        [DllImport("winspool.Drv", SetLastError = true, CharSet = CharSet.Unicode)]
        internal static extern bool StartPagePrinter(IntPtr hPrinter);

        [DllImport("winspool.Drv", SetLastError = true, CharSet = CharSet.Unicode)]
        internal static extern bool EndPagePrinter(IntPtr hPrinter);

        [DllImport("winspool.Drv", SetLastError = true, CharSet = CharSet.Unicode)]
        internal static extern bool WritePrinter(
            // 0
            IntPtr hPrinter,
            [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] byte[] pBytes,
            // 2
            UInt32 dwCount,
            out UInt32 dwWritten);

        #endregion

        #region Structs

        [StructLayout(LayoutKind.Sequential)]
        internal struct DOC_INFO_1
        {
            [MarshalAs(UnmanagedType.LPWStr)]
            public string DocName;
            [MarshalAs(UnmanagedType.LPWStr)]
            public string OutputFile;
            [MarshalAs(UnmanagedType.LPWStr)]
            public string Datatype;
        }

        #endregion

        #endregion
    }

    /// <summary>
    /// Represents a print job in a spooler queue
    /// </summary>
    public class GdiPrintJob
    {
        IntPtr PrinterHandle;
        //IntPtr DocHandle;

        /// <summary>
        /// The ID assigned by the print spooler to identify the job
        /// </summary>
        public UInt32 PrintJobID { get; private set; }

        /// <summary>
        /// Create a print job with a enumerated datatype
        /// </summary>
        /// <param name="PrinterName"></param>
        /// <param name="dataType"></param>
        /// <param name="jobName"></param>
        /// <param name="outputFileName"></param>
        public GdiPrintJob(string PrinterName, GdiPrintJobDataType dataType, string jobName, string outputFileName)
            : this(PrinterName, translateType(dataType), jobName, outputFileName)
        {
        }

        /// <summary>
        /// Create a print job with a string datatype
        /// </summary>
        /// <param name="PrinterName"></param>
        /// <param name="dataType"></param>
        /// <param name="jobName"></param>
        /// <param name="outputFileName"></param>
        public GdiPrintJob(string PrinterName, string dataType, string jobName, string outputFileName)
        {
            if (string.IsNullOrWhiteSpace(PrinterName))
                throw new ArgumentNullException("PrinterName");
            if (string.IsNullOrWhiteSpace(dataType))
                throw new ArgumentNullException("PrinterName");

            IntPtr hPrinter;
            if (!NativeMethods.OpenPrinter(PrinterName, out hPrinter, IntPtr.Zero))
                throw new Win32Exception();
            this.PrinterHandle = hPrinter;

            NativeMethods.DOC_INFO_1 docInfo = new NativeMethods.DOC_INFO_1()
            {
                DocName = jobName,
                Datatype = dataType,
                OutputFile = outputFileName
            };
            IntPtr pDocInfo = Marshal.AllocHGlobal(Marshal.SizeOf(docInfo));
            RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
                Marshal.StructureToPtr(docInfo, pDocInfo, false);
                UInt32 docid = NativeMethods.StartDocPrinter(hPrinter, 1, pDocInfo);
                if (docid == 0)
                    throw new Win32Exception();
                this.PrintJobID = docid;
            }
            finally
            {
                Marshal.FreeHGlobal(pDocInfo);
            }
        }

        /// <summary>
        /// Write the data of a single page or a precomposed PCL document
        /// </summary>
        /// <param name="data"></param>
        public void WritePage(Stream data)
        {
            if (data == null)
                throw new ArgumentNullException("data");
            if (!data.CanRead && !data.CanWrite)
                throw new ObjectDisposedException("data");
            if (!data.CanRead)
                throw new NotSupportedException("stream is not readable");

            if (!NativeMethods.StartPagePrinter(this.PrinterHandle))
                throw new Win32Exception();

            byte[] buffer = new byte[0x14000]; /* 80k is Stream.CopyTo default */
            uint read = 1;
            while ((read = (uint)data.Read(buffer, 0, buffer.Length)) != 0)
            {
                UInt32 written;
                if (!NativeMethods.WritePrinter(this.PrinterHandle, buffer, read, out written))
                    throw new Win32Exception();

                if (written != read)
                    throw new InvalidOperationException("Error while writing to stream");
            }

            if (!NativeMethods.EndPagePrinter(this.PrinterHandle))
                throw new Win32Exception();
        }

        /// <summary>
        /// Complete the current job
        /// </summary>
        public void CompleteJob()
        {
            if (!NativeMethods.EndDocPrinter(this.PrinterHandle))
                throw new Win32Exception();
        }

        #region datatypes
        private readonly static string[] dataTypes = new string[]
    { 
        // 0
        null,
        "RAW", 
        // 2
        "RAW [FF appended]",
        "RAW [FF auto]",
        // 4
        "NT EMF 1.003",
        "NT EMF 1.006",
        // 6
        "NT EMF 1.007",
        "NT EMF 1.008", 
        // 8
        "TEXT",
        "XPS_PASS", 
        // 10
        "XPS2GDI"
    };

        private static string translateType(GdiPrintJobDataType type)
        {
            return dataTypes[(int)type];
        }
        #endregion
    }

    public enum GdiPrintJobDataType
    {
        Unknown = 0,
        Raw = 1,
        RawAppendFF = 2,
        RawAuto = 3,
        NtEmf1003 = 4,
        NtEmf1006 = 5,
        NtEmf1007 = 6,
        NtEmf1008 = 7,
        Text = 8,
        XpsPass = 9,
        Xps2Gdi = 10
    }
}

如果只有这个可以打印到一个IP地址。 - Ryan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接