- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我目前正在努力使用我们的 Ionic3 应用程序。我似乎不知道如何使用 BT 打印机和蓝牙串行插件打印图像。打印文字就好了。
我们正在使用此文档(由我的前同事发现)测试 RPP02N-BU 打印机 Driver Commands Documentation ,但我无法得到
SELECT BIT IMAGE MODE
上类。
我们首先将上传的图像大小调整为不超过 300 像素,然后将其转换为黑白。打印时,我们迭代图像并创建二进制字符串,然后将其转换为字节。这些字节遵循 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));
生成的图像如下所示:
原文是:
最佳答案
更新 9.6.2023
对于仍在苦苦挣扎的人,我们最近找到了这个库: https://github.com/NielsLeenheer/EscPosEncoder
它完成大部分工作,还提供 QR 码和条形码编码。希望有帮助!
所以我终于成功了。我使用了部分代码:https://github.com/song940/node-escpos并设法打印 Logo ,甚至居中。
以下代码采用 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
希望这对某人有帮助。干杯
关于image - ionic 3 : Print image using Bluetooth printer,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46904252/
我在优化 JOIN 以使用复合索引时遇到问题。我的查询是: SELECT p1.id, p1.category_id, p1.tag_id, i.rating FROM products p1
我有一个简单的 SQL 查询,我正在尝试对其进行优化以删除“使用位置;使用临时;使用文件排序”。 这是表格: CREATE TABLE `special_offers` ( `so_id` int
我有一个具有以下结构的应用程序表 app_id VARCHAR(32) NOT NULL, dormant VARCHAR(6) NOT NULL, user_id INT(10) NOT NULL
此查询的正确索引是什么。 我尝试为此查询提供不同的索引组合,但它仍在使用临时文件、文件排序等。 总表数据 - 7,60,346 产品= '连衣裙' - 总行数 = 122 554 CREATE TAB
为什么额外的是“使用where;使用索引”而不是“使用索引”。 CREATE TABLE `pre_count` ( `count_id`
我有一个包含大量记录的数据库,当我使用以下 SQL 加载页面时,速度非常慢。 SELECT goal.title, max(updates.date_updated) as update_sort F
我想知道 Using index condition 和 Using where 之间的区别;使用索引。我认为这两种方法都使用索引来获取第一个结果记录集,并使用 WHERE 条件进行过滤。 Q1。有什
I am using TypeScript 5.2 version, I have following setup:我使用的是TypeScript 5.2版本,我有以下设置: { "
I am using TypeScript 5.2 version, I have following setup:我使用的是TypeScript 5.2版本,我有以下设置: { "
I am using TypeScript 5.2 version, I have following setup:我使用的是TypeScript 5.2版本,我有以下设置: { "
mysql Ver 14.14 Distrib 5.1.58,用于使用 readline 5.1 的 redhat-linux-gnu (x86_64) 我正在接手一个旧项目。我被要求加快速度。我通过
在过去 10 多年左右的时间里,我一直打开数据库 (mysql) 的连接并保持打开状态,直到应用程序关闭。所有查询都在连接上执行。 现在,当我在 Servicestack 网页上看到示例时,我总是看到
我使用 MySQL 为我的站点构建了一个自定义论坛。列表页面本质上是一个包含以下列的表格:主题、上次更新和# Replies。 数据库表有以下列: id name body date topic_id
在mysql中解释的额外字段中你可以得到: 使用索引 使用where;使用索引 两者有什么区别? 为了更好地解释我的问题,我将使用下表: CREATE TABLE `test` ( `id` bi
我经常看到人们在其Haxe代码中使用关键字using。它似乎在import语句之后。 例如,我发现这是一个代码片段: import haxe.macro.Context; import haxe.ma
这个问题在这里已经有了答案: "reduce" or "apply" using logical functions in Clojure (2 个答案) 关闭 8 年前。 “and”似乎是一个宏,
这个问题在这里已经有了答案: "reduce" or "apply" using logical functions in Clojure (2 个答案) 关闭 8 年前。 “and”似乎是一个宏,
我正在考虑在我的应用程序中使用注册表模式来存储指向某些应用程序窗口和 Pane 的弱指针。应用程序的一般结构如下所示。 该应用程序有一个 MainFrame 顶层窗口,其中有几个子 Pane 。可以有
奇怪的是:。似乎a是b或多或少被定义为id(A)==id(B)。用这种方式制造错误很容易:。有些名字出人意料地出现在Else块中。解决方法很简单,我们应该使用ext==‘.mp3’,但是如果ext表面
我遇到了一个我似乎无法解决的 MySQL 问题。为了能够快速执行用于报告目的的 GROUP BY 查询,我已经将几个表非规范化为以下内容(该表由其他表上的触发器维护,我已经同意了与此): DROP T
我是一名优秀的程序员,十分优秀!