Sunday, 2 August 2015

Retail Print Receipt Customization

How the Windows printing works.
There are two plug-ins that important with respect to the printing process:  the Printing service and the Peripherals service.  The Printing service handles all of the layout of what is being printed; it reads from the Form Layout table and replaces data fields with information from the transaction being printed.  The resulting string (and it really is just a simple text string) then gets passed to the Peripherals plug-in which handles the communication with the printer.
The Peripherals plug-in is of most interest for this article, specifically the branch of code that starts with the PrintReceipt() method of the printers.cs file:
           switch (LSRetailPosis.Settings.HardwareProfiles.Printer.DeviceType) 
case DeviceTypes.OPOS: 

case DeviceTypes.Windows: 
WindowsPrinting(text, LSRetailPosis.Settings.HardwareProfiles.Printer.DeviceName); 
When this code gets hit, the receipt has already been created in memory and is ready to send to the printer.  The decision to send to an OPOS printer (OPOSPrinting method) or a Windows printer (WindowsPrinting method) fully depends on the setting on the Printer tab of the POS Hardware Profile window:
Images and Barcodes:  The WindowsPrinting() method uses an standard method for communicating with the printer:  the System.Drawing.Printing class.  A very simplistic way of looking at this way of printing is to think of drawing an image of the page in memory and then sending that image to the printer.  Printing simple text alone using this method is somewhat difficult; adding complex formatting (images, different fonts, etc.) is something that we have left for Partners and Customers to customize.
When printing to an OPOS device, you can send special OPOS codes to the printer to print either a barcode or an image, both of which are directly managed by the printer.  Because System.Drawing.Printing is not specific to any one printer or class of printers, this shortcut is not available for Windows printers.  In fact, if you print these fields to a Windows printer, you’ll notice that they show up as placeholders like this:  <L> and <B:00001>.  If you are looking to add barcode and image functionality, the code in the printDoc_PrintPage() method is where you would start.
Page Breaking:  The printDoc_PrintPage() method is also where there is a bug in page break functionality.  OPOS printers have no concept of page breaks – if you add 100 lines to a receipt, it will just keep scrolling the paper and printing.  System.Drawing.Printing requires that you calculate the page size and add page breaks manually.  The implementation that we ship does not have this code for page breaks.  This means if you have a long receipt, even if you are printing to scrolling paper, sooner or later a page break will get hit and the receipt will just quit printing.
Attached below is code that shows one way that you can incorporate page breaking into the code.  Since we are printing with a fixed-sized font (7-point Courier New) we can calculate how many lines can be printed on a “page.”  The code then writes out each line of the receipt until it hits that number of lines.  It then stops writing, flushes to the printer, and sets the PrintPageEventArgs.HasMorePages Property for whether another page should be printed.  The PrintDocument.PrintPage Event entry on MSDN includes an excellent example showing how page breaks should be calculated.
I have included both the original version of “Printer.cs” and the version with my changes.  Create a new project for the Peripherals plug-in and merge in the code changes.  This fix has not gone through formal testing and you may find a better way to keep track of paging, but it works in my limited testing and should be a good starting point.
Page Size:  Printing to an OPOS device is very simplistic; a fixed-width font is used and a relatively narrow page size is used.  If you need to print to a Windows printer and use different paper sizes, there are limitations but a few things you can try.
First of all, you can try different font styles and sizes.  The printDoc_PrintPage() method hard-codes to 7-point Courier New:
                Font tempFont = new Font("Courier New", 7, FontStyle.Regular); 
SolidBrush tempBrush = new SolidBrush(Color.Black); 
System.Drawing.PointF tempPoint = new System.Drawing.PointF(0, 0);
Simply changing this font (it’s in five places) will spread your text across the page.  Make sure to use a fixed-width font or your receipts won’t line up properly.  You will also have to experiment with the values of the offsets for placing the text (coordinate variables x and y).
Also, a not-so-obvious feature of the Form Layout designer is the ability to change the number of columns in any of the three sections.  Simply right-click on a blank area and select “Number of columns” from the pop-up menu.  Change the value to change the width of your paper.  A lot of trial and error will be needed to match up font size and paper width, but it should give you some options.
Hopefully this gives you a place to start if you need to use a Windows driver to print receipts.  There are limitations to using System.Drawing.Printing for printing; if you’re looking for more flexibility (pre-printed forms, better use of graphics, headers and footers per page, etc.) you may want to look at other options such as third-party controls or report writers.