Skip to content
BabuleFredPublic

About

Печать чеков на термопринтере по-русски: ESC/POS, CP866/CP1251, раскладка, QR, картинки. Без обязательных зависимостей

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

2 Commits

Folders and files

Repository files navigation

escpos-ru

Python Tests Dependencies License

Печать чеков на термопринтере, по-русски.

Библиотека закрывает то, обо что обычно бьются при первой же попытке напечатать чек не на латинице: кириллицу в кодировке принтера, моноширинную раскладку под ширину ленты, QR, штрихкоды, картинки и доставку байт на сетевой принтер.

У текстовой части нет обязательных зависимостей — только стандартная библиотека Python.

from escpos_ru import Receipt, Printer, Charset

r = Receipt(width=32, charset=Charset.CP866)
r.rule()
r.bold_line("КУХНЯ / ПИЦЦА", align="center")
r.rule()
r.left_right("Заказ №1043", "12:40")
r.rule("-")
r.item(1, "Пицца Пепперони 33 см", 2, note="без лука")
r.rule("-")
r.left_right("Позиций:", "7")
r.feed(2).cut()

print(r.preview())                          # посмотреть глазами
Printer.network("192.168.1.50").send(r)     # напечатать
================================
         КУХНЯ / ПИЦЦА
================================
Заказ №1043                12:40
--------------------------------
1. Пицца Пепперони 33 см      x2
   > без лука
--------------------------------
Позиций:                       7
================================

Зачем это, если есть python-escpos

Потому что основная боль не в отправке байтов, а в кириллице.

Термопринтер не знает Unicode. Он печатает байты по таблице, которую вы ему указали командой ESC t n. Отправите UTF-8 — получите кракозябры. Отправите CP866, не выбрав страницу 17, — получите другие кракозябры. А если модель кириллицу не поддерживает вообще, честный выход один: транслитерация.

Здесь это три режима, и переключаются они одной строкой:

Charset Команда принтеру Когда
CP866 ESC t 17 большинство моделей с поддержкой кириллицы
CP1251 ESC t 46 часть моделей, Windows-совместимые
TRANSLIT — принтер кириллицу не умеет: Пицца → Picca
ASCII — гарантированно безопасный вывод
Receipt(width=32, charset=Charset.CP866)     # байты CP866 + ESC t 17
Receipt(width=32, charset=Charset.TRANSLIT)  # латиница, страница не выбирается

Ловушка, из-за которой чеки разъезжаются

Транслитерация удлиняет текст: Лимонад Дюшес 0.5 (17 знаков) превращается в Limonad Dyushes 0.5 (19). Строка, которая идеально влезала в 32 колонки по-русски, на принтере уезжает на две позиции.

Поэтому раскладка здесь считается в том виде, в котором текст уйдёт на бумагу, а не в исходном. И перед печатью чек можно проверить:

problems = r.check()
# ['строка 12 длиннее 32: 34 — "3. Limonad Dyushes 0.5          x3"']

r.check(strict=True)   # или сразу исключением

check() ловит три вещи: строки длиннее ширины ленты, табуляции (ломают моноширинность) и символы, которых нет в выбранной кодировке.

Предпросмотр без принтера

preview() возвращает текст чека без управляющих команд — ровно то, что окажется на бумаге. Это позволяет отлаживать макет, не подходя к железу, и писать тесты на раскладку.

python -m escpos_ru     # демонстрационный чек в двух кодировках

Раскладка

Модуль escpos_ru.layout — чистые функции «строки на входе, строки на выходе», без байтов и без железа:

from escpos_ru import layout

layout.rule(32, "=")                     # '================================'
layout.center("ИТОГО", 32)
layout.left_right("Сумма:", "1300 руб", 32)
layout.wrap("Позвонить за 10 минут", 32, indent="  ")
layout.item(1, "Пицца", 2, width=32, note="без лука")
layout.money(1300)                       # '1300 руб'

Строка позиции сама переносит длинное название, прижимает количество вправо и выравнивает продолжения по началу названия:

1. Пицца Пепперони 33 см      x2
   > без лука, соус отдельно
2. Сырный борт                x2

QR, штрихкод, картинка

r.qr("https://example.com/order/1043", module_size=5, ec="M")
r.barcode("4600000000000", kind="EAN13", height=80)
r.image("logo.png", dither=False)     # dither=False для чёткой графики

QR и штрихкод собираются вручную по спецификации (GS ( k, GS k) — без сторонних генераторов. Поддержаны CODE128, CODE39, EAN13, EAN8, UPC-A, ITF, CODABAR, CODE93.

Картинки — единственное место, где нужен Pillow:

pip install "escpos-ru[image]"

Доставка на принтер

Printer.network("192.168.1.50", port=9100)          # сетевой, сырой поток
Printer.file("out/tickets")                          # в папку — отладка и страховка
Printer.windows("XP-80C")                            # драйвер Windows (pywin32)
Printer.serial("COM3", baudrate=9600)                # COM-порт (pyserial)

Транспорт никогда не роняет заказ: send() возвращает результат, а не бросает исключение. Если сеть отвалилась, а указан fallback_dir, чек уезжает в файл, и вы об этом узнаете из результата:

p = Printer.network("192.168.1.50", retries=2, fallback_dir="out/tickets")
res = p.send(r)
# SendResult(ok=True, transport='file(fallback)', where='out/tickets/...',
#            error='192.168.1.50:9100 недоступен: ...')

Тесты

Зависимостей нет, ставить ничего не нужно:

python -m unittest discover -s tests -t .
# Ran 111 tests in 0.9s — OK

Тесты проверяют точные байтовые последовательности команд, раскладку на кириллице, поведение транслитерации и то, что чек не теряется при обрыве связи.

Примеры

pip install -e .                              # или PYTHONPATH=. перед запуском
python examples/kitchen_ticket.py             # кухонный чек по цехам
python examples/client_receipt.py             # чек клиенту с ценами и скидкой

Оба примера только печатают предпросмотр в консоль и ничего не отправляют на принтер.


English

A receipt-printing library for ESC/POS thermal printers with first-class Cyrillic support — the thing that usually breaks on the first non-Latin receipt.

  • Charset handling: CP866 (ESC t 17), CP1251 (ESC t 46), plus a transliteration fallback for printers with no Cyrillic code page at all.
  • Layout in the printed alphabet: transliteration widens text (Лимонад Дюшес → Limonad Dyushes), so column math is done on what will actually hit the paper. receipt.check() catches overflow, tabs and unencodable characters before you waste paper.
  • Zero dependencies for text, QR codes and barcodes — pure standard library. Pillow only for images, pywin32 only for the Windows driver, pyserial only for COM ports.
  • Preview without hardware: receipt.preview() returns the plain-text receipt, so layout can be unit-tested.
  • Transports never lose a ticket: send() returns a result instead of raising, and falls back to a file queue when the network printer is down.
from escpos_ru import Receipt, Printer, Charset

r = Receipt(width=32, charset=Charset.CP866)
r.bold_line("KITCHEN", align="center")
r.left_right("Order #1043", "12:40")
r.item(1, "Pepperoni pizza 33 cm", 2, note="no onion")
r.feed(2).cut()

Printer.network("192.168.1.50").send(r)

MIT licensed.


Лицензия

MIT. См. LICENSE.

About

Печать чеков на термопринтере по-русски: ESC/POS, CP866/CP1251, раскладка, QR, картинки. Без обязательных зависимостей

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages