How to Print Receipts With TSPL and JavaScript

Written by altynberg | Published 2022/12/20
Tech Story Tags: label-printer | tspl | javascript | nodejs | thermal-printer | guide | tutorial | print-receipts-with-tspl

TLDRGenerally, receipt printers use language like ESC/POS. One of the differences between TSPL and ESC/POS is we need to set the size of the receipt while printing. So when we build a receipt with the commands like TEXT, BARCODE, and BITMAP we need to calculate the height of the receipt according to the items that we have.via the TL;DR App

If you want to know more about printing labels using TSPL commands, then you can check my previous articles:

But we can also print receipts using the same TSPL commands and use the same printer as a receipt and label printer. Some of our customers from “Alto’s POS & Inventory” asked us if they can use their label printer as a receipt printer. So, we implemented this feature, and I wanted to share what should be considered while switching between these two modes.

Height of the receipt

We use label rolls to print labels and continuous paper rolls for receipts.

In the beginning, we can set the size and print multiple labels. This won’t be an issue because every label at the label roll has the same size. But the situation is different when printing receipts because every receipt can have a different height.

Generally, receipt printers use language like ESC/POS. One of the differences between TSPL and ESC/POS is we need to set the size of the receipt while printing. So when we build a receipt with the commands like TEXTBARCODE, and BITMAP we need to calculate the height of the receipt according to the items that we have.

We manually specify the height of the items like barcode and bitmap so we already know their height, but we should calculate the text height according to the font that we use. Let’s see what the text command looks like:

TEXT x,y,“font”,rotation,x-multiplication,y-multiplication,[alignment,] “content”

Every “font” has a different size:

1: 8 x 12 fixed pitch dot font

2: 12 x 20 fixed pitch dot font

3: 16 x 24 fixed pitch dot font

4: 24 x 32 fixed pitch dot font

5: 32 x 48 dot fixed pitch font

6: 14 x 19 dot fixed pitch font OCR-B

7: 21 x 27 dot fixed pitch font OCR-B

8: 14 x25 dot fixed pitch font OCR-A

So if the receipt contains a single text like this:

TEXT 10,10,"2",0,1,1,"FONT 2"

Then the receipt height should be:

y + [font height]*[y-multiplication]

10 + 20*1 = 30dots

Reset the printer

Generally, the printer takes the size at the beginning and will use that size for all labels until we manually reset the printer. In another word, if we print a receipt with a height of 100 and then if, we try to print a new receipt with a height of 50, it will continue printing with the height of 100.

To prevent this, we can reset the printer with the command <ESC>!R, and it will use our new size:

<ESC>!R
SIZE 48 mm,25 mm
CLS
TEXT 10,10,"4",0,1,1,"HackerNoon"
BARCODE 10,60,"128",90,1,0,2,2,"altospos.com"
PRINT 1
END

Printing with JavaScript (Node.js)

I created a simple example that prints two receipts with different heights. The first receipt’s height is about 90 dots (including paddings), and with the 203 DPI printer, it will be around 11 mm (learn more). And the second receipt’s height is 21 mm. If we do not reset the printer (<ESC>!R), the second one will also have a height of 11 mm and the remaining part won’t be printed.

const usb = require('usb');

(async function() {
  await print([
    '<ESC>!R',
    'SIZE 80 mm,11 mm',
    'CLS',
    'TEXT 10,10,"4",0,1,1,"HackerNoon"',
    'TEXT 10,47,"1",0,1,1,"Top Stories"',
    'TEXT 10,64,"1",0,1,1,"Programming"',
    'PRINT 1',
    'END',
  ]);

  await print([
    '<ESC>!R',
    'SIZE 80 mm,21 mm',
    'CLS',
    `TEXT 10,10,"4",0,1,1,"Alto's POS & Inventory"`,
    'TEXT 10,50,"2",0,1,1,"Restaurants & Cafes"',
    'TEXT 10,75,"2",0,1,1,"Retail Stores"',
    'TEXT 10,100,"2",0,1,1,"Services"',
    'TEXT 10,125,"1",0,1,1,"https://altospos.com"',
    'PRINT 1',
    'END',
  ]);
})();

function print(cmds) {
  return new Promise(resolve => {
    // you can get all available devices with usb.getDeviceList()
    let device = usb.findByIds(/*vid*/8137, /*pid*/8214);
    device.open();
    const interface = device.interfaces[0];
    interface.claim();
    const outEndpoint = interface.endpoints.find(e => e.direction === 'out');
    outEndpoint.transferType = 2;
    outEndpoint.transfer(Buffer.from(cmds.join('\r\n')), (err) => {
      device.close();
      resolve();
    });
  });
}

I used the ‘usb’ package to connect and send the commands (On Windows, you may need to install a driver, to learn more visit the package’s page).

No War! ✋🏽


Written by altynberg | Software Engineer
Published by HackerNoon on 2022/12/20