This crate implements a subset of Epson's ESC/POS protocol for thermal receipt printers. It allows you to generate and print documents with basic text formatting, cutting, barcodes, QR codes and raster images on a compatible printer. It also provides a way to check the printer status.
This project is strongly inspired by recibo (Rust), escposify (Rust) and escpos (Go).
For standard functionalities (e.g. printing text), no additional dependencies are required:
[dependencies]
escpos = "0.17.0"If you need all features, you can use the full feature:
[dependencies]
escpos = { version = "0.17.0", features = ["full"] }Or you can use cargo add command:
cargo add escpos
cargo add escpos -F fullTool used: tarpaulin
cargo install cargo-tarpaulincargo tarpaulin --all-features --tests
Results:
- [2025-09-15]
57.62% coverage, 1172/2034 lines covered
Tool used: cargo-msrv
cargo install cargo-msrvcargo msrv find
cargo msrv verify| Name | Description | Default |
|---|---|---|
barcodes |
Print barcodes (UPC-A, UPC-E, EAN8, EAN13, CODE39, ITF or CODABAR) | ✅ |
codes_2d |
Print 2D codes (QR Code, PDF417, GS1 DataBar, DataMatrix, Aztec, etc.) | ✅ |
graphics |
Print raster images | ❌ |
usb |
Enable USB feature | ❌ |
native_usb |
Enable native USB feature | ❌ |
hidapi |
Enable HidApi feature | ❌ |
serial_port |
Enable Serial port feature | ❌ |
ui |
Enable ui feature (UI components) | ❌ |
full |
Enable all features | ❌ |
The examples folder contains various examples of how to use escpos.
The docs also provide code snippets and examples.
To launch an example, use the following command:
RUST_LOG=debug cargo run --example full --features fullThe list of all the examples can be found here.
use escpos::printer::Printer;
use escpos::printer_options::PrinterOptions;
use escpos::utils::*;
use escpos::{driver::*, errors::Result};
fn main() -> Result<()> {
env_logger::init();
let driver = NetworkDriver::open("192.168.1.248", 9100, None)?;
Printer::new(driver, Protocol::default(), Some(PrinterOptions::default()))
.debug_mode(Some(DebugMode::Dec))
.init()?
.smoothing(true)?
.bold(true)?
.underline(UnderlineMode::Single)?
.writeln("Bold underline")?
.justify(JustifyMode::CENTER)?
.reverse(true)?
.bold(false)?
.writeln("Hello world - Reverse")?
.feed()?
.justify(JustifyMode::RIGHT)?
.reverse(false)?
.underline(UnderlineMode::None)?
.size(2, 3)?
.writeln("Hello world - Normal")?
.print_cut()?; // print() or print_cut() is mandatory to send the data to the printer
Ok(())
}use escpos::printer::Printer;
use escpos::utils::*;
use escpos::{driver::*, errors::Result};
fn main() -> Result<()> {
env_logger::init();
let driver = ConsoleDriver::open(true);
Printer::new(driver, Protocol::default(), None)
.debug_mode(Some(DebugMode::Hex))
.init()?
.ean13_option(
"1234567890265",
BarcodeOption::new(
BarcodeWidth::M,
BarcodeHeight::S,
BarcodeFont::A,
BarcodePosition::Below,
)
)?
.feed()?
.print()?; // print() or print_cut() is mandatory to send the data to the printer
Ok(())
}use escpos::printer::Printer;
use escpos::utils::*;
use escpos::{driver::*, errors::Result};
fn main() -> Result<()> {
env_logger::init();
let driver = ConsoleDriver::open(true);
Printer::new(driver, Protocol::default(), None)
.debug_mode(Some(DebugMode::Hex))
.init()?
.qrcode_option(
"https://www.google.com",
QRCodeOption::new(QRCodeModel::Model1, 6, QRCodeCorrectionLevel::M),
)?
.feed()?
.print_cut()?; // print() or print_cut() is mandatory to send the data to the printer
Ok(())
}use escpos::printer::Printer;
use escpos::utils::*;
use escpos::{driver::*, errors::Result};
fn main() -> Result<()> {
env_logger::init();
let driver = ConsoleDriver::open(true);
let mut printer = Printer::new(driver, Protocol::default(), None);
printer.debug_mode(Some(DebugMode::Hex))
.init()?
.bit_image_option(
"./resources/images/rust-logo-small.png",
BitImageOption::new(Some(128), None, BitImageSize::Normal)?,
)?
.feed()?
.print_cut()?; // print() or print_cut() is mandatory to send the data to the printer
Ok(())
}use escpos::printer::Printer;
use escpos::utils::*;
use escpos::{driver::*, errors::Result};
fn main() -> Result<()> {
env_logger::init();
let driver = ConsoleDriver::open(true);
Printer::new(driver.clone(), Protocol::default(), None)
.debug_mode(Some(DebugMode::Dec))
.real_time_status(RealTimeStatusRequest::Printer)?
.real_time_status(RealTimeStatusRequest::RollPaperSensor)?
.send_status()?;
let mut buf = [0; 1];
driver.read(&mut buf)?;
let status = RealTimeStatusResponse::parse(RealTimeStatusRequest::Printer, buf[0])?;
println!(
"Printer online: {}",
status.get(&RealTimeStatusResponse::Online).unwrap_or(&false)
);
Ok(())
}| Status | Command | Description | Feature |
|---|---|---|---|
| ✅ | init() |
Initialize printer (ESC @) |
|
| ✅ | print() |
Print document | |
| ✅ | reset() |
Hardware reset (ESC ? LF 0) |
|
| ✅ | cut() |
Paper cut (GS V A 0) |
|
| ✅ | partial_cut() |
Partial paper cut (GS V A 1) |
|
| ✅ | print_cut() |
Print and paper cut | |
| ✅ | page_code() |
Select character code table (ESC t) |
|
| ✅ | character_set() |
Select an international character set (ESC R) |
|
| ✅ | bold() |
Text bold (ESC E) |
|
| ✅ | underline() |
Text underline (ESC -) |
|
| ✅ | double_strike() |
Text double strike (ESC G) |
|
| ✅ | font() |
Text font (ESC M) |
|
| ✅ | flip() |
Text flip (ESC V) |
|
| ✅ | justify() |
Text justify (ESC a) |
|
| ✅ | reverse() |
Text reverse color (GS B) |
|
| ✅ | size() |
Text size (GS !) |
|
| ✅ | reset_size() |
Reset text size (GS !) |
|
| ✅ | smoothing() |
Smoothing mode (GS b) |
|
| ✅ | feed() |
Line feed (ESC d) |
|
| ✅ | feeds() |
Multiple lines feed (ESC d) |
|
| ✅ | line_spacing() |
Line spacing (ESC 3) |
|
| ✅ | reset_line_spacing() |
Reset line spacing (ESC 2) |
|
| ✅ | upside_down() |
Upside-down mode (ESC {) |
|
| ✅ | cash_drawer() |
Generate pulse (ESC p) |
|
| ✅ | write() |
Write text | |
| ✅ | writeln() |
Write text and line feed | |
| ✅ | custom() |
Custom command | |
| ✅ | custom_with_page_code() |
Custom command with page code | |
| ✅ | motion_units() |
Set horizontal and vertical motion units (GS P) |
|
| ✅ | ean13() |
Print EAN13 with default option | barcode |
| ✅ | ean13_option() |
Print EAN13 with custom option | barcode |
| ✅ | ean8() |
Print EAN8 with default option | barcode |
| ✅ | ean8_option() |
Print EAN8 with custom option | barcode |
| ✅ | upca() |
Print UPC-A with default option | barcode |
| ✅ | upca_option() |
Print UPC-A with custom option | barcode |
| ✅ | upce() |
Print UPC-E with default option | barcode |
| ✅ | upce_option() |
Print UPC-E with custom option | barcode |
| ✅ | code39() |
Print CODE 39 with default option | barcode |
| ✅ | code39_option() |
Print CODE 39 with custom option | barcode |
| ✅ | codabar() |
Print CODABAR with default option | barcode |
| ✅ | codabar_option() |
Print CODABAR with custom option | barcode |
| ✅ | itf() |
Print ITF with default option | barcode |
| ✅ | itf_option() |
Print ITF with custom option | barcode |
| ✅ | qrcode() |
Print QR code with default option | codes_2d |
| ✅ | qrcode_option() |
Print QR code with custom option | codes_2d |
| ✅ | bit_image() |
Print raster bit image with default option | graphics |
| ✅ | bit_image_option() |
Print raster bit image with custom option | graphics |
| ✅ | bit_image_from_bytes() |
Print raster bit image from bytes with default option | graphics |
| ✅ | bit_image_from_bytes_option() |
Print raster bit image from bytes with custom option | graphics |
| ✅ | gs1_databar_2d |
Print 2D GS1 DataBar with default option | codes_2d |
| ✅ | gs1_databar_2d_option |
Print 2D GS1 DataBar with custom option | codes_2d |
| ✅ | pdf417 |
Print PDF417 with default option | codes_2d |
| ✅ | pdf417_option |
Print PDF417 with custom option | codes_2d |
| ✅ | maxi_code |
Print MaxiCode with default option | codes_2d |
| ✅ | maxi_code_option |
Print MaxiCode with custom option | codes_2d |
| ✅ | data_matrix |
Print DataMatrix with default option | codes_2d |
| ✅ | data_matrix_option |
Print DataMatrix with custom option | codes_2d |
| ✅ | aztec |
Print Aztec code with default option | codes_2d |
| ✅ | aztec_option |
Print Aztec code with custom option | codes_2d |
| 🚧 | graphic() |
Print raster graphic with default option | graphics |
| 🚧 | graphic_option() |
Print raster graphic with custom option | graphics |
| ✅ | draw_line() |
Print a line | ui |
- ✅ Done
- 🚧 In progress
- ❌ To do
| Code | Implemented? |
|---|---|
| PC437 | ✅ |
| Katakana | ✅ |
| PC850 | ✅ |
| PC860 | ✅ |
| PC863 | ✅ |
| PC865 | ✅ |
| Hiragana | ❌ |
| PC851 | ✅ |
| PC853 | ✅ |
| PC857 | ✅ |
| PC737 | ✅ |
| ISO8859_7 | ✅ |
| WPC1252 | ✅ |
| PC866 | ✅ |
| PC852 | ✅ |
| PC858 | ✅ |
| PC720 | ❌ |
| WPC775 | ✅ |
| PC855 | ✅ |
| PC861 | ✅ |
| PC862 | ✅ |
| PC864 | ❌ |
| PC869 | ✅ |
| ISO8859_2 | ✅ |
| ISO8859_15 | ✅ |
| PC1098 | ❌ |
| PC1118 | ✅ |
| PC1119 | ✅ |
| PC1125 | ✅ |
| WPC1250 | ✅ |
| WPC1251 | ✅ |
| WPC1253 | ✅ |
| WPC1254 | ✅ |
| WPC1255 | ❌ |
| WPC1256 | ❌ |
| WPC1257 | ✅ |
| WPC1258 | ❌ |
| KZ1048 | ✅ |

