How to print custom currency symbols on a receipt printer

Most receipt printers have a font that contains a ‘$’ sign, and many have settings to print ‘£’ ‘¥’ and ‘€’. However, I don’t know of any that can display the Bitcoin ‘₿’ or Indian Rupee ‘₹’ symbols yet.

I recently answered a question about displaying inline images on receipts from PHP, and I think this would be the best way to output newer currency codes at the moment.

Based on that answer, I used an Epson TM-T20, which understands the ESC/POS page description language, and extended the escpos-php library to list prices on a receipt in Bitcoin.

Option 1: Use an inline image

Start with a 16×24 picture of your custom character. I traced the Font Awesome fa-btc icon:

I then extended escpos-php to issue the ESC * command without breaking the line, and injected this picture like so:

<?php
require __DIR__ . '/autoload.php';
use Mike42\Escpos\Printer;
use Mike42\Escpos\EscposImage;
use Mike42\Escpos\PrintConnectors\FilePrintConnector;

class CustomPrinter extends Mike42\Escpos\Printer {

    // Print image inline. If it is a multi-line image, then only the first line is printed!
    public function inlineImage(EscposImage $img, $size = Printer::IMG_DEFAULT)
    {
        $highDensityVertical = ! (($size & self::IMG_DOUBLE_HEIGHT) == Printer::IMG_DOUBLE_HEIGHT);
        $highDensityHorizontal = ! (($size & self::IMG_DOUBLE_WIDTH) == Printer::IMG_DOUBLE_WIDTH);
        // Header and density code (0, 1, 32, 33) re-used for every line
        $densityCode = ($highDensityHorizontal ? 1 : 0) + ($highDensityVertical ? 32 : 0);
        $colFormatData = $img -> toColumnFormat($highDensityVertical);
        $header = Printer::dataHeader(array($img -> getWidth()), true);
        foreach ($colFormatData as $line) {
            // Print each line, double density etc for printing are set here also
            $this -> connector -> write(self::ESC . "*" . chr($densityCode) . $header . $line);
            break;
        }
    }
}

/* Fill in your own connector here */
$connector = new FilePrintConnector("php://stdout");
$printer = new CustomPrinter($connector);

$btc = EscposImage::load("btc.png");

$printer -> text("Item    ");
$printer -> inlineImage($btc);
$printer -> text("2.50\n");

$printer -> cut();
$printer -> close();

The result was:

If you just have a few custom character to print, then this clearly works. Unfortunately, you can’t use text formatting commands alongside this method.

Option 2: Use a custom character set

This is a more complex method, where we will instruct the printer to use a BTC symbol in place of a dollar sign, through a custom character.

You must use a 12×24 image for this method, which is the standard size of the receipt printer font for most Epson models:

The example code now changes to include the ESC % and ESC % commands:

<?php
require __DIR__ . '/autoload.php';
use Mike42\Escpos\Printer;
use Mike42\Escpos\EscposImage;
use Mike42\Escpos\PrintConnectors\FilePrintConnector;

class MyCoolPrinter extends Mike42\Escpos\Printer {

    public function setUserDefinedCharacter(EscposImage $img, $char)
    {
        $verticalBytes = 3;
        $colFormatData = $img -> toColumnFormat(true);
        foreach ($colFormatData as $line) {
            // Print each line, double density etc for printing are set here also
            $this -> connector -> write(self::ESC . "&" . chr($verticalBytes) . $char . $char . chr($img -> getWidth()) . $line);
            break;
        }
    }

    public function selectUserDefinedCharacterSet($on = true)
    {
        self::validateBoolean($on, __FUNCTION__);
        $this -> connector -> write(self::ESC . "%". ($on ? chr(1) : chr(0)));
    }
}

/* Fill in your own connector here */
$connector = new FilePrintConnector("php://stdout");
$printer = new MyCoolPrinter($connector);

// Replace '$' with a 24x12 image.
$char = EscposImage::load("btc2.png");
$printer -> setUserDefinedCharacter($char, "$");
$printer -> selectUserDefinedCharacterSet(true);

// Print some stuff normally
$printer -> text("Item    $2.50\n");

$printer -> cut();
$printer -> close();

Which produces this output:

The difference here is that you can also apply text formatting commands to these characters, such as double-height or emphasis:

// ... Add to the end of the previous example

// Print some stuff normally
$printer -> text("Item    $2.50\n");

// Go taller!
$printer -> selectPrintMode(Printer::MODE_DOUBLE_HEIGHT);
$printer -> text("Item    $2.50\n");

// Emphasis too?
$printer -> selectPrintMode(Printer::MODE_DOUBLE_HEIGHT | Printer::MODE_EMPHASIZED);
$printer -> text("Item    $2.50\n");

// Adjust height and width
for ($i = 1; $i <= 8; $i++) {
    $printer -> setTextSize($i, $i);
    $printer -> text("$");
}
$printer -> text("\n");

$printer -> cut();
$printer -> close();

Both of these methods let us encode arbitrary characters that we couldn’t otherwise be able to print- all we need is bitmaps for each character.

There is no plan to include bitmap fonts with escpos-php at the moment, but this basic mechanism might be used to improve Unicode support for a lot of receipt printers in the future.

Update 2018-03-11: I added the custom character set option to this post.

Leave a Reply

Your email address will not be published. Required fields are marked *