This afternoon, @Joseinnewworld handpicked 5 #NFTs from our #NFTCollection — like a pro selecting the finest fruits from the market 😄🍇 Always appreciate your sharp taste and steady support, legend 🙌 #eCash $XEC #NFTCommunity #NFTCollectors #NFTDROPS #Crypto #CryptoTrading pic.twitter.com/XsyPX95QyF
— NFToa (@nftoa_) August 15, 2025
Hi Dev, recently I was struggling to face the challenge given by the client, why? because I was asked to create a solution for printing images on a thermal printer. Okay, I thought it was easy, as easy as printing text, but it turned out not. So, my assumption so far was wrong if I followed the plain text path, which changed it to ByteArray, it turned out not to be that easy ferguso.
As an illustration, here is my experiment to approach the search for a solution.
First, let's say I have some text input that I need to print.
String message="abcdef any message 12345";
byte[] send;
send = message.getBytes();
mService.write(send);Okay, the code above works fine for text printing tasks, but it goes wrong if I replace the input ByteArray with the image's ByteArray, this is roughly how I do it.
Bitmap bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.qrcode);
ByteArrayOutputStream stream=new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 90, stream);
byte[] image=stream.toByteArray();Unfortunately, what happens instead is that the print appears like unclear characters that are not readable, and if I leave it, the print length can reach 50 cm.
Okay, after wasting a lot of time just to solve the problem of printing images on a thermal printer, I finally changed my overly simple method to a fairly complicated one. Hopefully this will work on your type/model of thermal printer!
I created a general function that needs to include a string type image file parameter, which is intended to put the image path / image location address in local storage.
private void printImage(String file) {
File fl = new File(file);
if (fl.exists()) {
Bitmap bmp = BitmapFactory.decodeFile(file);
convertBitmap(bmp);
mService.write(PrinterCommands.SET_LINE_SPACING_24);
int offset = 0;
while (offset < bmp.getHeight()) {
mService.write(PrinterCommands.SELECT_BIT_IMAGE_MODE);
for (int x = 0; x < bmp.getWidth(); ++x) {
for (int k = 0; k < 3; ++k) {
byte slice = 0;
for (int b = 0; b < 8; ++b) {
int y = (((offset / 8) + k) * 8) + b;
int i = (y * bmp.getWidth()) + x;
boolean v = false;
if (i < dots.length()) {
v = dots.get(i);
}
slice |= (byte) ((v ? 1 : 0) << (7 - b));
}
mService.write(slice);
}
}
offset += 24;
mService.write(PrinterCommands.FEED_LINE);
mService.write(PrinterCommands.FEED_LINE);
mService.write(PrinterCommands.FEED_LINE);
mService.write(PrinterCommands.FEED_LINE);
mService.write(PrinterCommands.FEED_LINE);
mService.write(PrinterCommands.FEED_LINE);
}
mService.write(PrinterCommands.SET_LINE_SPACING_30);
} else {
Toast.makeText(this, "file doesn't exists", Toast.LENGTH_SHORT)
.show();
}
}If you notice, in the service I call a static variable defined in the PrinterCommands class, the variable contains the standard ESC/POS instruction , which is an instruction recognized by a thermal printer, so that's how we can communicate with the device.
public class PrinterCommands {
public static final byte[] INIT = {27, 64};
public static byte[] FEED_LINE = {10};
public static byte[] SELECT_FONT_A = {27, 33, 0};
public static byte[] SET_BAR_CODE_HEIGHT = {29, 104, 100};
public static byte[] PRINT_BAR_CODE_1 = {29, 107, 2};
public static byte[] SEND_NULL_BYTE = {0x00};
public static byte[] SELECT_PRINT_SHEET = {0x1B, 0x63, 0x30, 0x02};
public static byte[] FEED_PAPER_AND_CUT = {0x1D, 0x56, 66, 0x00};
public static byte[] SELECT_CYRILLIC_CHARACTER_CODE_TABLE = {0x1B, 0x74, 0x11};
public static byte[] SELECT_BIT_IMAGE_MODE = {0x1B, 0x2A, 33, -128, 0};
public static byte[] SET_LINE_SPACING_24 = {0x1B, 0x33, 24};
public static byte[] SET_LINE_SPACING_30 = {0x1B, 0x33, 30};
public static byte[] TRANSMIT_DLE_PRINTER_STATUS = {0x10, 0x04, 0x01};
public static byte[] TRANSMIT_DLE_OFFLINE_PRINTER_STATUS = {0x10, 0x04, 0x02};
public static byte[] TRANSMIT_DLE_ERROR_STATUS = {0x10, 0x04, 0x03};
public static byte[] TRANSMIT_DLE_ROLL_PAPER_SENSOR_STATUS = {0x10, 0x04, 0x04};
}The conclusion is, I save the image in local storage, then take the path (image file location address) in a string, then I use that path to call the function. printImage(String file)
If there are still some of you who can't grasp the concept or how it works, then please observe the following project first .
Good luck!
3rd Party Alternative
- https://github.com/anastaciocintra/escpos-coffee
