escpos-thermal
A powerful Python library for ESC/POS thermal receipt printers.
Features
- Full ESC/POS Support - Text, formatting, barcodes, QR codes, images, and more
- Multiple Connections - Network (TCP/IP), USB, Serial, File, CUPS, and Windows printing
- Async Support - AsyncNetworkConnector for non-blocking I/O
- Image Dithering - Floyd-Steinberg, Atkinson, and ordered dithering algorithms
- Printer Status - Read paper status, online state, and error conditions
- Cash Drawer Control - Open drawers and check open/closed status
- Context Manager - Clean resource management with
withstatement - Logging - Built-in debug logging support
- 294 Tests - Comprehensive test coverage
Installation
pip install escpos-thermal
Optional Dependencies
# USB printer support
pip install pyusb
# Serial printer support
pip install pyserial
# QR code generation fallback
pip install qrcode
# Barcode generation fallback
pip install python-barcode
Quick Start
from escpos_thermal import Printer
from escpos_thermal.connectors import NetworkConnector
# Using context manager (recommended)
with Printer(NetworkConnector("192.168.1.100", 9100)) as printer:
printer.text("Hello, World!\n")
printer.barcode("123456789012", Printer.BARCODE_UPCA)
printer.qr_code("https://example.com")
printer.cut()
Connection Types
Network Printer (TCP/IP)
from escpos_thermal import Printer
from escpos_thermal.connectors import NetworkConnector
with Printer(NetworkConnector("192.168.1.100", 9100)) as printer:
printer.text("Network printing!\n")
printer.cut()
Async Network Printer
import asyncio
from escpos_thermal.connectors import AsyncNetworkConnector
async def print_async():
async with AsyncNetworkConnector("192.168.1.100", 9100) as conn:
await conn.write(b"\x1b@") # Initialize
await conn.write(b"Async printing!\n")
await conn.write(b"\x1dVA\x03") # Cut
asyncio.run(print_async())
USB Printer
from escpos_thermal import Printer
from escpos_thermal.connectors import USBConnector
# Find vendor/product ID with: lsusb
with Printer(USBConnector(0x04b8, 0x0202)) as printer:
printer.text("USB printing!\n")
printer.cut()
Serial Printer
from escpos_thermal import Printer
from escpos_thermal.connectors import SerialConnector
with Printer(SerialConnector("/dev/ttyUSB0", 9600)) as printer:
printer.text("Serial printing!\n")
printer.cut()
Text Formatting
with Printer(connector) as printer:
# Text sizes (1-8)
printer.set_text_size(2, 2)
printer.text("BIG TEXT\n")
printer.set_text_size(1, 1)
# Styles
printer.set_emphasis(True)
printer.text("Bold\n")
printer.set_emphasis(False)
printer.set_underline(Printer.UNDERLINE_SINGLE)
printer.text("Underlined\n")
printer.set_underline(Printer.UNDERLINE_NONE)
# Alignment
printer.set_justification(Printer.JUSTIFY_CENTER)
printer.text("Centered\n")
printer.set_justification(Printer.JUSTIFY_LEFT)
# Fonts
printer.set_font(Printer.FONT_B)
printer.text("Smaller font\n")
printer.set_font(Printer.FONT_A)
Barcodes
with Printer(connector) as printer:
# Configure barcode appearance
printer.set_barcode_height(80)
printer.set_barcode_width(3)
printer.set_barcode_text_position(Printer.BARCODE_TEXT_BELOW)
# Print various barcode types
printer.barcode("012345678905", Printer.BARCODE_UPCA)
printer.barcode("5901234123457", Printer.BARCODE_JAN13)
printer.barcode("{BHELLO123", Printer.BARCODE_CODE128)
printer.barcode("ABC123", Printer.BARCODE_CODE39)
QR Codes
with Printer(connector) as printer:
# Simple QR code
printer.qr_code("https://example.com")
# With options
printer.qr_code(
"https://example.com",
ec=Printer.QR_ECLEVEL_H, # High error correction
size=8, # Module size
model=Printer.QR_MODEL_2
)
Image Printing with Dithering
from escpos_thermal import Printer, PillowEscposImage, DitherMode
from escpos_thermal.connectors import NetworkConnector
with Printer(NetworkConnector("192.168.1.100")) as printer:
# Simple threshold (default)
img = PillowEscposImage("logo.png")
printer.graphics(img)
# Floyd-Steinberg dithering (best for photos)
img = PillowEscposImage("photo.jpg", dither=DitherMode.FLOYDSTEINBERG)
printer.graphics(img)
# Atkinson dithering (lighter, good for graphics)
img = PillowEscposImage("graphic.png", dither=DitherMode.ATKINSON)
printer.graphics(img)
# Custom threshold
img = PillowEscposImage("logo.png", threshold=100)
printer.graphics(img)
Convert Image to Monochrome
from PIL import Image
from escpos_thermal import PillowEscposImage, DitherMode
# Convert any image to printer-ready monochrome
pil_image = Image.open("photo.jpg")
mono = PillowEscposImage.to_monochrome(pil_image, dither=DitherMode.FLOYDSTEINBERG)
mono.save("preview.png") # Preview what will print
Printer Status
with Printer(connector) as printer:
# Check printer status
if printer.is_online():
print("Printer is online")
if printer.has_paper():
print("Paper is loaded")
else:
print("Paper is low or out!")
if printer.has_error():
print("Printer has an error")
Cash Drawer
with Printer(connector) as printer:
# Open cash drawer
printer.pulse() # Pin 0, default timing
printer.pulse(pin=1, on_ms=200, off_ms=400) # Pin 1, custom timing
# Check drawer status (requires compatible hardware)
if printer.is_drawer_open():
print("Drawer is open!")
Logging
import logging
# Enable debug logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger('escpos')
logger.setLevel(logging.DEBUG)
# Now printer operations will log debug info
with Printer(connector) as printer:
printer.text("Debug logging enabled\n")
Printer Profiles
from escpos_thermal import Printer, CapabilityProfile
from escpos_thermal.connectors import NetworkConnector
# List available profiles
profiles = CapabilityProfile.get_profile_names()
print(profiles)
# Use a specific profile
profile = CapabilityProfile.load("TM-T88IV")
with Printer(NetworkConnector("192.168.1.100"), profile) as printer:
printer.text("Using TM-T88IV profile\n")
API Reference
Printer Constants
| Category | Constants |
|---|---|
| Barcode Types | BARCODE_UPCA, BARCODE_UPCE, BARCODE_JAN13, BARCODE_JAN8, BARCODE_CODE39, BARCODE_ITF, BARCODE_CODABAR, BARCODE_CODE93, BARCODE_CODE128 |
| QR Code | QR_ECLEVEL_L/M/Q/H, QR_MODEL_1/2, QR_MICRO |
| Text | JUSTIFY_LEFT/CENTER/RIGHT, FONT_A/B/C, UNDERLINE_NONE/SINGLE/DOUBLE |
| Cut | CUT_FULL, CUT_PARTIAL |
| Images | IMG_DEFAULT, IMG_DOUBLE_WIDTH, IMG_DOUBLE_HEIGHT |
DitherMode Options
| Mode | Description |
|---|---|
DitherMode.NONE |
Simple threshold (fast, good for logos) |
DitherMode.FLOYDSTEINBERG |
Floyd-Steinberg error diffusion (best for photos) |
DitherMode.ATKINSON |
Atkinson dithering (lighter, good for graphics) |
DitherMode.ORDERED |
Bayer ordered dithering (fast, consistent) |
Connectors
| Connector | Use Case | Requirements |
|---|---|---|
NetworkConnector |
TCP/IP printers | None |
AsyncNetworkConnector |
Async TCP/IP | None |
USBConnector |
USB printers | pyusb |
SerialConnector |
Serial printers | pyserial |
FileConnector |
Device files | None |
CupsConnector |
CUPS (Linux/macOS) | pycups |
WindowsConnector |
Windows API | Windows |
DummyConnector |
Testing | None |
Requirements
- Python 3.8+
- Pillow (for image support)
License
MIT License
Credits
- Author: Yevhen Salitrynskyi
- Based on: escpos-php by Michael Billington
Metadata
Release files for escpos-thermal 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| escpos_thermal-1.0.0.tar.gz | 62.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| escpos_thermal-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 128.6 kB
Release files / escpos_thermal-1.0.0.tar.gz
| Download URL | escpos_thermal-1.0.0.tar.gz |
|---|---|
| Size | 62.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7dcee6ef4cecca9a3a0fe0bca2d0523233234007a142e6c60335f098d17c6729
|
|
BLAKE2b-256 checksum How to use checksums |
92b6640a61b563f6d05c3be49fbefd772a904731de82ba6169a913f07ca136e4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 21, 2025.
Transparency logRelease files / escpos_thermal-1.0.0-py3-none-any.whl
| Download URL | escpos_thermal-1.0.0-py3-none-any.whl |
|---|---|
| Size | 66.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a094fd39a6c87a00ebbef708b0ee7e41d5ad1d9e0d021a264630f2290f91792e
|
|
BLAKE2b-256 checksum How to use checksums |
16844e73b9c7c04076a736ad1cdd341ff8ba76fa14c91ff00736a357a4c622e1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 21, 2025.
Transparency log