For more information on the ESC/POS command set which receipt printers use for printing, see What is ESC/POS and How Do I Use It by Michael Billington, also the author of the excellent escpos-php PHP library for receipt printers.
Thanks to this StackOverflow post as well: printing QR codes through an ESC/POS thermal printer? 🙂
Steps to run:
- Save the code below as
NetworkReceiptPrinterQrcode.java
– change QR code content and printer IP accordingly. - Run
javac NetworkReceiptPrinterQrcode.java
to compile. java NetworkReceiptPrinterQrcode
- If it does not work, try commenting out the command to select the model and removing “model” from the
commandSequence
array.
import java.io.*; import java.net.*; import java.util.HashMap; /** * Print QR Code to network receipt printer */ class NetworkReceiptPrinterQrcode { public static void main(String argv[]) throws Exception { String content = "Test Content"; String printerIp = "192.168.1.123"; int printerPort = 9100; try { Socket socket = new Socket(printerIp, printerPort); DataOutputStream out = new DataOutputStream(socket.getOutputStream()); DataInputStream in; byte[] byteArray = qrCode(content); in = new DataInputStream(new ByteArrayInputStream(byteArray)); while (in.available() != 0) { out.write(in.readByte()); } out.writeByte(0x00); out.flush(); out.close(); in.close(); socket.close(); } catch (Exception e) { e.printStackTrace(); } } /** * Compute bytes for printing QR code * * @link Adapted from https://stackoverflow.com/questions/23577702/printing-qr-codes-through-an-esc-pos-thermal-printer/#29221432 * @param content Contents of QR code * @return Bytes for command to send to printer */ public static byte[] qrCode(String content) { HashMapcommands = new HashMap (); String[] commandSequence = {"model", "size", "error", "store", "content", "print"}; int contentLen = content.length(); int resultLen = 0; byte[] command; // QR Code: Select the model // Hex 1D 28 6B 04 00 31 41 n1(x32) n2(x00) - size of model // set n1 [49 x31, model 1] [50 x32, model 2] [51 x33, micro qr code] // https://reference.epson-biz.com/modules/ref_escpos/index.php?content_id=140 command = new byte[]{(byte) 0x1d, (byte) 0x28, (byte) 0x6b, (byte) 0x04, (byte) 0x00, (byte) 0x31, (byte) 0x41, (byte) 0x32, (byte) 0x00}; commands.put("model", command); resultLen += command.length; // QR Code: Set the size of module // Hex 1D 28 6B 03 00 31 43 n // n depends on the printer // https://reference.epson-biz.com/modules/ref_escpos/index.php?content_id=141 command = new byte[]{(byte) 0x1d, (byte) 0x28, (byte) 0x6b, (byte) 0x03, (byte) 0x00, (byte) 0x31, (byte) 0x43, (byte) 0x06}; commands.put("size", command); resultLen += command.length; // Hex 1D 28 6B 03 00 31 45 n // Set n for error correction [48 x30 -> 7%] [49 x31-> 15%] [50 x32 -> 25%] [51 x33 -> 30%] // https://reference.epson-biz.com/modules/ref_escpos/index.php?content_id=142 command = new byte[]{(byte) 0x1d, (byte) 0x28, (byte) 0x6b, (byte) 0x03, (byte) 0x00, (byte) 0x31, (byte) 0x45, (byte) 0x33}; commands.put("error", command); resultLen += command.length; // QR Code: Store the data in the symbol storage area // Hex 1D 28 6B pL pH 31 50 30 d1...dk // https://reference.epson-biz.com/modules/ref_escpos/index.php?content_id=143 // 1D 28 6B pL pH cn(49->x31) fn(80->x50) m(48->x30) d1…dk int storeLen = contentLen + 3; byte store_pL = (byte) (storeLen % 256); byte store_pH = (byte) (storeLen / 256); command = new byte[]{(byte) 0x1d, (byte) 0x28, (byte) 0x6b, store_pL, store_pH, (byte) 0x31, (byte) 0x50, (byte) 0x30}; commands.put("store", command); resultLen += command.length; // QR Code content command = content.getBytes(); commands.put("content", command); resultLen += command.length; // QR Code: Print the symbol data in the symbol storage area // Hex 1D 28 6B 03 00 31 51 m // https://reference.epson-biz.com/modules/ref_escpos/index.php?content_id=144 command = new byte[]{(byte) 0x1d, (byte) 0x28, (byte) 0x6b, (byte) 0x03, (byte) 0x00, (byte) 0x31, (byte) 0x51, (byte) 0x30}; commands.put("print", command); resultLen += command.length; int cnt = 0; int commandLen = 0; byte[] result = new byte[resultLen]; for (String currCommand : commandSequence) { command = (byte[]) commands.get(currCommand); commandLen = command.length; System.arraycopy(command, 0, result, cnt, commandLen); cnt += commandLen; } return result; } }
[UPDATE 23 JUL 2016]
A friend commented that there was room for refactoring. Replied that I have not touched Java for 15 years and was trying to stick to pure Java, i.e. no external libraries, as I was doing the code as a demo for my Android developer lol. He later sent me a sample of the refactored code, reproduced below. Thanks, Jun Kwang!
import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.Socket; import java.util.Arrays; import java.util.EnumMap; import java.util.Map; public class QrCodePrinterRefactored { public static void main(String args[]) { String content = "Test Content"; String printerIp = "192.168.1.123"; int printerPort = 9100; try ( Socket socket = new Socket(printerIp, printerPort); DataInputStream in = new DataInputStream(new ByteArrayInputStream(toQrCode(content))); DataOutputStream out = new DataOutputStream(socket.getOutputStream()) ) { while (in.available() != 0) { out.write(in.readByte()); } out.writeByte(0x00); } catch (IOException e) { throw new RuntimeException(e); } } /** * Compute bytes for printing QR code. * * @link Adapted from https://stackoverflow.com/questions/23577702/printing-qr-codes-through-an-esc-pos-thermal-printer/#29221432 * @param content Contents of QR code * @return Bytes for command to send to printer */ public static byte[] toQrCode(String content) { return QrCodeBuilder.create() .withModel((byte) 0x32, (byte) 0x00) .withSize((byte) 0x06) .withErrorCorrection((byte) 0x33) .withContent(content, (byte) 0x30) .toBytes(); } enum QrCommand { MODEL, SIZE, ERROR_CORRECTION, STORE, CONTENT, PRINT } private static final class QrCodeBuilder { private final Mapcommands = new EnumMap<>(QrCommand.class); private QrCodeBuilder() { // empty } /** * Creates a new builder. * * @return a builder */ public static QrCodeBuilder create() { return new QrCodeBuilder(); } /** * Generates a {@code byte[]} array appended with the two {@code byte} arguments. * * @param penultimate the penultimate byte * @param last the last byte * @return a {@code byte[]} array starting with (@code 0x1d 0x28 0x6b 0x03 0x00 0x31) */ private static byte[] append(byte penultimate, byte last) { return new byte[]{0x1d, 0x28, 0x6b, 0x03, 0x00, 0x31, penultimate, last}; } /** * Sets the model with the following bytes: {@code 0x1d 0x28 0x6b 0x04 0x00 0x31 0x41 n1(x32) n2(x00)}. * * @param model [49 x31, model 1] [50 x32, model 2] [51 x33, micro qr code] * @param size (x00 size of model) * @return this builder */ public QrCodeBuilder withModel(byte model, byte size) { commands.put(QrCommand.MODEL, new byte[]{0x1d, 0x28, 0x6b, 0x04, 0x00, 0x31, 0x41, model, size}); return this; } /** * Sets the size with the following bytes: {@code 0x1d 0x28 0x6b 0x03 0x00 0x31 0x43 n}. * * @param size depends on the printer * @return this builder */ public QrCodeBuilder withSize(byte size) { commands.put(QrCommand.SIZE, append((byte) 0x43, size)); return this; } /** * Sets the error correction with the following bytes: {@code 0x1d 0x28 0x6b 0x03 0x00 0x31 0x43 n}. * * @param errorCorrection [48 x30 -> 7%] [49 x31-> 15%] [50 x32 -> 25%] [51 x33 -> 30%] * @return this builder */ public QrCodeBuilder withErrorCorrection(byte errorCorrection) { commands.put(QrCommand.ERROR_CORRECTION, append((byte) 0x45, errorCorrection)); return this; } /** * Sets the content. * * @param content the content to set * @param print the print byte * @return this builder */ public QrCodeBuilder withContent(String content, byte print) { // QR Code: Store the data in the symbol storage area // Hex 1D 28 6B pL pH 31 50 30 d1...dk // https://reference.epson-biz.com/modules/ref_escpos/index.php?content_id=143 // 1D 28 6B pL pH cn(49->x31) fn(80->x50) m(48->x30) d1...dk int contentLength = content.length() + 3; byte length = (byte) (contentLength % 256); byte height = (byte) (contentLength / 256); commands.put(QrCommand.STORE, new byte[]{0x1d, 0x28, 0x6b, length, height, 0x31, 0x50, print}); commands.put(QrCommand.CONTENT, content.getBytes()); commands.put(QrCommand.PRINT, append((byte) 0x51, print)); return this; } public byte[] toBytes() { if (commands.size() != QrCommand.values().length) { throw new IllegalStateException("Not all commands given."); } byte[] result = new byte[0]; for (byte[] current : commands.values()) { result = Arrays.copyOf(result, result.length + current.length); System.arraycopy(current, 0, result, result.length, current.length); } return result; } } }