I have written a function that takes a canvas scans the horizontal pixel rows from bottom to top to find all the empty lines and trims the canvas height. After trimming I scan through the image data and read pixels into packed bytes representing monochrome image where each bit is a pixel. Afterwards I make a large buffer and at the start put some prefix bytes found in the escpos docs. and at the end of the large buffer I am appending 3 bytes for a cut command.
If I remove the epmtyLines
calculation part, everything works smoothly but as soon as I enable the line trimming logic. The printer actually prints the whole image and but the cut happens 70 to 80 horizontal rows before the end of image. I have reread the trimming logic dozens of times and nothing seems to be wrong.
Note: I am considering the last line of canvas to be empty by default hence starting the loop from height - 2
.
const canvasToEscpos = (canvas) => {
var context = canvas.getContext("2d");
const { data } = context.getImageData(0, 0, canvas.width, canvas.height);
let width = canvas.width;
let height = canvas.height;
let emptyLines = 0;
for (let y = height - 2; y >= 0; y--) {
let empty = true;
for (let x = 0; x < width; x++) {
empty &&= data[(width * y + x) * 4] > 248;
if (!empty) break;
}
if (empty) {
emptyLines++;
} else {
break;
}
}
console.log({ emptyLines });
height -= emptyLines + 1;
const bytes = new Uint8Array((width * height) >> 3);
const readPixel = (x, y) => {
return data[(width * y + x) * 4] < 200 ? 1 : 0;
};
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x += 8) {
for (let b = 0; b < 8; b++) {
bytes[y * (width >> 3) + (x >> 3)] |= readPixel(x + b, y) << (7 - b);
}
}
}
const buffer = new Uint8Array(10 + bytes.length + 3);
// image command
buffer.set(
[
0x0a,
0x0d,
0x1d,
0x76,
0x30,
0x00,
(width >> 3) & 0xff,
((width >> 3) >> 8) & 0xff,
height & 0xff,
(height >> 8) & 0xff,
],
0
);
// image bits
buffer.set(bytes, 10);
// cut
buffer.set([0x1d, 0x56, 0x00], buffer.length - 3);
return buffer;
};
Since there is a gap between the print head of the printer and the paper cutter, if the paper is cut immediately after printing, the printed result will remain on the cut paper for that gap.
GS V
[Name] Select cut mode and cut paper [Format] <Function A> ASCII GS V m Hex 1D 56 m Decimal 29 86 m <Function B> ASCII GS V m n Hex 1D 56 m n Decimal 29 86 m n <Function A> Cuts the paper 0, 48 Full cut 1, 49 Partial cut <Function B> Feeds paper and cuts the paper 65 Full cut 66 Partial cut <Function A> Executes paper cut <Function B> Feeds paper to [cutting position + (n × vertical motion unit)] and executes paper cut
Your program uses the Function A
command on this page to cut the paper, but in order to include all the print results on the cut side, use the Function B
command to set the paper feed amount before cutting to the printer. must be adjusted accordingly.
The distance between the printer's print head and the paper cutter may be different for each printer model, so check the specifications of your printer or adjust it by experiment.
For example, here is an example of paper cutting using EPSON's print data send tool.
Select Cut Mode and Cut Paper