diff --git a/src/packets/packet_generator.ts b/src/packets/packet_generator.ts index ade938c..b05713e 100644 --- a/src/packets/packet_generator.ts +++ b/src/packets/packet_generator.ts @@ -153,9 +153,7 @@ export class PacketGenerator { } public static setPrintQuantity(quantity: number): NiimbotPacket { - return new NiimbotPacket(RequestCommandId.PrintQuantity, [ - ...Utils.u16ToBytes(quantity) - ]); + return new NiimbotPacket(RequestCommandId.PrintQuantity, [...Utils.u16ToBytes(quantity)]); } public static printStatus(): NiimbotPacket { @@ -226,37 +224,51 @@ export class PacketGenerator { return packet; } - public static printBitmapRow(pos: number, repeats: number, data: Uint8Array): NiimbotPacket { - const blackPixelCount: number = Utils.countSetBits(data); + public static printBitmapRow( + 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, [ ...Utils.u16ToBytes(pos), - // 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) - 0, - ...Utils.u16ToBytes(blackPixelCount), + ...header, repeats, ...data, ]); packet.oneWay = true; return packet; } - /** Printer powers off if black pixel count > 6 */ - public static printBitmapRowIndexed(pos: number, repeats: number, data: Uint8Array): NiimbotPacket { - const blackPixelCount: number = Utils.countSetBits(data); + // 5555 83 0e 007e 000400 01 0027 0028 0029 002a fa aaaa + 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); - if (blackPixelCount > 6) { - throw new Error(`Black pixel count > 6 (${blackPixelCount})`); + if (total > 6) { + 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, [ ...Utils.u16ToBytes(pos), - 0, - ...Utils.u16ToBytes(blackPixelCount), + ...header, repeats, ...indexes, ]); @@ -273,13 +285,13 @@ export class PacketGenerator { 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) => { if (p.dataType === "pixels") { if (p.blackPixelsCount > 6) { - return this.printBitmapRow(p.rowNumber, p.repeat, p.rowData!); + return this.printBitmapRow(p.rowNumber, p.repeat, p.rowData!, printheadPixels); } else { - return this.printBitmapRowIndexed(p.rowNumber, p.repeat, p.rowData!); + return this.printBitmapRowIndexed(p.rowNumber, p.repeat, p.rowData!, printheadPixels); } } else { return this.printEmptySpace(p.rowNumber, p.repeat); diff --git a/src/utils.ts b/src/utils.ts index 4f05c3e..0d45a5e 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -15,7 +15,7 @@ export class Utils { if (!match) { return new Uint8Array(); } - + return new Uint8Array( match.map((h) => { return parseInt(h, 16); @@ -39,23 +39,45 @@ export class Utils { return new TextDecoder().decode(arr); } - /** Count non-zero bits in the byte array */ - public static countSetBits(arr: Uint8Array): number { - // not so efficient, but readable - let count: number = 0; + /** + * Count non-zero bits in the byte array + * + * 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) => { - // shift until value becomes zero - while (value > 0) { - // check last bit - if ((value & 1) === 1) { - count++; + const printheadSizeDiv3: number = printheadSize / 3; + + arr.forEach((value: number) => { + //for (let bitN = 0; bitN < 8; bitN++) { + for (let bitN: number = 7; bitN >= 0; bitN--) { + 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 count; + return { total, a, b, c }; } /** Big endian */