MCPcopy Index your code
hub / github.com/fabienbellanger/escpos-rs

github.com/fabienbellanger/escpos-rs @0.19.0

Chat with this repo
repository ↗ · DeepWiki ↗ · release 0.19.0 ↗ · + Follow
490 symbols 844 edges 45 files 237 documented · 48%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

ESC/POS Rust implementation

Build status Crates.io Documentation

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.

Ticket Receipt
Printed on Aures ODP 333

This project is strongly inspired by recibo (Rust), escposify (Rust) and escpos (Go).

Installation

For standard functionalities (e.g., printing text), no additional dependencies are required:

[dependencies]
escpos = "0.19.0"

If you need all features, you can use the full feature:

[dependencies]
escpos = { version = "0.19.0", features = ["full"] }

Or you can use cargo add command:

cargo add escpos
cargo add escpos -F full

Code coverage

Tool used: tarpaulin

cargo install cargo-tarpaulin
cargo tarpaulin --all-features --tests

Results:

  • [2025-09-15] 57.62% coverage, 1172/2034 lines covered

MSRV

Tool used: cargo-msrv

cargo install cargo-msrv
cargo msrv find
cargo msrv verify

Features list

Name Description Default
std Enable std support (disable for no_std + alloc environments)
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 (requires std)
usb Enable USB feature (requires std)
native_usb Enable native USB feature (requires std)
hidapi Enable HidApi feature (requires std)
serial_port Enable Serial port feature (requires std)
usbprint Enable Windows USB print driver (usbprint.sys via Win32 API)
ui Enable ui feature (UI components)
full Enable all features

no_std support

The crate can be used on bare-metal targets (microcontrollers, kernels…) by disabling default features. Only alloc is required:

[dependencies]
escpos = { version = "0.18", default-features = false, features = ["barcodes", "codes_2d"] }

The built-in Console, Network and File drivers as well as the graphics feature require std. In no_std mode you implement the Driver trait for your peripheral (UART, SPI, USB endpoint, …) and pass it to Printer::new. The Printer::driver accessor lets you recover the driver from a Printer.

See examples/no_std_codes.rs for a minimal example with a custom in-memory driver and barcodes / 2D codes — all the protocol-level APIs (barcodes, QR Code, PDF417, DataMatrix, Aztec, MaxiCode, page codes, status…) work in no_std. The codes themselves are rendered by the printer's firmware: the crate only serializes the ESC/POS commands, so the embedded-side cost is minimal.

Examples

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 full

The list of all the examples can be found here.

Simple text formatting

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(())
}

EAN13

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(())
}

QR Code

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(())
}

Bit image (with graphics feature enabled)

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(())
}

Windows USB print driver (with usbprint feature enabled, Windows only)

Drives a POS printer through the standard Windows usbprint.sys kernel driver using the Win32 API (CreateFile / ReadFile / WriteFile). No Zadig / WinUSB / libusb swap required — the device keeps working with the regular Windows print spooler at the same time.

```rust,ignore use escpos::printer::Printer; use escpos::utils::; use escpos::{driver::, errors::Result};

fn main() -> Result<()> { env_logger::init();

// List USB printers exposed by usbprint.sys
for info in WindowsUsbPrintDriver::list()? {
    println!("{} (VID={:?} PID={:?})", info.device_path, info.vendor_id, info.product_id);
}

// Option 1: open by USB vendor/product id
let driver = WindowsUsbPrintDriver::open_by_vid_pid(0x0525, 0xa700)?;

// Option 2: open by full device interface path
// let driver = WindowsUsbPrintDriver::open(r"\\?\USB#VID_0525&PID_A700#...")?;

Printer::new(driver, Protocol::default(), None)
    .init()?
    .writeln("Hello from Windows usbprint!")?
    .print_cut()?;

Ok(())

}


### Check printer status

```rust
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(())
}

Commands list

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

Extension points exported contracts — how you extend this code

Driver (Interface)
Printer driver trait A custom driver can be implemented by implementing this trait. [9 implementers]
src/io/driver.rs
UIComponent (Interface)
UIComponent trait [1 implementers]
src/domain/ui/mod.rs

Core symbols most depended-on inside this repo

command
called by 42
src/printer.rs
writeln
called by 39
src/printer.rs
feed
called by 21
src/printer.rs
style
called by 18
src/domain/ui/line.rs
init
called by 14
src/printer.rs
barcode
called by 14
src/printer.rs
print_cut
called by 13
src/printer.rs
justify
called by 11
src/printer.rs

Shape

Method 285
Function 132
Class 40
Enum 31
Interface 2

Languages

Rust100%
TypeScript1%

Modules by API surface

src/domain/protocol.rs138 symbols
src/printer.rs77 symbols
src/io/driver.rs33 symbols
src/domain/graphics.rs28 symbols
src/domain/codes/barcodes.rs24 symbols
src/domain/ui/line.rs21 symbols
src/domain/bit_image.rs21 symbols
src/domain/codes/pdf417.rs16 symbols
src/domain/codes/qrcode.rs14 symbols
src/domain/codes/gs1_databar_2d.rs12 symbols
src/domain/codes/data_matrix.rs12 symbols
src/domain/codes/aztec.rs12 symbols

For agents

$ claude mcp add escpos-rs \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page