I’ve been working on software that interacts with ESC/POS receipt printers for some time, and a constant source of trouble is the archaic character encoding scheme used on these printers.
Most commonly, non-ASCII characters are accessed by swapping the extended range to a different 128-character code page. The main open source drivers (escpos-php and python-escpos) are both capable of auto-selecting an encoding, but they need a good database of known encodings to power this feature for each individual printer.
Today, I’ll share a small utility that can print out the contents of a code page, like this:
A printer’s documentation vaguely labeled this encoding as “[1] Katakana”. By printing it out, I can see that if I map single-byte half-width Katakana from Code Page 932, it will appear correctly in this code page. That’s type of information you need when you’re asked about it on an issue tracker!
Usage
You will generally find a list of code pages with a corresponding number for each one (0-255) in an ESC/POS printer’s documentation.
This command-line tool then takes a list of code pages to inspect, and will output raw binary that generates a table like the one above when sent to the printer:
php escpos-caracter-table.php NUMBER ...
So to print the code pages 1, 2 and 3 to a binary file, the command would be:
php escpos-character-tables.php 1 2 3 > code-page-1.bin
Next, you need to know how to do raw printing. Raw USB printing on Linux typically works like this:
cat code-page-1.bin > /dev/usb/lp0
For other platforms, it will be different! You will need to do a bit of research on raw printing for your platform if you haven’t tried it before.
The code: escpos-character-tables.php
<?php
/**
* This standalone script can be used to print the contents of a code page
* for troubleshooting.
*
* Usage: php escpos-caracter-table.php NUMBER ...
*
* Code pages are numbered 0-255.
*
* The ESC/POS binary will be send to stdout, and should be redirected to a
* file or printer:
*
* php escpos-caracter-table.php 20 > /dev/usb/lp0
*
* @author Michael Billington < michael.billington@gmail.com >
* @license MIT
*/
/* Sanity check */
if(php_sapi_name() !== "cli") {
die("This is a command-line script, invoke via php.exen");
}
if(count($argv) < 2) {
die("At least one code page number must be specifiedn");
}
array_shift($argv);
foreach($argv as $codePage) {
if(!is_numeric($codePage) || $codePage < 0 || $codePage > 255) {
die("Code pages must be numbered 0-255");
}
}
/* Reset */
$str = "\x1b@";
foreach($argv as $codePage) {
/* Print header, switch code page */
$str .= "\x1bt" . chr($codePage);
$str .= "\x1bE\x01Code page $codePage\x1bE\x00\n";
$str .= "\x1bE\x01 0123456789ABCDEF0123456789ABCDEF\x1bE\x00\n";
$chars = str_repeat(' ', 128);
for ($i = 0; $i < 128; $i++) {
$chars[$i] = chr($i + 128);
}
for ($y = 0; $y < 4; $y++) {
$row = "" . " ";
$rowHeader = "\x1bE\x01" . strtoupper(dechex($y + 8)) . "\x1bE\x00";
$row = substr($chars, $y * 32, 32);
$str .= "$rowHeader $row\n";
}
}
/* Cut */
$str .= "\x1dV\x41\x03";
/* Output to STDOUT */
file_put_contents("php://stdout", $str);