Print PDF Byte Array to Zebra Printer





5.00/5 (3 votes)
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.
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.
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.
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