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:
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;
iTextSharp.text.pdf.PdfReader.unethicalreading = true;
using (iTextSharp.text.pdf.PdfReader pdfReader = new iTextSharp.text.pdf.PdfReader(pdfbytes))
{
iTextSharp.text.pdf.PdfRectangle rect =
new iTextSharp.text.pdf.PdfRectangle(0f, 425f, 288f, 842f);
using (MemoryStream ms = new MemoryStream())
{
using (iTextSharp.text.Document doc =
new iTextSharp.text.Document(iTextSharp.text.PageSize.A4))
{
iTextSharp.text.pdf.PdfSmartCopy smartCopy =
new iTextSharp.text.pdf.PdfSmartCopy(doc, ms)
{
PdfVersion = iTextSharp.text.pdf.PdfWriter.VERSION_1_7
};
smartCopy.CloseStream = false;
doc.Open();
for (int i = 1; i <= pdfReader.NumberOfPages; i++)
{
doc.NewPage();
var page = pdfReader.GetPageN(i);
page.Put(iTextSharp.text.pdf.PdfName.CROPBOX, rect);
page.Put(iTextSharp.text.pdf.PdfName.MEDIABOX, rect);
var copiedPage = smartCopy.GetImportedPage(pdfReader, i);
smartCopy.AddPage(copiedPage);
}
smartCopy.FreeReader(pdfReader);
smartCopy.Close();
ms.Position = 0;
rslt = ms.GetBuffer();
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
{
[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);
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;
di.pDocName = "My C#.NET RAW Document";
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 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)
{
FileStream fs = new FileStream(szFileName, FileMode.Open);
BinaryReader br = new BinaryReader(fs);
Byte[] bytes = new Byte[fs.Length];
bool bSuccess = false;
IntPtr pUnmanagedBytes = new IntPtr(0);
int nLength;
nLength = Convert.ToInt32(fs.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 SendStringToPrinter(string szPrinterName, string szString)
{
IntPtr pBytes;
Int32 dwCount;
dwCount = szString.Length;
pBytes = Marshal.StringToCoTaskMemAnsi(szString);
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());
Rectangle2D.Double clip= new Rectangle2D.Double
(50,375,ZebraWidthInDot,ZebraHeightInDot);
g2.translate(0, 0);
PDFRenderer pgs = new PDFRenderer(page, g2, imageArea, clip, null);
try {
page.waitForFinish();
pgs.run();
} catch (InterruptedException ie) {
}
return PAGE_EXISTS;
} else {
return NO_SUCH_PAGE;
}
}
}, pf, pdfFile.getNumPages());
pjob.setPageable(book);
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