feat: Add Web iface with QR codes
This commit is contained in:
parent
b4bf6552f6
commit
783d9b6d34
10 changed files with 1293 additions and 739 deletions
75
labeler/adapter/cli.py
Normal file
75
labeler/adapter/cli.py
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
import os
|
||||
|
||||
from labeler.app.labeler import Application
|
||||
from labeler.infra.e550w_printer.printer import E550W
|
||||
from labeler.infra.renderer import PILRenderer
|
||||
|
||||
|
||||
class LabelingBot:
|
||||
def __init__(self, app: Application):
|
||||
self.app = app
|
||||
|
||||
def media_info(self):
|
||||
media = self.app.get_installed_media()
|
||||
print(f"Installed medium: {media}")
|
||||
|
||||
def simple_label(self, label_text, label_length=0):
|
||||
try:
|
||||
label = self.app.print_label(text=label_text, length=label_length)
|
||||
except Exception as e:
|
||||
print(f"There was an exception: {e}")
|
||||
|
||||
def get_qrcode(self, label_text, label_length=0):
|
||||
label = self.app.render_qrcode_preview(text=label_text, length=label_length)
|
||||
return label
|
||||
|
||||
def print_qrcode(self, label_text, label_length=0):
|
||||
try:
|
||||
label = self.app.print_qrcode(text=label_text, length=label_length)
|
||||
except Exception as e:
|
||||
print(f"There was an exception: {e}")
|
||||
|
||||
# async def label_length(self):
|
||||
# await update.message.reply_text(
|
||||
# "Hello! Please tell me the length of the label, enter 0 for auto:"
|
||||
# )
|
||||
# return LABEL_LENGTH
|
||||
#
|
||||
# async def label_text(self, update: Update, context: CallbackContext) -> int:
|
||||
# user_input = update.message.text
|
||||
# context.user_data["length"] = int(user_input)
|
||||
# await update.message.reply_text("Now, please tell me the text of the label:")
|
||||
# return LABEL_TEXT
|
||||
#
|
||||
# async def simple_label(self, update: Update, context: CallbackContext) -> int:
|
||||
# user_input = update.message.text
|
||||
# context.user_data["label"] = user_input
|
||||
# try:
|
||||
# label = self.app.print_label(
|
||||
# text=context.user_data["label"], length=context.user_data["length"]
|
||||
# )
|
||||
# except Exception as e:
|
||||
# await update.message.reply_text(f"There was an exception: {e}")
|
||||
# return ConversationHandler.END
|
||||
#
|
||||
# await update.message.reply_photo(
|
||||
# label.bytes, f'Your label is: {context.user_data["label"]}'
|
||||
# )
|
||||
# return ConversationHandler.END
|
||||
#
|
||||
# async def cancel(self, update: Update, context: CallbackContext) -> int:
|
||||
# await update.message.reply_text("Cancelled.")
|
||||
# return ConversationHandler.END
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
application = Application(PILRenderer(), E550W(os.environ.get("PRINTER_IP")))
|
||||
bot = LabelingBot(application)
|
||||
|
||||
LABEL_LENGTH, LABEL_TEXT = range(2)
|
||||
|
||||
bot.media_info()
|
||||
label = bot.get_qrcode("512", 25)
|
||||
with open("label.png", "wb") as preview:
|
||||
preview.write(label.bytes)
|
||||
label = bot.print_qrcode("512", 25)
|
||||
80
labeler/adapter/fastapi_srv.py
Normal file
80
labeler/adapter/fastapi_srv.py
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
import os
|
||||
|
||||
from labeler.app.labeler import Application
|
||||
from labeler.infra.e550w_printer.printer import E550W
|
||||
from labeler.infra.renderer import PILRenderer
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
class LabelingBot:
|
||||
def __init__(self, app: Application):
|
||||
self.app = app
|
||||
|
||||
def media_info(self):
|
||||
media = self.app.get_installed_media()
|
||||
print(f"Installed medium: {media}")
|
||||
|
||||
def simple_label(self, label_text, label_length=0):
|
||||
try:
|
||||
label = self.app.print_label(text=label_text, length=label_length)
|
||||
except Exception as e:
|
||||
print(f"There was an exception: {e}")
|
||||
|
||||
def get_qrcode(self, label_text, label_length=0):
|
||||
label = self.app.render_qrcode_preview(text=label_text, length=label_length)
|
||||
return label
|
||||
|
||||
def print_qrcode(self, label_text, label_length=0):
|
||||
try:
|
||||
label = self.app.print_qrcode(text=label_text, length=label_length)
|
||||
except Exception as e:
|
||||
print(f"There was an exception: {e}")
|
||||
|
||||
# async def label_length(self):
|
||||
# await update.message.reply_text(
|
||||
# "Hello! Please tell me the length of the label, enter 0 for auto:"
|
||||
# )
|
||||
# return LABEL_LENGTH
|
||||
#
|
||||
# async def label_text(self, update: Update, context: CallbackContext) -> int:
|
||||
# user_input = update.message.text
|
||||
# context.user_data["length"] = int(user_input)
|
||||
# await update.message.reply_text("Now, please tell me the text of the label:")
|
||||
# return LABEL_TEXT
|
||||
#
|
||||
# async def simple_label(self, update: Update, context: CallbackContext) -> int:
|
||||
# user_input = update.message.text
|
||||
# context.user_data["label"] = user_input
|
||||
# try:
|
||||
# label = self.app.print_label(
|
||||
# text=context.user_data["label"], length=context.user_data["length"]
|
||||
# )
|
||||
# except Exception as e:
|
||||
# await update.message.reply_text(f"There was an exception: {e}")
|
||||
# return ConversationHandler.END
|
||||
#
|
||||
# await update.message.reply_photo(
|
||||
# label.bytes, f'Your label is: {context.user_data["label"]}'
|
||||
# )
|
||||
# return ConversationHandler.END
|
||||
#
|
||||
# async def cancel(self, update: Update, context: CallbackContext) -> int:
|
||||
# await update.message.reply_text("Cancelled.")
|
||||
# return ConversationHandler.END
|
||||
|
||||
|
||||
@app.get("/print/{item_id}")
|
||||
def print_item(item_id: int, q: str | None = None):
|
||||
application = Application(PILRenderer(), E550W(os.environ.get("PRINTER_IP")))
|
||||
bot = LabelingBot(application)
|
||||
|
||||
LABEL_LENGTH, LABEL_TEXT = range(2)
|
||||
|
||||
bot.media_info()
|
||||
label = bot.get_qrcode(item_id, 25)
|
||||
with open("label.png", "wb") as preview:
|
||||
preview.write(label.bytes)
|
||||
bot.print_qrcode(item_id, 25)
|
||||
|
|
@ -31,6 +31,23 @@ class Application:
|
|||
|
||||
self.renderer.render_label(label_definition)
|
||||
|
||||
def render_qrcode_preview(self, text: str, length: int = None) -> Label:
|
||||
media = self.printer.get_installed_media()
|
||||
|
||||
if length != 0:
|
||||
label_length = Dimension(mm=length) - 2 * media.minimal_margin_horizontal
|
||||
else:
|
||||
label_length = None
|
||||
|
||||
label_definition = LabelDefinition(
|
||||
text=text,
|
||||
length=label_length,
|
||||
width=media.printable_width,
|
||||
dpi=media.dpi,
|
||||
)
|
||||
|
||||
return self.renderer.render_qrcode(label_definition)
|
||||
|
||||
def print_label(self, text: str, length: int = None) -> Image:
|
||||
media = self.printer.get_installed_media()
|
||||
|
||||
|
|
@ -50,5 +67,24 @@ class Application:
|
|||
self.printer.print_label(label)
|
||||
return label
|
||||
|
||||
def print_qrcode(self, text: str, length: int = None) -> Image:
|
||||
media = self.printer.get_installed_media()
|
||||
|
||||
if length != 0:
|
||||
label_length = Dimension(mm=length) - 2 * media.minimal_margin_horizontal
|
||||
else:
|
||||
label_length = None
|
||||
|
||||
label_definition = LabelDefinition(
|
||||
text=text,
|
||||
length=label_length,
|
||||
width=media.printable_width,
|
||||
dpi=media.dpi,
|
||||
)
|
||||
|
||||
label = self.renderer.render_qrcode(label_definition)
|
||||
self.printer.print_label(label)
|
||||
return label
|
||||
|
||||
def get_installed_media(self) -> MediaDefinition:
|
||||
return self.printer.get_installed_media()
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ from math import inf
|
|||
|
||||
from brother_ql import BrotherQLRaster, create_label
|
||||
from brother_ql.backends import guess_backend, backend_factory
|
||||
from brother_ql.conversion import convert
|
||||
from pysnmp.entity.engine import SnmpEngine
|
||||
from pysnmp.hlapi import getCmd, CommunityData, UdpTransportTarget, ContextData
|
||||
from pysnmp.smi.rfc1902 import ObjectType, ObjectIdentity
|
||||
|
|
@ -43,9 +44,9 @@ class E550W(Printer):
|
|||
im = PILImage.open(io.BytesIO(label.bytes))
|
||||
|
||||
qlr = BrotherQLRaster("PT-E550W")
|
||||
create_label(
|
||||
convert(
|
||||
qlr,
|
||||
im,
|
||||
[im],
|
||||
self.__media_width_to_type(label.height),
|
||||
red=False,
|
||||
threshold=70,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import qrcode
|
||||
import textwrap
|
||||
from string import ascii_letters
|
||||
|
||||
|
|
@ -7,9 +8,16 @@ from labeler.domain.objects import Image, LabelDefinition
|
|||
from labeler.interfaces import Renderer
|
||||
|
||||
|
||||
DPI = 360.0
|
||||
|
||||
|
||||
def points_to_pixels(point_size: float):
|
||||
return int(point_size * (72 / DPI))
|
||||
|
||||
|
||||
class PILRenderer(Renderer):
|
||||
def __init__(self):
|
||||
self.font_path = "/Library/Fonts/Arial.ttf"
|
||||
self.font_path = "/Library/Fonts/Arial Unicode.ttf"
|
||||
|
||||
def render_label(self, label_definition: LabelDefinition) -> Image:
|
||||
if label_definition.length is None:
|
||||
|
|
@ -47,7 +55,7 @@ class PILRenderer(Renderer):
|
|||
|
||||
while text_height > 0:
|
||||
font = ImageFont.truetype(
|
||||
"/Library/Fonts/Arial.ttf",
|
||||
"/Library/Fonts/Arial Unicode.ttf",
|
||||
text_height,
|
||||
)
|
||||
if lines_to_print > 1:
|
||||
|
|
@ -74,6 +82,42 @@ class PILRenderer(Renderer):
|
|||
)
|
||||
return im
|
||||
|
||||
def render_qrcode(self, label_definition: LabelDefinition) -> Image:
|
||||
width = label_definition.pixel_width
|
||||
length = label_definition.pixel_length
|
||||
text = label_definition.text
|
||||
font = self.__get_font_for_qr()
|
||||
qr = qrcode.QRCode(box_size=7)
|
||||
qr.add_data(f"https://hs3.pl/db/{text}")
|
||||
qr.make(fit=True)
|
||||
qr_img = qr.make_image()
|
||||
print(width, length)
|
||||
pil_image = PILImage.new("1", (width, length), 1)
|
||||
draw = ImageDraw.Draw(pil_image)
|
||||
pil_image.paste(qr_img)
|
||||
draw.text(
|
||||
(width / 2, 232),
|
||||
"HS3-DB",
|
||||
font=font,
|
||||
fill=0,
|
||||
anchor="mm",
|
||||
align="center",
|
||||
)
|
||||
draw.text(
|
||||
(20, 232 + 34),
|
||||
f"ID: {text}",
|
||||
font=font,
|
||||
fill=0,
|
||||
align="left",
|
||||
)
|
||||
|
||||
return Image.from_pil(pil_image.transpose(PILImage.Transpose.ROTATE_90))
|
||||
|
||||
def __get_font_for_qr(self):
|
||||
font_size = int(360 / 9)
|
||||
|
||||
return ImageFont.truetype("fonts/SourceCodePro-SemiBold.ttf", font_size)
|
||||
|
||||
def __get_font(self, text: str, max_width: int, max_length: int):
|
||||
font_size = max_width
|
||||
step = max_width // 2
|
||||
|
|
|
|||
|
|
@ -8,6 +8,10 @@ class Renderer(abc.ABC):
|
|||
def render_label(self, label_definition: LabelDefinition) -> Image:
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def render_qrcode(self, label_definition: LabelDefinition) -> Image:
|
||||
pass
|
||||
|
||||
|
||||
class Printer(abc.ABC):
|
||||
@abc.abstractmethod
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue