12 个版本
0.4.3 | 2024年2月5日 |
---|---|
0.4.2 | 2023年7月19日 |
0.3.1 | 2022年3月10日 |
0.3.0 | 2021年8月23日 |
0.1.0 | 2021年8月7日 |
#157 in 硬件支持
在 rawprinter 中使用
110KB
1.5K SLoC
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在哪里查找pkg-config
文件。 -
在这些路径中的任何一个中添加文件
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这样的工具更改打印机的驱动程序。只需记住,此驱动程序更改可能会使打印机对其他工具不可见;)。
依赖项
~8MB
~122K SLoC