I'm trying to print an image of 576 pixels width in a thermal printer that supports ESC commands, the problem is that the command "ESC *" for printing image bits only let me print images of 255 pixels width (if i use a 576 pixels image some parts are printed and the rest are random symbols), in the documentacion saids that the commands accepts a max of 255 bytes like this:
ESC * m nL nH d1Ödk
Name Specify bit image mode
Code ASCII ESC * m nL nHd1...dk
Hex. 1B 2A m nL nHd1...dk
Decimal 27 42 m nL nHd1...dk
Defined Region m = 0,1,32,33
0 ≤ nL ≤ 255
0 ≤ nH ≤ 3
0 ≤ d ≤ 255
So i don't know how to print a image that is the max of width of the printer page (576 px), i have this code that prints the image:
public class ESCPOSApi {
private final byte[] INITIALIZE_PRINTER = new byte[]{0x1B,0x40};
private final byte[] PRINT_AND_FEED_PAPER = new byte[]{0x0A};
private final byte[] SELECT_BIT_IMAGE_MODE = new byte[]{(byte)0x1B, (byte)0x2A};
private final byte[] SET_LINE_SPACING = new byte[]{0x1B, 0x33};
private FileOutputStream printOutput;
public int maxBitsWidth = 255;
public ESCPOSApi(String device) {
try {
printOutput = new FileOutputStream(device);
} catch (FileNotFoundException ex) {
Logger.getLogger(ESCPOSApi.class.getName()).log(Level.SEVERE, null, ex);
}
}
private byte[] buildPOSCommand(byte[] command, byte... args) {
byte[] posCommand = new byte[command.length + args.length];
System.arraycopy(command, 0, posCommand, 0, command.length);
System.arraycopy(args, 0, posCommand, command.length, args.length);
return posCommand;
}
private BitSet getBitsImageData(BufferedImage image) {
int threshold = 127;
int index = 0;
int dimenssions = image.getWidth() * image.getHeight();
BitSet imageBitsData = new BitSet(dimenssions);
for (int y = 0; y < image.getHeight(); y++)
{
for (int x = 0; x < image.getWidth(); x++)
{
int color = image.getRGB(x, y);
int red = (color & 0x00ff0000) >> 16;
int green = (color & 0x0000ff00) >> 8;
int blue = color & 0x000000ff;
int luminance = (int)(red * 0.3 + green * 0.59 + blue * 0.11);
//dots[index] = (luminance < threshold);
imageBitsData.set(index, (luminance < threshold));
index++;
}
}
return imageBitsData;
}
public void printImage(BufferedImage image) {
try {
BitSet imageBits = getBitsImageData(image);
byte widthLSB = (byte)(image.getWidth() & 0xFF);
byte widthMSB = (byte)((image.getWidth() >> 16) & 0xFF);
// COMMANDS
byte[] selectBitImageModeCommand = buildPOSCommand(SELECT_BIT_IMAGE_MODE, (byte) 33, widthLSB, widthMSB);
byte[] setLineSpacing24Dots = buildPOSCommand(SET_LINE_SPACING, (byte) 24);
byte[] setLineSpacing30Dots = buildPOSCommand(SET_LINE_SPACING, (byte) 30);
printOutput.write(INITIALIZE_PRINTER);
printOutput.write(setLineSpacing24Dots);
int offset = 0;
while (offset < image.getHeight()) {
printOutput.write(selectBitImageModeCommand);
int imageDataLineIndex = 0;
byte[] imageDataLine = new byte[3 * image.getWidth()];
for (int x = 0; x < image.getWidth(); ++x) {
// Remember, 24 dots = 24 bits = 3 bytes.
// The 'k' variable keeps track of which of those
// three bytes that we're currently scribbling into.
for (int k = 0; k < 3; ++k) {
byte slice = 0;
// A byte is 8 bits. The 'b' variable keeps track
// of which bit in the byte we're recording.
for (int b = 0; b < 8; ++b) {
// Calculate the y position that we're currently
// trying to draw. We take our offset, divide it
// by 8 so we're talking about the y offset in
// terms of bytes, add our current 'k' byte
// offset to that, multiple by 8 to get it in terms
// of bits again, and add our bit offset to it.
int y = (((offset / 8) + k) * 8) + b;
// Calculate the location of the pixel we want in the bit array.
// It'll be at (y * width) + x.
int i = (y * image.getWidth()) + x;
// If the image (or this stripe of the image)
// is shorter than 24 dots, pad with zero.
boolean v = false;
if (i < imageBits.length()) {
v = imageBits.get(i);
}
// Finally, store our bit in the byte that we're currently
// scribbling to. Our current 'b' is actually the exact
// opposite of where we want it to be in the byte, so
// subtract it from 7, shift our bit into place in a temp
// byte, and OR it with the target byte to get it into there.
slice |= (byte) ((v ? 1 : 0) << (7 - b));
}
imageDataLine[imageDataLineIndex + k] = slice;
// Phew! Write the damn byte to the buffer
//printOutput.write(slice);
}
imageDataLineIndex += 3;
}
printOutput.write(imageDataLine);
offset += 24;
printOutput.write(PRINT_AND_FEED_PAPER);
}
printOutput.write(setLineSpacing30Dots);
} catch (IOException ex) {
Logger.getLogger(ESCPOSApi.class
.getName()).log(Level.SEVERE, null, ex);
}
}
}
I want to use 24-dots double-density but for now i'm using 24-dots sigle-density with images of 255 pixels (this let me print images in full page width but i need double density)
But because of that, the bitmap can be represented as an array of bits, where 1 means black dot and 0 means blank dot. The printer's datasheet defines a couple of different mechanisms for printing bitmaps.
A better way is to raster the image pixel by pixel using ESC/POS, the native command language of the printer. Being a thermal printer, there is no concept of color, nor gray scale; either the pixel is burned or not burned, black or white. This is a very important concept to have in mind.
Print a bitmap full page. Printing a bitmap isn't very difficult to do. I saw several solutions which used creation of DIB sections and quite some code. The trick here is to use the " LoadImage " API which can do that for you. This code uses portions of Chris Maunder's printing article:
In this example, we get the image in an array of pixels in the following order [px0, px1, ..., pxw, ..., px8w], but the "same" data must be sent the printer in another order: [d0, d1, d2, ..., d k]. Like I said before, there is no concept of color in thermal printing, either the pixel is burn or is not.
In the code above,
image.getWidth() >> 16 --- should be ">> 8". 8-bits per byte.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With