Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Print PDF Byte Array to Zebra Printer

5.00/5 (3 votes)
20 Jan 2015CPOL2 min read 40.8K  
Print an attachment to Zebra printer

Introduction

In this tip, we shall see how C# can print PDF byte array to Zebra printer using RawPrinterHelper class from Microsoft.

Background

In previous posts, you can see how to print texts and images on Zebra labels.

But when a new project is coming, it demands to print a PDF page which is downloaded from web service in Base64 encode string to Zebra printer.
So just convert byte array into an image, then output to printer? Unfortunately, it does not work at all. What I did so far is to render byte array into a PDF document using iText library, crop it and copy a part of PDF page into a new document and print it out using RawPrinterHelper class. I am posting here hoping that somebody might be interested.

Using the Code

The attached code is built using C#2013 & Eclipse. It has:

  • C# syntax
  • Java syntax

Let's Break It Down

We will use the SendBytesToPrinter of RawPrinterHelper.cs to send data to Zebra printer.
First, we get base64 encode string data from web service, here I get it from XML file, convert into byte array.
Read this data by PdfReader into a copy of document, crop it and print using RawPrinterHelper class.

C#
using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Configuration;
using System.Drawing.Imaging;
using System.Drawing.Printing;
using System.Runtime.InteropServices;
using System.Linq;
using System.Xml.Linq;
using Utility;

class PrintEPL
{
    public PrintEPL() { }
    public void RunPDF()
    {
            XDocument doc = XDocument.Load(@"C:\Development\out1.xml");
            XElement ele = doc.Descendants("Attachment").FirstOrDefault();
            Byte[] pdfbytes = Convert.FromBase64String(ele.Value);

            byte[] bytes = Crop(pdfbytes);
            IntPtr pUnmanagedBytes = new IntPtr(0);
            int nLength = bytes.Length;
            pUnmanagedBytes = Marshal.AllocCoTaskMem(nLength);
            Marshal.Copy(bytes, 0, pUnmanagedBytes, nLength);
            RawPrinterHelper.SendBytesToPrinter("IT infotec  IS 2325 PCL", pUnmanagedBytes, nLength);
            Marshal.FreeCoTaskMem(pUnmanagedBytes);
    }
    private byte[] Crop(Byte[] pdfbytes)
    {            
            byte[] rslt = null;
            // Allows PdfReader to read a pdf document without the owner's password
            iTextSharp.text.pdf.PdfReader.unethicalreading = true;
            // Reads the PDF document
            using (iTextSharp.text.pdf.PdfReader pdfReader = new iTextSharp.text.pdf.PdfReader(pdfbytes))
            {
                // Set which part of the source document will be copied.
                // PdfRectangel(bottom-left-x, bottom-left-y, upper-right-x, upper-right-y)
                iTextSharp.text.pdf.PdfRectangle rect = 
                	new iTextSharp.text.pdf.PdfRectangle(0f, 425f, 288f, 842f);
                               
                using (MemoryStream ms = new MemoryStream())
                {
                    // Create a new document
                    //using (iTextSharp.text.Document doc = 
                    //	new iTextSharp.text.Document(new iTextSharp.text.Rectangle(288f,432f)))
                    using (iTextSharp.text.Document doc = 
                    	new iTextSharp.text.Document(iTextSharp.text.PageSize.A4))
                    {
                        // Make a copy of the document
                        iTextSharp.text.pdf.PdfSmartCopy smartCopy = 
                                          new iTextSharp.text.pdf.PdfSmartCopy(doc, ms)
                        {
                            PdfVersion = iTextSharp.text.pdf.PdfWriter.VERSION_1_7
                        };
                        smartCopy.CloseStream = false;                        
                        // Open the newly created document                        
                        doc.Open();
                        // Loop through all pages of the source document
                        for (int i = 1; i <= pdfReader.NumberOfPages; i++)
                        {
                            doc.NewPage();// net necessary line
                            // Get a page
                            var page = pdfReader.GetPageN(i);
                            // Apply the rectangle filter we created
                            page.Put(iTextSharp.text.pdf.PdfName.CROPBOX, rect);
                            page.Put(iTextSharp.text.pdf.PdfName.MEDIABOX, rect);
                            // Copy the content and insert into the new document
                            var copiedPage = smartCopy.GetImportedPage(pdfReader, i);
                            smartCopy.AddPage(copiedPage);                                                        
                        }
                        smartCopy.FreeReader(pdfReader);
                        smartCopy.Close();
                        ms.Position = 0;
                        rslt = ms.GetBuffer();
                        // Close the output document
                        doc.Close();                        
                    }
                }
                return rslt;
            }
        }
}

RawPrinterHelper

I found this class on the internet, I just edited it for suiting my purpose. I am posting here together so if someone is interested, there is no need to Google.

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

namespace Utility
{
    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 SendMemoryToPrinter(string szPrinterName, MemoryStream ms)
        {            
            BinaryReader br = new BinaryReader(ms);
            Byte[] bytes = new Byte[ms.Length];
            bool bSuccess = false;
            IntPtr pUnmanagedBytes = new IntPtr(0);
            int nLength;

            nLength = Convert.ToInt32(ms.Length);
            bytes = br.ReadBytes(nLength);
            pUnmanagedBytes = Marshal.AllocCoTaskMem(nLength);
            Marshal.Copy(bytes, 0, pUnmanagedBytes, nLength);
            bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes, nLength);
            Marshal.FreeCoTaskMem(pUnmanagedBytes);
            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;
        }
    }
}

Last part - We Create Java Code

First, you need to download pdf-renderer-1.0.5.jar and add it to Java runtime library, in my case, it is C:\Program Files\Java\jre7\lib\ext\pdf-renderer-1.0.5.jar.
We will use that library to render PDF page creating from byte array.

Java
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import java.awt.print.Book;
import java.awt.print.PageFormat;
import java.awt.print.Paper;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.Socket;
import java.net.URL;
import java.nio.ByteBuffer;
import java.net.URLDecoder;
import sun.misc.BASE64Decoder;
import java.text.MessageFormat;
import java.util.Date;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import com.sun.pdfview.PDFFile;
import com.sun.pdfview.PDFPage;
import com.sun.pdfview.PDFRenderer;

private static void Print(String encodedBytes, String sPrinterName) throws Exception {
		BASE64Decoder decoder = new BASE64Decoder();
		byte[] pdfContent = decoder.decodeBuffer(encodedBytes);
		ByteBuffer bb = ByteBuffer.wrap(pdfContent);
		final PDFFile pdfFile = new PDFFile(bb);	
		final int ZebraWidthInDot = 4*72;
		final int ZebraHeightInDot = 6*72;
		PrintService psZebra = null;           		       
   		PrintService[] services = PrintServiceLookup.lookupPrintServices(null, null);        
   		for (int i = 0; i < services.length;i++) {     			
   			if(services[i].getName().equalsIgnoreCase(sPrinterName)){
   				psZebra = services[i];            
   				break;   
   			}
   		} 
   		PrinterJob pjob = PrinterJob.getPrinterJob();
		pjob.setPrintService(psZebra);
		PageFormat pf = PrinterJob.getPrinterJob().defaultPage();
		pjob.setJobName("Test Print PDF");
		Book book = new Book();
		book.append(new Printable(){
			@Override
			public int print(Graphics g, PageFormat format, int index) throws PrinterException {
				int pagenum = index + 1;
				if ((pagenum >= 1) && (pagenum <= pdfFile.getNumPages())) {
					Graphics2D g2 = (Graphics2D) g;
					PDFPage page = pdfFile.getPage(pagenum);
					
					Rectangle imageArea = new Rectangle((int) format.getImageableX(), 
                                         (int) format.getImageableY(),
							(int) format.getImageableWidth(), 
							(int) format.getImageableHeight()); // fit the portion of PDFPage 
                                                               // into the printing area
					Rectangle2D.Double clip= new Rectangle2D.Double
						(50,375,ZebraWidthInDot,ZebraHeightInDot); //get portion of PDFPage 
                                                                  //we want to print
					g2.translate(0, 0); //print at point(0,0) when image is drawn at(0,0)
					PDFRenderer pgs = new PDFRenderer(page, g2, imageArea, clip, null);
					try {
						page.waitForFinish();
						pgs.run();
					} catch (InterruptedException ie) {
						// nothing to do
					}
					return PAGE_EXISTS;
				} else {
					return NO_SUCH_PAGE;
				}
			}			
		}, pf, pdfFile.getNumPages());
		pjob.setPageable(book);
		// to remove margins
		Paper paper = new Paper();
		paper.setSize(ZebraWidthInDot, ZebraHeightInDot);
		paper.setImageableArea(0, 0, paper.getWidth(), paper.getHeight());
		pf.setPaper(paper);		
		pjob.print();   		   	
	}

Points of Interest

What we want to know in this tip is to understand how to render byte array into PDF document.

History

  • 10th October 2013: First version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)