离子3:使用蓝牙打印机打印图像

时间:2017-10-24 07:09:34

标签: image typescript printing bluetooth ionic3

我目前正在努力使用我们的Io​​nic3应用程序。我似乎无法找到如何使用BT打印机和蓝牙串行插件打印图像。打印文本就好了。

我们正在使用此文档测试RPP02N-BU打印机(由我的前同事发现) Driver Commands Documentation,但我无法获得

  

选择位图像模式

工作。

我们首先调整上传图片的大小不超过300px,我们将其转换为黑白图像。打印时,我们迭代图像并创建二进制字符串,然后我们将其转换为字节。这些字节遵循SELECT BIT IMAGE MODE命令。

我们的代码(在TypeScript中)如下:

/**
 * Image to printer command
 * @param image 
 */
public static getImagePrintData(image: HTMLImageElement): Buffer {
    // Initialize list of commands
    let command: number[] = [ 0x1b, 0x2a, 33, 255, 3 ];

    // Get image bytes
    let bytes = this.getImageBytes(image);

    // Add bytes to command
    bytes.forEach((byte) => command.push(byte));

    // Return command
    return new Buffer(command);
}

/**
 * Get image bytes
 * @param image 
 */
private static getImageBytes(image: HTMLImageElement): number[] {
    // Init result
    let result = [];

    // Create image padding
    let padding = this.getZeroBytePadding(image.width);

    // Get image context
    let ctx = this.getImageContext(image);

    // Iterate image pixels
    for (let y = 0; y < image.height; y++) {
        // Init row string
        let row = "";

        // Go through row of pixels
        for (let x = 0; x < image.width; x++) {
            // Get pixel
            let pixel = ctx.getImageData(x, y, 1, 1).data;

            // Get rgb value
            let rgbValue = pixel[0] + pixel[1] + pixel[2];

            // Add 0 or 1 based on value
            row = row + (rgbValue > 0 ? 0 : 1);
        }

        // Add padding
        row = row + padding;

        // Now we need to split the row into byte chunks
        let byteChunks = row.match(/.{1,8}/g);

        // Now add those byte chunks to result
        byteChunks.forEach((chunk) => result.push(parseInt(chunk, 2)));
    }

    // Return result
    return result;
}

/**
 * Get zero byte padding
 * @param value 
 */
private static getZeroBytePadding(value: number): string {
    // Init padding
    let padding = "";

    // Get difference
    let diff = value % 8;

    // Create padding
    for (let i = 0; i < (8 - diff); i++) {
        padding = padding + "0";
    }

    // Return result
    return padding;
}

/**
 * Get image context
 * @param image 
 */
private static getImageContext(image: HTMLImageElement): CanvasRenderingContext2D {
    // Prepare canvas to draw image into
    var canvas = document.createElement('canvas');
    canvas.width = image.width;
    canvas.height = image.height;

    // Context
    var ctx = canvas.getContext('2d');
    ctx.drawImage(image, 0, 0);

    return ctx;
}

然后命令被发送到BT打印机:

// Initialize image
let image = new Image();
// Set data
image.src = options.logo.content;
// Get image print data
let imagePrintData = PrinterUtils.getImagePrintData(image);

// Push image to print queue
printQueue.push(this.bluetoothUtility.write(imagePrintData));

生成的图像如下所示:

Printed image

原作是:

Original image

4 个答案:

答案 0 :(得分:2)

所以我终于成功了。我使用了此代码的一部分:https://github.com/song940/node-escpos并设法打印徽标,甚至居中。

以下代码位于TypeScript

我创建了ESCPOSImage类:

/**
 * RGB interface
 */
interface IRGB {
    r: number;
    g: number;
    b: number;
    a: number;
}

/**
 * ESCPOS image
 */
export class ESCPOSImage {

    // Data
    private data: number[] = [];

    // Width
    private width: number = 0;

    // Height
    private height: number = 0;

    /**
     * Constructor
     * @param image 
     */
    constructor(image: HTMLImageElement) {
        // Set width 
        this.width = image.width;

        // Set height
        this.height = image.height;

        // Get image context
        let ctx = this.getContext(image);

        // Get data
        this.data = this.getBitData(ctx);
    }

    /**
     * Get bit data
     * @param ctx 
     */
    private getBitData(ctx: CanvasRenderingContext2D): number[] {
        // Init result
        let result: number[] = [];

        // Iterate rows
        for (let y = 0; y < this.height; y++) {
            // Iterate columns
            for (let x = 0; x < this.width; x++) {
                // Get pixel
                let pixel = ctx.getImageData(x, y, 1, 1).data;

                // Get rgb
                let rgb = this.getRGB(pixel);

                // Get rgb value
                let value = rgb.r + rgb.g + rgb.b;

                // Add bit to result
                result.push(value > 0 ? 0 : 1);
            }
        }

        // Return result
        return result;
    }

    /**
     * Get image context
     * @param image 
     */
    private getContext(image: HTMLImageElement): CanvasRenderingContext2D {
        // Create canvas
        var canvas = document.createElement('canvas');
        canvas.width = image.width;
        canvas.height = image.height;

        // Set context
        var context = canvas.getContext('2d');
        context.drawImage(image, 0, 0);

        // Return context
        return context;
    }

    /**
     * Get RGB
     * @param pixel 
     */
    private getRGB(pixel: any): IRGB {
        // Return RGB
        return {
            r: pixel[0],
            g: pixel[1],
            b: pixel[2],
            a: pixel[3]
        }
    }

    /**
     * To raster
     */
    public toRaster() {
        // Init result
        let result = [];

        // Get width and height
        let width = this.width;
        let height = this.height;

        // N block lines
        let n = Math.ceil(width / 8);

        // Iterate
        for (let y = 0; y < height; y++) {
            for (let x = 0; x < n; x++) {
                for (let b = 0; b < 8; b++) {
                    let i = x * 8 + b;

                    if (result[y * n + x] === undefined) {
                        result[y * n + x] = 0;
                    }

                    let c = x * 8 + b;

                    if (c < width) {
                        if (this.data[y * width + i]) {
                            result[y * n + x] += (0x80 >> (b & 0x7));
                        }
                    }
                }
            }
        }

        // Return result
        return {
            data: result,
            width: n,
            height: height
        };
    }   
}

该类实现toRaster方法,稍后在ESCPOSPrinter类中使用:

/**
 * ESCPOS printer
 */
export class ESCPOSPrinter {

    // Buffer
    private buffer: Buffer;

    /**
     * Constructor
     * @param buffer 
     */
    constructor(buffer: Buffer) {
        // Init buffer
        this.buffer = buffer;
    }

    /**
     * Write buffer
     * @param buffer 
     */
    private write(buffer: Buffer) {
        this.buffer = Buffer.concat([this.buffer, buffer]);
    }

    /**
     * Print raster
     * @param image 
     * @param mode 
     */
    public raster(image: ESCPOSImage, mode: string = 'normal') {
        // Get header
        let header = COMMANDS.S_RASTER_N;

        // Get raster
        let raster = image.toRaster();

        // Set alignment
        this.align('center');

        // Write header
        this.write(new Buffer(header));
        this.write(new Buffer([raster.width, 0]));
        this.write(new Buffer([raster.height, 0]));
        // Write data
        this.write(new Buffer(raster.data));
    }

    /**
     * Print line
     */
    public printLn() {
        this.write(new Buffer([COMMANDS.CTL_CR, COMMANDS.CTL_LF]));
    }

    /**
     * Align 
     * @param alignment ['left', 'center', 'right'] 
     */
    public align(alignment: string = 'left') {
        // Create alignment dictionary
        const aligments = {
            ['left']: COMMANDS.TXT_ALIGN_LT,
            ['center']: COMMANDS.TXT_ALIGN_CT,
            ['right']: COMMANDS.TXT_ALIGN_RT
        }

        // Write alignment
        this.write(new Buffer(aligments[alignment]));
    }

    /**
     * Get buffer
     */
    public getBuffer(): Buffer {
        return this.buffer;
    }
}

最后,一起使用:

// Create image
let image = new Image();

// Set data
image.src = options.logo.content;

// Create ESCPOS image
let escposImage = new ESCPOSImage(image);

// Initialize ESCPOS printer
let escposPrinter = new ESCPOSPrinter(new Buffer([]));

// Print image
escposPrinter.raster(escposImage);

// And also print new line
escposPrinter.printLn();

// Assign data to print queue
printData = Buffer.concat([escposPrinter.getBuffer(), printData]);

然后将数据分成数据包并使用蓝牙串行插件的写入方法发送。

如果您对这些命令感到疑惑:

TXT_ALIGN_LT: [0x1b, 0x61, 0x00],     // Left justification
TXT_ALIGN_CT: [0x1b, 0x61, 0x01],     // Centering
TXT_ALIGN_RT: [0x1b, 0x61, 0x02],     // Right justification

S_RASTER_N: [0x1d, 0x76, 0x30, 0x00], // Set raster image normal size

CTL_LF: [0x0a], // Print and line feed
CTL_CR: [0x0d], // Carriage return

希望这有助于某人。干杯

答案 1 :(得分:1)

我收到错误&#34;找不到名字&#34; public class A extends D implements Serializable { public Dataset<Row> getDataSet(SparkSession session) { Dataset<Row> dfs = session.readStream().format("socket").option("host", hostname).option("port", port).load(); publish(dfs.toDF(), "reader"); return dfs; } } public class B extends D implements Serializable { public Dataset<Row> execute(Dataset<Row> ds) { Dataset<Row> d = ds.select(functions.explode(functions.split(ds.col("value"), "\\s+"))); publish(d.toDF(), "component"); return d; } } public class C extends D implements Serializable { public Dataset<Row> execute(Dataset<Row> ds) { publish(inputDataSet.toDF(), "console"); ds.writeStream().format("csv").option("path", "hdfs://hostname:9000/user/abc/data1/") .option("checkpointLocation", "hdfs://hostname:9000/user/abc/cp").outputMode("append").start(); return ds; } } public class D { public void publish(Dataset<Row> dataset, String directory) { dataset.writeStream().format("csv").option("path", "hdfs://hostname:9000/user/abc/" + directory) .option("checkpointLocation", "hdfs://hostname:9000/user/abc/checkpoint/" + directory).outputMode("append") .start(); } } public static void main(String[] args) { SparkSession session = createSession(); try { A a = new A(); Dataset<Row> records = a.getDataSet(session); B b = new B(); Dataset<Row> ds = b.execute(records); C c = new C(); c.execute(ds); session.streams().awaitAnyTermination(); } catch (StreamingQueryException e) { e.printStackTrace(); } } COMMANDS

这是什么?

以及如何导入&#34; node-escpos&#34;?

答案 2 :(得分:0)

testtest2

嗨,菲利普·马蒂斯

我尝试与您的班级一起打印您的 StarWars 图像,但结果喜忧参半。根据我的理解,您尝试重用 node-escpos 您是否找到了一种方法可以访问所有 packags/printer/index.js 功能?

喜欢:

printer
  .font('a')
  .align('ct')
  .style('bu')
  .size(1, 1)
  .text('The quick brown fox jumps over the lazy dog')
  .text('敏捷的棕色狐狸跳过懒狗')
  .barcode('1234567', 'EAN8')
  .table(["One", "Two", "Three"])
  .tableCustom([
    { text:"Left", align:"LEFT", width:0.33 },
     { text:"Center", align:"CENTER", width:0.33},
     { text:"Right", align:"RIGHT", width:0.33 }
  ])
  .qrimage('https://github.com/song940/node-escpos', function(err){
     this.cut();
     this.close();
  });

答案 3 :(得分:0)

我能够使用外部库打印到 escpos 兼容打印机。

遵循以下指南:

  1. https://levelup.gitconnected.com/how-to-print-on-a-bluetooth-printer-using-your-ionic-application-ceabc45abf75

  2. https://www.neodynamic.com/articles/How-to-generate-and-print-raw-ESC-POS-commands-from-Javascript/

enter image description here

  • 设备:Samsung Tab A 10.1
  • 打印机:MUNBYN POS
  • Ionic 4、Angular 8、Ionic 原生蓝牙串口