PrintDocument vs Printer Control Language
I have been involved in a project which has a requirement for printing labels using label printers. That sounds to be a very simple requirement. But as always there are always things which make our life miserable. My team is responsible for building a label printing solution which can handle Internationalized / localized text. Currently we are building the solution for Korean system with a possibility of taking it to other countries where we have retail presence.
Challenges involved in label printing
Some of the challenges involved in developing this solution are
- Ability to print various types of barcodes based on industry standards like EAN13 / 128, UPCA
- Ability to print from a central server to any label printer connected in any store
- Ability to print localized text
- Ability to print both text and symbols on labels
There are some of paid software and libraries which help us in doing stuff like print industry standard barcodes, localized text and symbols etc. But these software packages did not satisfy all our requirements as we wanted the labels to be printed differently based on various conditions. The biggest problem I feel in label design is the estate area of label. There is very limited space available in which we needed to print many details. hence positioning of text and symbols is very important.
We can use also use the driver or API provided by printer vendor to print labels. Epson supports such an API. But in my case I was am using Sato printer and there is no driver / API which I could use directly from C# program.
We can use the GDI+ features and PrintDocument object to position the text. The problem with this approach is that PrintDocument relies on the printer driver to convert the text and images into the Printer Control / Command Language (PCL) which is very specific to any printer. This is a combination of ASCII characters which are used to program the printer. This results in performance hit as the PrintDocument object needs to convert the GDI instructions into PCL. Also it defeats the purpose of having a central server as in our case. It also means the central server needs to have all the printer drivers installed on it which I don't think is very scalable approach.
Another disadvantage of this approach is that there is no built in support for barcode printing in GDI+ which means that we need to use third party libraries like Neodynamic. Label printers have very limited support for fonts and comes with default fonts. If we want to use commonly used windows fonts such as Aerial or Times New Roman these are treated as images which again slows down the printing process.
To overcome these limitation we can use the printer Control / Command Language (PCL). It is bit tedious to understand this language at first but since the functionality is so small that we can get familiarized with it in a day or two. This requires us to send raw data to the printer in the form of ASCII text which are interpreted as commands. Since we are sending raw data there is no need for the printer driver to be installed. As long as we can send data to a printer using a network port we can send these commands as byte streams.
This gives a great advantage in terms of speed of printing as there is no conversion required at the printer end like in case of GDI+ graphics. The label printer supports printing of industry standards barcode using default fonts without any dependency on external libraries. We can control the speed and quality of printing. We can use features like partial edits which enables editing few sections of data within a label.
One of the disadvantages of this approach is that for every type of printer that we want to support we'll need to build a sort of adapter which can send these raw data to the printer. For e.g. Sato has a different language / instruction set as compared to that of Epson or Zebra label printers. Adapting to each language can be a real pain. Given the performance benefits of PCL I decided to go ahead and try that approach for Sato CX400 printer development.
All was fine and I was able to print text in different sizes, with different orientation, different fonts etc. I hit a road block while trying to print an image onto the label. I am not sure how many people use Sato printers for label printing. The information available online is very limited and the documentation provided with the installation disk / online are also very basic. I found a method where BMP or PCX images can be loaded into extended memory and printed using some command. But the printer that we have did not have extended memory.
Somehow I came across embedding binary data within the payload which is sent to the printer. This seem to have worked. After some trial and error I was able to achieve what I had set to do and it was a very satisfying thing. I used a evaluation software CODESOFT from Teklynx for converting the images into byte streams. This software also helps you to convert a PCL file into a label and vice versa. It was very helpful in designing the initial layout and then modify it as per the needs. It supports conversion between various formats and various printers. Thanks to the developers of this software. It saved me at least 2 days of effort to get the hex / binary representation and alignment of images. Please note that this is one time job which I used to convert all 10-15 images I wanted to use on my labels into a string which can be used with SATO printers.
Understanding PCL is really challenging. But the performance benefits it offers over PrintDocument are manifolds. If you have a choice I would always suggest writing raw data directly to the printer. It will give a performance boost to the application and you need not depend on third party tools for simple task like drawing barcodes. Until next time Happy Programming!!!