2 个版本
0.0.2 | 2023 年 5 月 4 日 |
---|---|
0.0.1 | 2023 年 4 月 25 日 |
#960 在 硬件支持
26 每月下载量
105KB
1.5K SLoC
escpos-rust: 基于 escpos-rs 优化扩展
新增内容
- 打印一维条形码
- 打印 GB18030 文本
未来新增功能
- 四行表格打印
escpos-rs: 用于热敏打印机的 Rust crate
开发中。尚未准备好用于生产。
Escpos-rs 基于 escpospp
构建了一些功能,旨在为理解 ESC/POS 协议的热敏打印机提供相对简单的通信。以下是一个使用 escpos-rs
进行简单打印的示例
use escpos_rs::{Printer, PrinterProfile};
fn main() {
// We create the printer details
let mut printer_details = PrinterProfile::usb_builder(0x0001, 0x0001).build();
// We pass it to the printer
let printer = match Printer::new(printer_details) {
Ok(maybe_printer) => match maybe_printer {
Some(printer) => printer,
None => panic!("No printer was found :(")
},
Err(e) => panic!("Error: {}", e)
};
// We print simple text
match printer.println("Hello, world!") {
Ok(_) => (),
Err(e) => println!("Error: {}", e)
}
}
连接到打印机
为了连接到打印机,您需要知道打印机的供应商 ID 和产品 ID。常见的打印机在线上发布了这些详细信息,而对于不太常见的打印机,您至少有以下两种选择
- 一些打印机会在测试打印上打印它们的信息(通常按住进纸按钮)
- 如果您使用的是 Linux,
lsusb
命令会显示这些信息。
有了这些信息,您就可以开始与打印机建立连接了
// Here goes the vendor id, and the product it (in that order)
let mut printer_details = PrinterProfile::usb_builder(0x0001, 0x0001).build();
// We pass it to the printer
let printer = match Printer::new(printer_details) {
Ok(maybe_printer) => match maybe_printer {
Some(printer) => printer,
None => panic!("No printer was found :(")
},
Err(e) => panic!("Error: {}", e)
};
发送原始信息
打印机有 raw
方法,允许您向打印机发送原始字节。如果您需要操作在低级别,这很简单。
use escpos_rs::{
Printer, PrinterModel,
command::Command
};
fn main() {
let printer = match Printer::new(PrinterModel::ZKTeco.usb_profile()) {
Ok(maybe_printer) => match maybe_printer {
Some(printer) => printer,
None => panic!("No printer was found :(")
},
Err(e) => panic!("Error: {}", e)
};
match printer.raw(b"Hello, world!\n") {
Ok(_) => (),
Err(e) => println!("Error: {}", e)
}
match printer.raw(Command::Cut.as_bytes()) {
Ok(_) => (),
Err(e) => println!("Error: {}", e)
}
}
您可以通过查看 Command
枚举来了解哪些命令已实现(列表将增长)。
打印图像
您还可以通过 EscposImage
结构将图像发送到打印机(假设它受支持)。
use escpos_rs::{
EscposImage, Printer, PrinterProfile, Justification
};
fn main() {
let printer_profile = PrinterProfile::usb_builder(0x0001, 0x0001).build();
let printer = match Printer::new(printer_profile) {
Ok(maybe_printer) => match maybe_printer {
Some(printer) => printer,
None => panic!("No printer was found :(")
},
Err(e) => panic!("Error: {}", e)
};
let img = image::open("logo.jpg").unwrap();
let escpos_image = EscposImage::new(img, 128, Justification::Center).unwrap();
match printer.image(escpos_image) {
Ok(_) => (), // Image should be printed
Err(e) => println!("Error: {}", e)
};
}
EscposImage
的构造函数接受第一个参数为 DynamicImage
,第二个参数为宽度缩放(从 0 到 255),第三个参数为对齐方式。
网络功能
即将添加。
指令结构
指令结构的主要目标是构建一个 模板,可以用来打印包含动态数据的多个文档。
use escpos_rs::{Printer, PrintData, PrinterProfile, Instruction, Justification, command::Font};
fn main() {
// Printer profile...
let printer_profile = PrinterProfile::usb_builder(0x0001, 0x0001)
.with_font_width(Font::FontA, 32)
.build();
// We pass it to the printer
let printer = match Printer::new(printer_profile) {
Ok(maybe_printer) => match maybe_printer {
Some(printer) => printer,
None => panic!("No printer was found :(")
},
Err(e) => panic!("Error: {}", e)
};
// We create a simple instruction with a single substitution
let instruction = Instruction::text(
"Hello, %name%!",
Font::FontA,
Justification::Center,
// Words that will be replaced in this specific instruction
Some(vec!["%name%".into()].into_iter().collect())
);
// We create custom information for the instruction
let print_data_1 = PrintData::builder()
.replacement("%name%", "Carlos")
.build();
// And a second set...
let print_data_2 = PrintData::builder()
.replacement("%name%", "John")
.build();
// We send the instruction to the printer, along with the custom data
// for this particular print
match printer.instruction(&instruction, Some(&print_data_1)) {
Ok(_) => (), // "Hello, Carlos!" should've been printed.
Err(e) => println!("Error: {}", e)
}
// Now we print the second data
match printer.instruction(&instruction, Some(&print_data_2)) {
Ok(_) => (), // "Hello, John!" should've been printed.
Err(e) => println!("Error: {}", e)
}
}
可以将指令组合起来形成一个复杂的指令。此外,您可以使用 serde 对这些指令进行序列化和反序列化,以便您保存模板。
运行示例
您可以在 examples 文件夹中运行示例,通过 cargo 调用它们。
cargo run --example basic
关于在 Windows 上构建此库
编译需要 libusb 库。请访问 https://github.com/libusb/libusb/releases 下载编译后的二进制文件,并将它们放入 mingw 的 include 和 bin 文件夹中。您还需要一个 pkg config 文件。
-
执行以下命令
pkg-config.exe --variable pc_path pkg-config
以了解 pkg-config 查找 pc 文件的位置 -
在这些路径中的任何一个添加文件
libusb-1.0.pc
,内容如下
prefix=c:/mingw-w64/x86_64-8.1.0-posix-seh-rt_v6-rev0/mingw64
exec_prefix=${prefix}
libdir=${prefix}/lib
includedir=${prefix}/include
Name: libusb-1.0
Description: C API for USB device access from Linux, Mac OS X, Windows, OpenBSD/NetBSD and Solaris userspace
Version: 1.0.23
Libs: -L${libdir} -lusb-1.0
Libs.private: -ludev -pthread
Cflags: -I${includedir}/libusb-1.0
注意:版本必须与您的 libusb 版本匹配,并且前缀也必须与 MinGW 的主 include 和 lib 文件夹匹配。
以下步骤基于 这篇 stackoverflow 帖子。
我们假设您的 mingw 安装在 C:\MinGW\bin
- 访问 gnome,并下载包
pkg-config_0.26-1_win32.zip
- 将文件
bin/pkg-config.exe
解压到C:\MinGW\bin
- 下载文件 gettext-runtime_0.18.1.1-2_win32.zip
- 将文件 bin/intl.dll 解压到
C:\MinGW\bin
,然后访问 http://ftp.gnome.org/pub/gnome/binaries/win32/glib/2.28 - 从这里(gnome 的网站)下载文件
glib_2.28.8-1_win32.zip
- 将文件
bin/libglib-2.0-0.dll
解压到C:\MinGW\bin
在 Windows 上使用库
我只在选择了 WinUSB 驱动程序的情况下能够使用此库。您可以使用像 Zadig 这样的工具更改打印机的驱动程序。但请记住,这种驱动程序更改可能会使打印机对其他工具不可见;)。
依赖项
~10MB
~152K SLoC