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.javato compile. java NetworkReceiptPrinterQrcode- If it does not work, try commenting out the command to select the model and removing “model” from the
commandSequencearray.
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) {
HashMap commands = 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 Map commands = 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;
}
}
}

