Обновить print-labels-gui.py
переделка под графический интерфейс добавление логики под графический интерфейс мелкие правки передачи данных в методы генерации
This commit is contained in:
parent
a57b7f1ea2
commit
6ac996d6c9
106
barcodegen.py
106
barcodegen.py
@ -1,106 +0,0 @@
|
||||
import argparse
|
||||
import pathlib
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from textwrap import dedent
|
||||
|
||||
from PIL import Image, ImageOps, ImageDraw, ImageFont
|
||||
from barcode import EAN13
|
||||
from barcode.writer import ImageWriter
|
||||
|
||||
PRODUCT_TYPES = {
|
||||
"comp": ("21", "инвентарный номер для компьютера"),
|
||||
"mon": ("22", "инвентарный номер для монитора"),
|
||||
"net": ("23", "инвентарный номер для сетевого оборудования"),
|
||||
"token": ("24", "инвентарный номер для токена"),
|
||||
"print": ("25", "инвентарный номер для принтера/МФУ"),
|
||||
"flash": ("26", "инвентарный номер для флешки"),
|
||||
"hid": ("27", "инвентарный номер для HID устройств"),
|
||||
"ups": ("28", "инвентарный номер для UPS устройств"),
|
||||
"other": ("29", "инвентарный номер для других устройств"),
|
||||
}
|
||||
|
||||
BARCODES_PATH = pathlib.Path().absolute() / "barcodes"
|
||||
|
||||
|
||||
def gen_ean13(ptype: str):
|
||||
product_code = PRODUCT_TYPES[ptype][0]
|
||||
digits = product_code + str(round(time.time()))
|
||||
digits = [int(i) for i in digits]
|
||||
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(filename: str | pathlib.Path, code, text):
|
||||
if not filename.parent.exists():
|
||||
filename.parent.mkdir(parents=True)
|
||||
|
||||
my_code = EAN13(code, writer=ImageWriter())
|
||||
|
||||
image = my_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 parse_args():
|
||||
help_for_text = """\
|
||||
code is must be a 13 digit code
|
||||
or one of the following:
|
||||
|
||||
"""
|
||||
help_for_text = dedent(help_for_text) + "\n".join(
|
||||
f"{code} - {desc[1]}" for code, desc in PRODUCT_TYPES.items()
|
||||
)
|
||||
parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter)
|
||||
parser.add_argument("code", type=str, help=help_for_text)
|
||||
parser.add_argument(
|
||||
"text", type=str, nargs="?", default="", help="Description for barcode"
|
||||
)
|
||||
parser.add_argument("--print", action=argparse.BooleanOptionalAction, default=True)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
if args.code not in PRODUCT_TYPES:
|
||||
if args.code.isdigit() and len(args.code) == 13:
|
||||
barcode = args.code
|
||||
else:
|
||||
print("Invalid args")
|
||||
sys.exit(1)
|
||||
else:
|
||||
barcode = gen_ean13(args.code)
|
||||
|
||||
filename = BARCODES_PATH / f"{barcode}.png"
|
||||
print(f"Generated code: {barcode}")
|
||||
create_code_png(filename, barcode, args.text)
|
||||
if args.print:
|
||||
subprocess.run(["ptouch-print", "--image", filename])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
248
print-labels-gui.py
Executable file
248
print-labels-gui.py
Executable file
@ -0,0 +1,248 @@
|
||||
#!/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,QtWidgets
|
||||
from PySide6.QtWidgets import QMainWindow, QWidget, QLabel,QVBoxLayout, QPushButton,QGridLayout,QLineEdit, QComboBox,QMessageBox
|
||||
|
||||
import subprocess
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
|
||||
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.conf="barcode2-gui.ini"
|
||||
|
||||
self.setWindowTitle('Печать стикеров')
|
||||
self.q_button_start = QPushButton('печать')
|
||||
self.q_button_start.clicked.connect(self.start_print)
|
||||
|
||||
self.q_label1 = QLabel()
|
||||
self.q_label2 = QLabel()
|
||||
self.q_label3 = QLabel()
|
||||
|
||||
|
||||
self.q_label1.setText("Введите текст:")
|
||||
self.q_label2.setText("Введите SN (не вводить - генерация):")
|
||||
self.q_label3.setText("Выберите тип устройства:")
|
||||
|
||||
self.q_combo = QComboBox(self)
|
||||
|
||||
self.q_combo.addItem("компьютер")
|
||||
self.q_combo.addItem("монитор")
|
||||
self.q_combo.addItem("сетевое об.")
|
||||
self.q_combo.addItem("токен")
|
||||
self.q_combo.addItem("принтер/МФУ")
|
||||
self.q_combo.addItem("флешка")
|
||||
self.q_combo.addItem("HID")
|
||||
self.q_combo.addItem("UPS")
|
||||
self.q_combo.addItem("другое")
|
||||
|
||||
self.q_button_start=QPushButton("печать")
|
||||
self.q_button_start.setMinimumSize(20,80)
|
||||
|
||||
self.q_button_start.clicked.connect(self.start_print)
|
||||
|
||||
self.grid_layout = QGridLayout()
|
||||
self.layout1 = QVBoxLayout()
|
||||
|
||||
self.q_edit1=QLineEdit() # текст (над ШК)
|
||||
self.q_edit2=QLineEdit() # вводимый свой серийник (если не нужна генерациия)
|
||||
self.q_edit3=QLineEdit() # выводимый SN для справки
|
||||
self.q_edit3.setReadOnly(True)
|
||||
|
||||
self.layout1.addWidget(self.q_label1)
|
||||
self.layout1.addWidget(self.q_edit1)
|
||||
self.layout1.addWidget(self.q_label2)
|
||||
self.layout1.addWidget(self.q_edit2)
|
||||
|
||||
self.layout1.addWidget(self.q_label3)
|
||||
self.layout1.addWidget(self.q_combo)
|
||||
self.layout1.addWidget(self.q_button_start)
|
||||
self.layout1.addWidget(self.q_edit3)
|
||||
|
||||
|
||||
self.grid_layout.setRowStretch(5,0)
|
||||
self.grid_layout.setRowStretch(20,1)
|
||||
self.grid_layout.setRowStretch(1,2)
|
||||
self.grid_layout.setRowStretch(1,3)
|
||||
self.grid_layout.setRowStretch(1,4)
|
||||
self.grid_layout.setRowStretch(100,5)
|
||||
self.grid_layout.setRowStretch(1,6)
|
||||
|
||||
self.grid_layout.addWidget(self.q_label1, 0,0)
|
||||
self.grid_layout.addWidget(self.q_edit1, 1,0)
|
||||
self.grid_layout.addWidget(self.q_label2, 2,0)
|
||||
self.grid_layout.addWidget(self.q_edit2, 3,0)
|
||||
self.grid_layout.addWidget(self.q_label3, 4,0)
|
||||
self.grid_layout.addWidget(self.q_combo, 5,0)
|
||||
self.grid_layout.addWidget(self.q_button_start,6,0)
|
||||
self.grid_layout.addWidget(self.q_edit3,7,0) # шк-код текстом
|
||||
|
||||
|
||||
self.content_widget = QWidget()
|
||||
self.content_widget.setLayout(self.grid_layout)
|
||||
self.setCentralWidget(self.content_widget)
|
||||
|
||||
# выпадающий список типов и кодовые соответствия
|
||||
self.combo_type_items = {
|
||||
|
||||
"компьютер":"21",
|
||||
"монитор":"22",
|
||||
"сетевое об.":"23",
|
||||
"токен":"24",
|
||||
"принтер/МФУ":"25",
|
||||
"флешка":"26",
|
||||
"HID":"27",
|
||||
"UPS":"28",
|
||||
"другое":"29",
|
||||
}
|
||||
|
||||
|
||||
# получаем текущий каталог и переходим в него
|
||||
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):
|
||||
|
||||
# добавляем псевдослучаное значение (от времени к коду продукта)
|
||||
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):
|
||||
|
||||
|
||||
# берем ID по типу оборудования
|
||||
type_device=self.combo_type_items[self.q_combo.currentText()]
|
||||
|
||||
# берем текст подписи
|
||||
text_data=self.q_edit1.text()
|
||||
|
||||
barcode = self.gen_ean13(type_device)
|
||||
|
||||
# если ввели свой SN, передаем его в создание ШК
|
||||
if len(self.q_edit2.text())>0:
|
||||
if len(self.q_edit2.text())==12:
|
||||
barcode=self.q_edit2.text()
|
||||
else:
|
||||
msg = QMessageBox()
|
||||
msg.setWindowTitle("Внимание")
|
||||
msg.setText("Должно быть 12 знаков")
|
||||
msg.setIcon(QMessageBox.Warning)
|
||||
msg.exec_()
|
||||
exit(0)
|
||||
if len(self.q_edit2.text())==0:
|
||||
self.q_edit3.setText(barcode)
|
||||
|
||||
self.create_code_png("temp.png", barcode, text_data)
|
||||
self.start_process()
|
||||
|
||||
# запуск непосредственно печати, с SUDO
|
||||
def start_process(self):
|
||||
password, ok = QtWidgets.QInputDialog.getText(None, "SUDO", "Введите пароль:",QLineEdit.Password)
|
||||
if ok:
|
||||
subprocess.run(["sudo", "-S", "ptouch-print", "--image", "temp.png"], input=password.encode() + b"\n")
|
||||
|
||||
# если без sudo
|
||||
# def start_process(self):
|
||||
# subprocess.run(["sudo","ptouch-print", "--image", "temp.png"])
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = QApplication(sys.argv)
|
||||
configparser = ChildProcessError
|
||||
|
||||
# таблица стилей (задаем размер шрифта)
|
||||
style_sheet01 = """
|
||||
* {
|
||||
font-size: 11pt;
|
||||
}
|
||||
"""
|
||||
|
||||
# Применение таблицы стилей (размер шрифта) ко всему приложению
|
||||
app.setStyleSheet(style_sheet01)
|
||||
|
||||
window = MainWindow()
|
||||
|
||||
# Установить размер окна
|
||||
window.resize(500, 300)
|
||||
|
||||
# Получить допустимое разрешение
|
||||
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_())
|
Loading…
x
Reference in New Issue
Block a user