Attempt to reproduce the format of the original bitmap packet

This commit is contained in:
MultiMote 2024-10-20 17:27:19 +03:00
parent 8a62605876
commit a37f8a67de
2 changed files with 69 additions and 35 deletions

@ -153,9 +153,7 @@ export class PacketGenerator {
} }
public static setPrintQuantity(quantity: number): NiimbotPacket { public static setPrintQuantity(quantity: number): NiimbotPacket {
return new NiimbotPacket(RequestCommandId.PrintQuantity, [ return new NiimbotPacket(RequestCommandId.PrintQuantity, [...Utils.u16ToBytes(quantity)]);
...Utils.u16ToBytes(quantity)
]);
} }
public static printStatus(): NiimbotPacket { public static printStatus(): NiimbotPacket {
@ -226,37 +224,51 @@ export class PacketGenerator {
return packet; return packet;
} }
public static printBitmapRow(pos: number, repeats: number, data: Uint8Array): NiimbotPacket { public static printBitmapRow(
const blackPixelCount: number = Utils.countSetBits(data); pos: number,
repeats: number,
data: Uint8Array,
printheadPixels?: number
): NiimbotPacket {
const { total, a, b, c } = Utils.countPixelsForBitmapPacket(data, printheadPixels ?? 0);
// Black pixel count. Not sure what role it plays in printing.
// There is two formats of this part
// 1. <count> <count> <count> (sum must equals number of pixels, every number calculated by algorithm based on printhead resolution)
// 2. <0> <countH> <countL> (big endian)
let header: number[] = [0, ...Utils.u16ToBytes(total)];
if (printheadPixels !== undefined) {
header = [a, b, c];
}
const packet = new NiimbotPacket(RequestCommandId.PrintBitmapRow, [ const packet = new NiimbotPacket(RequestCommandId.PrintBitmapRow, [
...Utils.u16ToBytes(pos), ...Utils.u16ToBytes(pos),
// Black pixel count. Not sure what role it plays in printing. ...header,
// There is two formats of this part
// 1. <count> <count> <count> (sum must equals number of pixels, every number calculated by algorithm based on printhead resolution)
// 2. <0> <countH> <countL> (big endian)
0,
...Utils.u16ToBytes(blackPixelCount),
repeats, repeats,
...data, ...data,
]); ]);
packet.oneWay = true; packet.oneWay = true;
return packet; return packet;
} }
/** Printer powers off if black pixel count > 6 */ /** Printer powers off if black pixel count > 6 */
public static printBitmapRowIndexed(pos: number, repeats: number, data: Uint8Array): NiimbotPacket { // 5555 83 0e 007e 000400 01 0027 0028 0029 002a fa aaaa
const blackPixelCount: number = Utils.countSetBits(data); public static printBitmapRowIndexed(pos: number, repeats: number, data: Uint8Array, printheadPixels?: number): NiimbotPacket {
const { total, a, b, c } = Utils.countPixelsForBitmapPacket(data, printheadPixels ?? 0);
const indexes: Uint8Array = ImageEncoder.indexPixels(data); const indexes: Uint8Array = ImageEncoder.indexPixels(data);
if (blackPixelCount > 6) { if (total > 6) {
throw new Error(`Black pixel count > 6 (${blackPixelCount})`); throw new Error(`Black pixel count > 6 (${total})`);
}
let header: number[] = [0, ...Utils.u16ToBytes(total)];
if (printheadPixels !== undefined) {
header = [a, b, c];
} }
const packet = new NiimbotPacket(RequestCommandId.PrintBitmapRowIndexed, [ const packet = new NiimbotPacket(RequestCommandId.PrintBitmapRowIndexed, [
...Utils.u16ToBytes(pos), ...Utils.u16ToBytes(pos),
0, ...header,
...Utils.u16ToBytes(blackPixelCount),
repeats, repeats,
...indexes, ...indexes,
]); ]);
@ -273,13 +285,13 @@ export class PacketGenerator {
return new NiimbotPacket(RequestCommandId.WriteRFID, data); return new NiimbotPacket(RequestCommandId.WriteRFID, data);
} }
public static writeImageData(image: EncodedImage): NiimbotPacket[] { public static writeImageData(image: EncodedImage, printheadPixels?: number): NiimbotPacket[] {
return image.rowsData.map((p: ImageRow) => { return image.rowsData.map((p: ImageRow) => {
if (p.dataType === "pixels") { if (p.dataType === "pixels") {
if (p.blackPixelsCount > 6) { if (p.blackPixelsCount > 6) {
return this.printBitmapRow(p.rowNumber, p.repeat, p.rowData!); return this.printBitmapRow(p.rowNumber, p.repeat, p.rowData!, printheadPixels);
} else { } else {
return this.printBitmapRowIndexed(p.rowNumber, p.repeat, p.rowData!); return this.printBitmapRowIndexed(p.rowNumber, p.repeat, p.rowData!, printheadPixels);
} }
} else { } else {
return this.printEmptySpace(p.rowNumber, p.repeat); return this.printEmptySpace(p.rowNumber, p.repeat);

@ -15,7 +15,7 @@ export class Utils {
if (!match) { if (!match) {
return new Uint8Array(); return new Uint8Array();
} }
return new Uint8Array( return new Uint8Array(
match.map((h) => { match.map((h) => {
return parseInt(h, 16); return parseInt(h, 16);
@ -39,23 +39,45 @@ export class Utils {
return new TextDecoder().decode(arr); return new TextDecoder().decode(arr);
} }
/** Count non-zero bits in the byte array */ /**
public static countSetBits(arr: Uint8Array): number { * Count non-zero bits in the byte array
// not so efficient, but readable *
let count: number = 0; * Not efficient, but readable.
*
* The algorithm is obtained by reverse engineering and I don't understand what's going on here.
*
* Sometimes these values match original packets, sometimes not.
**/
public static countPixelsForBitmapPacket(
arr: Uint8Array,
printheadSize: number
): { total: number; a: number; b: number; c: number } {
let total: number = 0;
let a: number = 0;
let b: number = 0;
let c: number = 0;
let xPos: number = 0;
arr.forEach((value) => { const printheadSizeDiv3: number = printheadSize / 3;
// shift until value becomes zero
while (value > 0) { arr.forEach((value: number) => {
// check last bit //for (let bitN = 0; bitN < 8; bitN++) {
if ((value & 1) === 1) { for (let bitN: number = 7; bitN >= 0; bitN--) {
count++; const isBlack: boolean = (value & (1 << bitN)) !== 0;
if (isBlack) {
if (xPos < printheadSizeDiv3) {
a++;
} else if (xPos < printheadSizeDiv3 * 2) {
b++;
} else {
c++;
}
total++;
} }
value >>= 1; xPos++;
} }
}); });
return { total, a, b, c };
return count;
} }
/** Big endian */ /** Big endian */