Showing posts with label Printer. Show all posts
Showing posts with label Printer. Show all posts

Thursday, June 2, 2016

.NET code to send ZPL to Zebra printers

.NET code to send ZPL to Zebra printers

This way you will be able to send ZPL to a printer no matter how it is connected (LPT, USB, Network Share...)

Create the RawPrinterHelper class (from the Microsoft article on How to send raw data to a printer by using Visual C# .NET):

using System;
using System.IO;
using System.Drawing;
using System.Drawing.Printing;
using System.Windows.Forms;
using System.Runtime.InteropServices;

public class RawPrinterHelper
{
    // Structure and API declarions:
    [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 );

    // 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, false on failure.
    public static 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; // Assume failure unless you specifically succeed.

        di.pDocName = "My C#.NET RAW Document";
        di.pDataType = "RAW";

        // Open the printer.
        if( OpenPrinter( szPrinterName.Normalize(), out hPrinter, IntPtr.Zero ) )
        {
            // Start a document.
            if( StartDocPrinter(hPrinter, 1, di) )
            {
                // Start a page.
                if( StartPagePrinter(hPrinter) )
                {
                    // Write your bytes.
                    bSuccess = WritePrinter(hPrinter, pBytes, dwCount, out dwWritten);
                    EndPagePrinter(hPrinter);
                }
                EndDocPrinter(hPrinter);
            }
            ClosePrinter(hPrinter);
        }
        // If you did not succeed, GetLastError may give more information
        // about why not.
        if( bSuccess == false )
        {
                dwError = Marshal.GetLastWin32Error();
        }
        return bSuccess;
    }

    public static bool SendFileToPrinter( string szPrinterName, string szFileName )
    {
        // Open the file.
        FileStream fs = new FileStream(szFileName, FileMode.Open);
        // Create a BinaryReader on the file.
        BinaryReader br = new BinaryReader(fs);
        // Dim an array of bytes big enough to hold the file's contents.
        Byte []bytes = new Byte[fs.Length];
        bool bSuccess = false;
        // Your unmanaged pointer.
        IntPtr pUnmanagedBytes = new IntPtr(0);
        int nLength;

        nLength = Convert.ToInt32(fs.Length);
        // Read the contents of the file into the array.
        bytes = br.ReadBytes( nLength );
        // Allocate some unmanaged memory for those bytes.
        pUnmanagedBytes = Marshal.AllocCoTaskMem(nLength);
        // Copy the managed byte array into the unmanaged array.
        Marshal.Copy(bytes, 0, pUnmanagedBytes, nLength);
        // Send the unmanaged bytes to the printer.
        bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes, nLength);
        // Free the unmanaged memory that you allocated earlier.
        Marshal.FreeCoTaskMem(pUnmanagedBytes);
        return bSuccess;
    }
    public static bool SendStringToPrinter( string szPrinterName, string szString )
    {
        IntPtr pBytes;
        Int32 dwCount;
        // 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);
        Marshal.FreeCoTaskMem(pBytes);
        return true;
    }
}

Call the print method:

using System.Windows.Forms;
using System.Drawing.Printing;

private void button2_Click(object sender, System.EventArgs e)
{
    string s = "^XA^LH30,30\n^FO20,10^ADN,90,50^AD^FDHello World^FS\n^XZ";

    // Print directly wiht the default printer.
    PrinterSettings printerSetting = new PrinterSettings();
    RawPrinterHelper.SendStringToPrinter(printerSetting.PrinterName, s);

    // Allow the user to select a printer.
    PrintDialog pd  = new PrintDialog();
    pd.PrinterSettings = new PrinterSettings();

    if( DialogResult.OK == pd.ShowDialog(this) )
    {
        // Send a printer-specific to the printer.
        RawPrinterHelper.SendStringToPrinter(pd.PrinterSettings.PrinterName, s);
    }
}

There are 2 gotchas I've come across that happen when you're sending txt files with ZPL codes to the printer:

1. The file has to end with a new line character.

2. Encoding has to be set to Encoding.Default when reading ANSI txt files with special characters.

public static bool SendTextFileToPrinter(string szFileName, string printerName)
{
    var sb = new StringBuilder();

    using (var sr = new StreamReader(szFileName, Encoding.Default)) // Set the correct encoding
    {
        while (!sr.EndOfStream)
        {
            sb.AppendLine(sr.ReadLine()); // This will automatically fix the last line
        }
    }

    return RawPrinterHelper.SendStringToPrinter(printerName, sb.ToString());
}

===

I've managed a project that does this with sockets for years. Zebra's typically use port 6101. I'll look through the code and post what I can.

public void SendData(string zpl)
{
    NetworkStream ns = null;
    Socket socket = null;

    try
    {
        if (printerIP == null)
        {
            /* IP is a string property for the printer's IP address. */
            /* 6101 is the common port of all our Zebra printers. */
            printerIP = new IPEndPoint(IPAddress.Parse(IP), 6101);  
        }

        socket = new Socket(AddressFamily.InterNetwork,
            SocketType.Stream,
            ProtocolType.Tcp);
        socket.Connect(printerIP);

        ns = new NetworkStream(socket);

        byte[] toSend = Encoding.ASCII.GetBytes(zpl);
        ns.Write(toSend, 0, toSend.Length);
    }
    finally
    {
        if (ns != null)
            ns.Close();

        if (socket != null && socket.Connected)
            socket.Close();
    }
}

Note: Zebra Mobile printers use port 6101 (QL, RW, MZ, etc). Larger printers usually use port 9100.

===

SharpZebra - A C# library that simplifies printing to Zebra printers in their native EPL2/ZPL languages without needing to know EPL2 or ZPL.

===

Here is how to do it using TCP IP protocol:

// Printer IP Address and communication port
    string ipAddress = "10.3.14.42";
   int port = 9100;

// ZPL Command(s)
   string ZPLString =
    "^XA" +
    "^FO50,50" +
    "^A0N50,50" +
    "^FDHello, World!^FS" +
    "^XZ";

   try
   {
    // Open connection
    System.Net.Sockets.TcpClient client = new System.Net.Sockets.TcpClient();
    client.Connect(ipAddress, port);

    // Write ZPL String to connection
    System.IO.StreamWriter writer =
    new System.IO.StreamWriter(client.GetStream());
    writer.Write(ZPLString);
    writer.Flush();

    // Close Connection
    writer.Close();
    client.Close();
}
catch (Exception ex)
{
    // Catch Exception
}

Reference:

http://stackoverflow.com/questions/2044676/net-code-to-send-zpl-to-zebra-printers

http://support.microsoft.com/kb/322091

http://sharpzebra.codeplex.com/

Wednesday, November 4, 2015

How to print a logo on labels using a Zebra printer and sending ZPL instructions to it

How to print a logo on labels using a Zebra printer and sending ZPL instructions to it

go to the Labelary online ZPL viewer, paste your ZPL into the viewer, click "Add image", and upload the image that you want to add to the ZPL.

Reference:

http://stackoverflow.com/questions/29253453/how-to-print-a-logo-on-labels-using-a-zebra-printer-and-sending-zpl-instructions

http://labelary.com/viewer.html

https://sharpzebra.codeplex.com/

Tuesday, November 3, 2015

Load PDF into iframe and call print

<html>
<head>
<script src="jquery-1.11.3.min.js"></script>
<script>
jQuery(document).ready(function($) {
  function print(url)
  {
      var _this = this,
          iframeId = 'iframeprint',
          $iframe = $('iframe#iframeprint');
      $iframe.attr('src', url);

      $iframe.load(function() {
          callPrint(iframeId);
      });
  }

  //initiates print once content has been loaded into iframe
  function callPrint(iframeId) {
      var PDF = document.getElementById(iframeId);
      PDF.focus();
      PDF.contentWindow.print();
  }

  print('http://mydomain.local/test.pdf');
});
</script>
</head>
<body>
  <iframe id="iframeprint"></iframe>
</body>
</html>

Reference:

http://www.sitepoint.com/load-pdf-iframe-call-print/

Print directly from browser without print popup dialog window

Print directly from browser without print popup dialog window

I wanted to follow up on this to share how I resolved this.

I ended up implementing a custom application that works very similar to the Nexus Mod Manager. I wrote a C# application that registers a custom Application URI Scheme. Here's how it works:

1. User clicks "Print" on the website.
2. Website links user to "CustomURL://Print/{ID}
3. Application is launched by windows via the custom uri scheme.
4. Application communicates with the pre-configured server to confirm the print request and in my case get the actual print command.
5. The application then uses the C# RawPrinterHelper class to send commands directly to the printer.

This approach required an initial download from the user, and a single security prompt from windows when launching the application the first time. I also implemented some Javascript magic to make it detect whether the print job was handled or not. If it wasn't it asks them to download the application.

Reference:

http://stackoverflow.com/questions/9213660/html-javascript-one-click-print-no-dialogs

get ZPL Code From zebra designer?

You can add a new ZebraDesigner ZPL driver to the system and use a file as the port. Then when you "Print" the document, it will write the ZPL code to the file.

Note that it might have some header information before the first ^XA which you might not need.

UPDATE : (How to add local port on a driver)

  1. Go to Printer Properties
  2. Click on the Ports tab
  3. Click Add Port
  4. Select Local Port and click New port
  5. Enter a filename e.g. C:\output.zpl
  6. Make sure it is checked in the ports list
  7. Now all printing output should go to C:\output.zpl

===

If you want to see native ZLP codes you must use zebra fonts, if you do not use you will see .GRF codes like below:

^FT320,64^XG007.GRF,1,1^FS

and do not understand them. After that hit print than select "print to file". So you can see clear ZLP codes.

Reference:

http://stackoverflow.com/questions/13586865/get-zpl-code-from-zebra-designer