print-labels-gui/print-labels-gui.py

284 lines
10 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/python3
"""
Скрипт с графическим интерфейсом
для печати этикеток на принтере серий brother p-touch
(форк) на основе скрипта Анны Полковниковой (https://gitea.basealt.ru/polkovnikovaav/ptouch-print-labels)
подробности и настройки в README.md
зи
"""
from PySide6.QtWidgets import QApplication
from PySide6 import QtGui
from PySide6.QtWidgets import QMainWindow, QWidget, QVBoxLayout, QPushButton, QComboBox, QTableWidget, QHBoxLayout, QMessageBox, QTableWidgetItem
import subprocess
import time
import os
import sys
import glob
import re
from PIL import Image, ImageOps, ImageDraw, ImageFont
from barcode import EAN13
from barcode.writer import ImageWriter
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.version = "v1.3"
self.device_names = ['компьютер', 'монитор', 'сетевое об.',
'токен', 'принтер/МФУ', 'флешка', 'HID', 'UPS', 'другое']
self.setWindowTitle(f"Печать стикеров инвентаризации {self.version}")
self.resize(700, 500)
# таблица
self.q_table = QTableWidget()
self.init_table()
# кнопка печати
self.q_print_button = QPushButton()
self.q_print_button.setText("печать")
self.q_print_button.clicked.connect(self.start_print)
self.q_print_button.setMinimumSize(15, 50)
# кнопка очистки
self.q_clear_button = QPushButton()
self.q_clear_button.setText("очистка")
self.q_clear_button.clicked.connect(self.init_table)
self.q_clear_button.setMinimumSize(15, 50)
self.qh_layout2 = QHBoxLayout()
self.qh_layout2.addWidget(self.q_print_button)
self.qh_layout2.addWidget(self.q_clear_button)
# компоновщик1 вертикальный
self.qv_layout1 = QVBoxLayout()
self.qv_layout1.setContentsMargins(15, 15, 15, 15)
self.qv_layout1.setSpacing(15)
self.qv_layout1.addWidget(self.q_table)
self.qv_layout1.addLayout(self.qh_layout2)
# компоновщик горизонтальный
self.qh_layout = QHBoxLayout()
self.qh_layout.addLayout(self.qv_layout1)
# обобщающий виджет
self.q_central_widget = QWidget()
self.q_central_widget.setLayout(self.qh_layout)
self.setCentralWidget(self.q_central_widget)
# выпадающий список типов и кодовые соответствия
self.combo_type_items = {
"компьютер": "21",
"монитор": "22",
"сетевое об.": "23",
"токен": "24",
"принтер/МФУ": "25",
"флешка": "26",
"HID": "27",
"UPS": "28",
"другое": "29",
}
def gen_message_box(self, message_str):
msg_box = QMessageBox()
msg_box.setWindowTitle("Внимание")
msg_box.setText(message_str)
msg_box.setIcon(QMessageBox.Information)
msg_box.exec()
# проверка строки на соответствие строго 12 цифр
def check_inventory_number(self, inventoryN):
pattern=r'^\d{12,17}$'
if re.match(pattern, inventoryN):
return True
else:
return False
# инициализация таблицы
def init_table(self):
self.q_table.clear()
self.q_table.setColumnCount(3)
self.q_table.setHorizontalHeaderLabels(
['Текст', 'Тип', 'Инв.Н (пустое - генерация)'])
self.q_table.setRowCount(10)
self.q_table.setColumnWidth(0, 200)
self.q_table.setColumnWidth(1, 110)
self.q_table.setColumnWidth(2, 200)
# кладем комбобоксы в ячейки
for i in range(0, 10):
self.q_combo = QComboBox(self)
self.q_combo.addItems(self.device_names)
self.q_table.setCellWidget(i, 1, self.q_combo)
# удаляем временные Png файлы
def clear_temp_png_files(self):
self.set_current_location()
fileList = glob.glob('*.png')
# Iterate over the list of filepaths & remove each file.
for filePath in fileList:
try:
os.remove(filePath)
except Exception:
self.gen_message_box("Ошибка удаления файла : ", filePath)
# получаем текущий каталог и переходим в него
def set_current_location(self):
path_there = os.path.dirname(os.path.realpath(__file__))
os.chdir(path_there)
# генерация штрих-кода с контрльной суммой
def gen_ean13(self, product_code: str):
# добавляем псевдослучаное значение (от времени к коду продукта)
# при пакетной генерации между генерациями необходим интервал
time.sleep(1)
digits_s = product_code + str(round(time.time()))
# строка продукта в список чисел
digits = [int(i) for i in digits_s]
# контрольная сумма по алгоритму ЛУна
checksum = (10 - (sum(digits[1::2]) * 3 + sum(digits[::2])) % 10) % 10
return "".join(str(i) for i in (digits + [checksum]))
# генерация картинки
def create_code_png(self, filename, code, text):
self.set_current_location()
ean13_code = EAN13(code, writer=ImageWriter())
image = ean13_code.render(
writer_options={
"module_height": 11.0,
"module_width": 0.3,
"dpi": 169,
"font_size": 0,
"text_distance": 1,
"write_text": None,
}
)
image = image.convert("1", dither=Image.Dither.NONE)
image = ImageOps.expand(image, border=17, fill=1)
draw = ImageDraw.Draw(image)
# загружаем шрифт
dst = "terminus.pil"
font = ImageFont.load(dst)
text_length = draw.textlength(text, font=font)
code_text_length = draw.textlength(code, font=font)
draw.text(((image.width - text_length) / 2, 3),
text, fill="black", font=font)
draw.text(
((image.width - code_text_length) / 2, 100),
code,
fill="black",
font=font,
)
image.save(filename)
# запуск всего процесса (генерация и печать)
def start_print(self):
# удаляем старые png-файлы
self.clear_temp_png_files()
for row in range(0, self.q_table.rowCount()):
#print(row)
# проверка Инв. Номера на корректность
if self.q_table.item(row, 2) is not None and self.check_inventory_number(self.q_table.item(row, 2).text()) is False:
self.gen_message_box(
"инвентарный номер должен содержать минимум 12 цифр")
self.q_table.setItem(row, 2, QTableWidgetItem(""))
return None
# если ТЕКСТ и ИН заполнены
if self.q_table.item(row, 0) is not None and self.q_table.item(row, 2) is not None:
#print(self.q_table.item(row, 0).text())
combo_widget = self.q_table.cellWidget(row, 1)
type_device = self.combo_type_items[combo_widget.currentText()]
barcode = self.q_table.item(row, 2).text()
self.create_code_png(
f"temp-{row}.png", barcode, self.q_table.item(row, 0).text())
# если только ТЕКСТ заполнен
if self.q_table.item(row, 0) is not None and self.q_table.item(row, 2) is None:
#print(self.q_table.item(row, 0).text())
combo_widget = self.q_table.cellWidget(row, 1)
type_device = self.combo_type_items[combo_widget.currentText()]
barcode = self.gen_ean13(type_device)
self.create_code_png(
f"temp-{row}.png", barcode, self.q_table.item(row, 0).text())
# запуск утилиты печати сфомированного изображения
self.start_process()
# удаляем временные файлы
self.clear_temp_png_files()
def start_process(self):
# получаем список файлов
file_list_to_print = glob.glob('*.png')
# подготовка строки параметров для запуска
prepare_cmd = ""
for file_name in file_list_to_print:
prepare_cmd = prepare_cmd+" --image "+file_name+" --pad 5"
prepare_cmd=prepare_cmd[:-8]
#print(prepare_cmd)
subprocess.run("ptouch-print "+prepare_cmd,shell=True)
if __name__ == '__main__':
app = QApplication(sys.argv)
configparser = ChildProcessError
# таблица стилей (задаем размер шрифта)
style_sheet01 = """
* {
font-size: 10pt;
}
"""
# Применение таблицы стилей (размер шрифта) ко всему приложению
app.setStyleSheet(style_sheet01)
window = MainWindow()
# Установить размер окна
window.resize(600, 500)
# Получить допустимое разрешение
SrcSize = QtGui.QScreen.availableGeometry(QApplication.primaryScreen())
frmX = (SrcSize.width() - window.width())/2
frmY = (SrcSize.height() - window.height())/2
window.move(frmX, frmY)
window.show()
sys.exit(app.exec_())