-
Notifications
You must be signed in to change notification settings - Fork 44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
This library without printing images is useless #92
Comments
I wrote this: import { Inject, Injectable, NgModule } from '@angular/core';
export const WIDTH = 'WIDTH';
export const HEIGHT = 'HEIGHT';
export const INVERT_COLORS = 'INVERT_COLORS';
@Injectable({
providedIn: 'root',
})
export class ImagePrintingService {
private imageData: ImageData;
private invertColors: boolean;
private ESC_INIT = [0x1b, 0x40];
private ESC_BIT_IMAGE = [0x1b, 0x2a]
private DOTS_DENSITY = 24
private LUMINANCE = {
RED: 0.299,
GREEN: 0.587,
BLUE: 0.114
}
private LINE_FEED = 0x0a;
// https://www.sparkag.com.br/wp-content/uploads/2016/06/ESC_POS-AK912-English-Command-Specifications-V1.4.pdf
private LINE_FEED_AMOUNT = [0x1b, 0x33, 0x18]; // the third parameter is a numeric value where 1 = 0.125mm
private LINE_FEED_DEFAULT = [0x1b, 0x32];
// the best print quality is achieved when width and height are both multiples of 8
constructor(image: HTMLImageElement, @Inject(INVERT_COLORS) invertColors: boolean = false, @Inject(WIDTH) width?: number, @Inject(HEIGHT) height?: number) {
const canvas = document.createElement('canvas');
canvas.width = width ?? image.width;
canvas.height = height ?? image.height;
const context = canvas.getContext('2d');
if (!context) {
throw new Error('Could not get 2D context for canvas');
}
context.drawImage(image, 0, 0, canvas.width, canvas.height);
this.imageData = context.getImageData(0, 0, canvas.width, canvas.height);
this.invertColors = invertColors;
}
private calculateLuminance(pixel: number[]): number {
let lum = this.LUMINANCE.RED * pixel[0] + this.LUMINANCE.GREEN * pixel[1] + this.LUMINANCE.BLUE * pixel[2];
return this.invertColors ? 255 - lum : lum;
}
private calculateSlice(x: number, y: number): number {
const threshold = 127;
let slice = 0;
for (let bit = 0; bit < 8; bit++) {
if ((y + bit) >= this.imageData.height)
continue;
const index = (this.imageData.width * (y + bit) + x) * 4;
const pixel = [
this.imageData.data[index],
this.imageData.data[index + 1],
this.imageData.data[index + 2]
];
const luminance = this.calculateLuminance(pixel);
slice |= (luminance < threshold ? 1 : 0) << 7 - bit;
}
return slice;
}
private collectStripe(x: number, y: number): number[] {
let slices = [];
let z = y + this.DOTS_DENSITY;
let i = 0
while (y < z && i < 3){
slices.push(this.calculateSlice(x, y));
y += 8
}
return slices;
}
private manipulateImage(): number[] {
let data = [];
const imageWidth = this.imageData.width;
for (let y = 0; y < this.imageData.height; y += this.DOTS_DENSITY){
data.push(...this.ESC_BIT_IMAGE, 33, (0x00ff & imageWidth), (0xff00 & imageWidth) >> 8);
for (let x = 0; x < imageWidth; x++) {
data.push(...this.collectStripe(x, y));
}
data.push(this.LINE_FEED);
}
return data;
}
public getUint8Array(): Uint8Array {
let transformedImage = [];
// transformedImage.push(...this.ESC_INIT);
transformedImage.push(...this.LINE_FEED_AMOUNT);
transformedImage.push(...this.manipulateImage());
transformedImage.push(...this.LINE_FEED_DEFAULT);
return new Uint8Array(transformedImage);
}
} Use it like this: let img = new Image();
img.src = "assets/logo.svg";
img.onload = () => {
let imagePrintingService = new ImagePrintingService(img, true, 240, 56);
this.escEncoder.raw(imagePrintingService.getUint8Array())
} |
@PiegoIlTempo , thanks alot for ur Help, can i see (this.escEncoder) |
Np man, I had the same problem trying to print images, actually let me know if it gets printed correctly since I tested it on few printers. This is an example of a printing service in Angular 11 with usb and bluetooth: import { Injectable } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import EscPosEncoder from 'esc-pos-encoder';
import { UsbDriver, BluetoothDriver, PrintService } from 'ngx-thermal-print';
import { BehaviorSubject, combineLatest } from 'rxjs';
import { map } from 'rxjs/operators';
import { ImagePrintingService } from 'src/app/route-modules/web-app-root/services/image-printing-service';
import { formatToEuro } from 'src/app/shared/pipes/euro.pipe';
import { ConnectThermalPrinterDialogComponent } from '../components/connect-thermal-printer-dialog/connect-thermal-printer-dialog.component';
enum DeviceType {
USB,
BLUETOOTH
}
@Injectable({
providedIn: 'root',
})
export class ThermalPrinterService {
private readonly AUTO_PRINT_RECEIPT = "auto_print_receipt"
private readonly PRINTER_DEVICE = "printer_device"
private readonly productsTableFormat = [
{ width: 18, marginRight: 1, align: 'left' },
{ width: 4, align: 'right' },
{ width: 9, align: 'right' }
]
private readonly escEncoder = new EscPosEncoder({
imageMode: 'legacy',
codepageMapping: 'legacy'
});
private usbPrintDriver = new UsbDriver();
private bluetoothPrintDriver = new BluetoothDriver();
readonly isConnected = new BehaviorSubject<boolean>(false)
private codepage = "auto"
constructor(private matDialog: MatDialog) {
const device = this.getSavedPrinterDevice()
if(device != null) {
if(device.type == DeviceType.USB) {
this.usbPrintDriver = new UsbDriver(device.vendorId, device.productId)
this.usbPrintDriver.connect()
}
}
const isConnectedObservable = combineLatest([this.usbPrintDriver.isConnected, this.bluetoothPrintDriver.isConnected]).pipe(
map(([usb, bluetooth]) => {
return usb || bluetooth
})
)
isConnectedObservable.subscribe(this.isConnected)
}
private savePrinterDevice(type: DeviceType, vendorId: number, productId: number) {
localStorage.setItem(this.PRINTER_DEVICE, JSON.stringify({type: type, vendorId: vendorId, productId: productId}));
}
private getSavedPrinterDevice(): any|null {
const deviceData = localStorage.getItem(this.PRINTER_DEVICE)
if(deviceData != null) {
return JSON.parse(deviceData)
}
else return null;
}
private deleteSavedPrinterDevice() {
localStorage.removeItem(this.PRINTER_DEVICE)
}
disconnect() {
this.usbPrintDriver = new UsbDriver()
this.bluetoothPrintDriver = new BluetoothDriver()
this.deleteSavedPrinterDevice()
window.location.reload()
}
connectUsbPrinter() {
this.usbPrintDriver.requestUsb().subscribe(
(result) => {
// HACK to this fucking brand that doesn't support any codepage except chinese
if (result.manufacturerName == "GEZHI") {
this.codepage = "cp54936"
} else {
this.codepage = "auto"
}
this.usbPrintDriver.connect()
this.savePrinterDevice(DeviceType.USB, result.vendorId, result.productId)
},
(error) => {
console.log(error);
}
);
}
connectBluetoothPrinter() {
this.bluetoothPrintDriver.requestBluetooth().subscribe(
(result) => {
// HACK to this fucking brand that doesn't support any codepage except chinese
if (result.name == "MTP-II") {
this.codepage = "cp54936"
} else {
this.codepage = "auto"
}
this.bluetoothPrintDriver.connect()
},
(error) => {
console.log(error);
}
)
}
get hasPrinterSupport(): boolean {
return this.usbPrintDriver.isSupported || this.bluetoothPrintDriver.isSupported
}
get isBluetoothSupported(): boolean {
return this.bluetoothPrintDriver.isSupported
}
get isUsbSupported(): boolean {
return this.usbPrintDriver.isSupported
}
set autoPrintReceipt(value: boolean) {
localStorage.setItem(this.AUTO_PRINT_RECEIPT, value ? "1" : "0")
}
get autoPrintReceipt(): boolean {
const value = localStorage.getItem(this.AUTO_PRINT_RECEIPT)
if (value == null) {
return true
} else {
return value == "1"
}
}
connectPrinterDialog() {
ConnectThermalPrinterDialogComponent.openDialog(this.matDialog, this)
}
private endOfPrint() {
this.escEncoder.newline()
this.escEncoder.newline()
this.escEncoder.newline()
this.escEncoder.newline()
this.escEncoder.cut()
this.writeBuffer(this.escEncoder.encode())
}
printCheckout(documentId: string, checkhoutDetails: CheckoutDetails) {
if (this.isConnected.value) {
this.internalPrintScontrino(documentId, scontrinoDetails)
} else {
ConnectThermalPrinterDialogComponent.openDialog(this.matDialog, this).subscribe(result => {
if (result) {
this.internalPrintScontrino(documentId, scontrinoDetails)
}
})
}
}
private async internalPrintCheckout(documentId: string, checkhoutDetails: CheckoutDetails) {
this.escEncoder.codepage(this.codepage as any)
this.escEncoder.align("left")
this.escEncoder.newline()
this.escEncoder.bold(true)
this.escEncoder.table(
this.productsTableFormat,
[
["", "VAT", "EUR"],
]
)
this.escEncoder.bold(false)
this.escEncoder.table(
this.productsTableFormat, [[/* your table */]]
)
this.escEncoder.line(documentId)
this.escEncoder.newline()
this.escEncoder.line("Thank you, come again!")
this.escEncoder.newline()
let logo = new Image();
logo.src = "assets/logo.svg";
logo.onload = () => {
let imagePrintingService = new ImagePrintingService(logo, true, 240, 56);
this.escEncoder.raw(imagePrintingService.getUint8Array())
if(checkoutDetails.referral_link != null) {
this.escEncoder.bold(true)
this.escEncoder.line("Download the app!")
this.escEncoder.qrcode(checkoutDetails.referral_link, 1, 8)
this.escEncoder.bold(false)
}
this.escEncoder.align("left")
this.endOfPrint()
}
}
private writeBuffer(buffer: Uint8Array) {
if (this.usbPrintDriver.isConnected.value) {
this.usbPrintDriver.write(buffer)
} else if (this.bluetoothPrintDriver.isConnected.value) {
this.bluetoothPrintDriver.write(buffer)
}
}
} NOTE: |
No description provided.
The text was updated successfully, but these errors were encountered: