VB.NET: Printing POS Receipt Directly to Printer

I once discussed printing directly to the printer in the article below:

Indeed the results in the article are still relatively simple, just plain text. That's why now I want to discuss more about direct printing which is often used to print cashier receipts through the POS (Point of Sales) application.

The basic is PrintDocument. If you want to know about it please check this article.
I created 2 classes for supporting printing process. These classes also allow us to print images or logos and arrange fonts as desired. The classes can be downloaded using below link:
Last updated files on 5/26/2020 

Now, I'll show you how to use them. After downloading those 2 files, copy them into your project/solution as below image.


Open your project on Visual Studio, go to solution explorer. Right-click on your project node then choose Add -> Existing item...

Browse and choose files that we need. Those are Printer.vb and PrintingFormat.vb then click Add button.


Files are added and shown on Solution Explorer.
!!! Make sure you added those 2 files to prevent errors !!!

On UI Design we'll only add a button into the Form1. Printing will be triggered by Button1_Click()



Add Imports System.Drawing.Printing on  the top of Form's code.

Imports System.Drawing.Printing

On this article I use dummy data for printing. Creating some variable and a DataTable for saving detail. Please adjust with your own needed.

Dim StoreName As String = "SERBA ADA STORE"
Dim StoreAddress As String = "Jl. Kehidupan No. 100"
Dim Img As Image = Image.FromFile("c:\logo.jpg")
Dim TransNo As String = "TCN10-20191204-001"
Dim TransDate As String = Format(Now, "yyyy-MM-dd HH:mm:ss")

'for item sales | untuk item penjualan
Dim dtItem As DataTable
Dim arrWidth() As Integer
Dim arrFormat() As StringFormat

'declaring printing format class
Dim c As New PrintingFormat

'for subtotal & qty total
Dim dblSubtotal As Double = 0
Dim dblQty As Double = 0
Dim dblPayment As Double = 50000

DataTable is used to save sales items. I'll fill it manually under Data_Load procedure.

Sub Data_Load()
    dtItem = New DataTable
    With dtItem.Columns
        .Add("itemname", Type.GetType("System.String"))
        .Add("qty", Type.GetType("System.String"))
        .Add("price", Type.GetType("System.String"))
    End With

    Dim ItemRow As DataRow

    ItemRow = dtItem.NewRow()
    ItemRow("itemname") = "Taro Snack"
    ItemRow("qty") = "1"
    ItemRow("price") = "5000"
    dtItem.Rows.Add(ItemRow)

    ItemRow = dtItem.NewRow()
    ItemRow("itemname") = "Kopi Ice"
    ItemRow("qty") = "2"
    ItemRow("price") = "7000"
    dtItem.Rows.Add(ItemRow)

    ItemRow = dtItem.NewRow()
    ItemRow("itemname") = "Lolipop"
    ItemRow("qty") = "5"
    ItemRow("price") = "1000"
    dtItem.Rows.Add(ItemRow)

End Sub

And code sample of using Printer class will be described on below sample code under button1_click event:

Private Sub Button1_Click(sender As Object, e As EventArgs) _
        Handles Button1.Click

    Data_Load()

    Printer.NewPrint()

    Printer.Print(Img, 200, 100)

    'Setting Font
    Printer.SetFont("Courier New", 11, FontStyle.Bold)
    Printer.Print(StoreName) 'Store Name | Nama Toko

    'Setting Font
    Printer.SetFont("Courier New", 8, FontStyle.Regular)
    Printer.Print(StoreAddress & ";", {280}, 0) 'Store Address | Alamat Toko

    'spacing
    Printer.Print(" ")

    Printer.Print(TransNo) ' Transaction No | Nomor transaksi
    Printer.Print(TransDate) ' Trans Date | Tanggal transaksi

    Printer.Print(" ") 'spacing
    Printer.SetFont("Courier New", 8, FontStyle.Bold) 'Setting Font
    arrWidth = {90, 40, 50, 70} 'array for column width | array untuk lebar kolom
    arrFormat = {c.MidLeft, c.MidRight, c.MidRight, c.MidRight} 'array alignment 

    'column header split by ; | nama kolom dipisah dengan ;
    Printer.Print("item;qty;price;subtotal", arrWidth, arrFormat)
    Printer.SetFont("Courier New", 8, FontStyle.Regular) 'Setting Font
    Printer.Print("------------------------------------"'line

    dblSubtotal = 0
    dblQty = 0
    'looping item sales | loop item penjualan
    For r = 0 To dtItem.Rows.Count - 1
        Printer.Print(dtItem.Rows(r).Item("itemname") & ";" & _
                      dtItem.Rows(r).Item("qty") & ";" & _
                      dtItem.Rows(r).Item("price") & ";" & _
                     (dtItem.Rows(r).Item("qty") * _
                      dtItem.Rows(r).Item("price")), arrWidth, arrFormat)
        dblQty = dblQty + CSng(dtItem.Rows(r).Item("qty"))
        dblSubtotal = dblSubtotal + (dtItem.Rows(r).Item("qty") * dtItem.Rows(r).Item("price"))
    Next

    Printer.Print("------------------------------------")
    arrWidth = {130, 120} 'array for column width | array untuk lebar kolom
    arrFormat = {c.MidLeft, c.MidRight} 'array alignment 

    Printer.Print("Total;" & dblSubtotal, arrWidth, arrFormat)
    Printer.Print("Payment;" & dblPayment, arrWidth, arrFormat)
    Printer.Print("------------------------------------")
    Printer.Print("Change;" & dblPayment - dblSubtotal, arrWidth, arrFormat)
    Printer.Print(" ")
    Printer.Print("Item Qty;" & dblQty, arrWidth, arrFormat)

    'Release the job for actual printing
    Printer.DoPrint()

End Sub

Full code:


Let's run and print.


Printing result (I'm using pdf printer)



Okay, I made a mistake while updating file for bug fix. So, As my apologize please download the full source code below. I wrote it using VS2015. 

Post a Comment

21 Comments

Sanby Condz said…
Sir? How about using MySQL Workbench as the Load data?
Thank You sir for the reply.
rani said…
you can load your mysql data into datatable. it's depending how you connect to your mysql database.
Abhay said…
Thank you so much for your post, Its a great help.

I am trying to create a project which will use Epson TM U220 and would like the printer font to be used as It will be fast and not send font from the code. Can you help me with how to tweak the code.
rani said…
just remove the font setting on code and font will be set to default from printer setting.
Abhay said…
Thank you for reply, Will try the same and appreciate your blog post which helped me a lot.
Unknown said…
Hello Sir,

How can I adjust the width of the print area to taker up a whole receipt? 80mm> Currently it's only using about 75% of the usable width of the paper.

Also, how can I reduce white space at the top and bottom of the receipt. When printing, there is roughly 4 inches of blank space at the top and about 10 inches of white space at the bottom.
rani said…
For width we need to set each object of a row for e.g the image:
Printer.Print(Img, 200, 100) '-- 200 is width

or for table layout
arrWidth = {90, 40, 50, 70} 'array for column width
Printer.Print("item;qty;price;subtotal", arrWidth, arrFormat)

each column set by the array value.

For paper/page size I use default setting from printer, because here we're targeting mini printer for POS that has continous paper and also has special setting. Please check your printer setting otherwise you have to modify PageSettings in printer class.
vmc said…
Hello sir
Does this has a C# version .. can you post the link
Unknown said…
hello sir...
how to limit or cut item character when character exceed the limit on arrWidth...
thanks
rani said…
Actually it was designed to be wordwrap.
But if you want to limit just use the Left string as below:
Dim str As String = "Ultra Milk UHT 100 ml plain low fat"
str = Microsoft.VisualBasic.Left(str, 10)
Johan said…
Thanks for sharing, how can i reduce spacing between each line? Because right now is to much space between each line? Thanks
rani said…
@johan: I think you need to modify the printingformat.vb file. In "function PrintCellText", you could do trial/error by modifying cellRect.Size.
JElectronics said…
how can it be changed where it doesnt print to the default printer
rani said…
@JElectronics:
Try to change code in Printer.vb
On SUb DoPrint as below:
Public Shared Sub DoPrint()
prn.PrinterSettings.PrinterName = "doPDF 7"
prn.Print()
End Sub

"doPDF 7" is a printer name, change it to yours.
naushad said…
Sir how to logo Center for receipts
shehan said…
Center shop name :

arrWidth = {250}
arrFormat = {c.MidCenter}
Printer.Print("Your Text", arrWidth, arrFormat)
Sulaeman said…
This comment has been removed by the author.
Sulaeman said…
Can this be used for all POS printers? and I see in your code there is nothing to preview.
RN said…
how to save to txt file ??