drop code128
This commit is contained in:
parent
377b7f1d2f
commit
37280f0345
1 changed files with 7 additions and 39 deletions
46
app.py
46
app.py
|
|
@ -3,14 +3,12 @@ import asyncio
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from barcode import Code128
|
|
||||||
from barcode.writer import ImageWriter
|
|
||||||
from brother_ql.backends.helpers import send
|
from brother_ql.backends.helpers import send
|
||||||
from brother_ql.conversion import convert
|
from brother_ql.conversion import convert
|
||||||
from brother_ql.raster import BrotherQLRaster
|
from brother_ql.raster import BrotherQLRaster
|
||||||
from fastapi import FastAPI, HTTPException
|
from fastapi import FastAPI, HTTPException
|
||||||
from PIL import Image, ImageDraw, ImageFont
|
from PIL import Image, ImageDraw, ImageFont
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, ConfigDict, Field
|
||||||
from pylibdmtx.pylibdmtx import encode
|
from pylibdmtx.pylibdmtx import encode
|
||||||
|
|
||||||
TARGET_H = 106
|
TARGET_H = 106
|
||||||
|
|
@ -29,39 +27,13 @@ class PrintRequest(BaseModel):
|
||||||
product: str = Field(..., description="Product name")
|
product: str = Field(..., description="Product name")
|
||||||
due_date: Optional[str] = Field(None, description="Due date from stock entry")
|
due_date: Optional[str] = Field(None, description="Due date from stock entry")
|
||||||
|
|
||||||
class Config:
|
model_config = ConfigDict(extra="ignore")
|
||||||
# ignore any other fields Grocy might send
|
|
||||||
extra = "ignore"
|
|
||||||
|
|
||||||
|
|
||||||
def mm_for_px(px, dpi=DPI):
|
def mm_for_px(px, dpi=DPI):
|
||||||
return 25.4 * px / dpi
|
return 25.4 * px / dpi
|
||||||
|
|
||||||
|
|
||||||
@lru_cache(maxsize=256)
|
|
||||||
def make_code128_exact(
|
|
||||||
grocycode: str,
|
|
||||||
xdim_px: int = 2, # narrower bars reduce overall width; ~0.25mm at 300dpi
|
|
||||||
dpi: int = DPI,
|
|
||||||
) -> Image.Image:
|
|
||||||
code = Code128(grocycode, writer=ImageWriter())
|
|
||||||
pil = code.render(
|
|
||||||
writer_options={
|
|
||||||
"write_text": False,
|
|
||||||
"dpi": dpi,
|
|
||||||
"module_height": mm_for_px(TARGET_H, dpi), # exact 106 px tall
|
|
||||||
"module_width": mm_for_px(xdim_px, dpi), # integer px/narrow bar
|
|
||||||
"quiet_zone": max(2.5, 10 * mm_for_px(xdim_px, dpi)), # generous quiet zone
|
|
||||||
}
|
|
||||||
).convert(
|
|
||||||
"L"
|
|
||||||
) # keep grayscale
|
|
||||||
# Height should already be 106 px; if writer adds 1px border, crop vertically.
|
|
||||||
if pil.height != TARGET_H:
|
|
||||||
pil = pil.resize((pil.width, TARGET_H), Image.NEAREST)
|
|
||||||
return pil
|
|
||||||
|
|
||||||
|
|
||||||
@lru_cache(maxsize=256)
|
@lru_cache(maxsize=256)
|
||||||
def make_datamatrix_scaled(grocycode: str) -> Image.Image:
|
def make_datamatrix_scaled(grocycode: str) -> Image.Image:
|
||||||
dm = encode(grocycode.encode("utf-8"))
|
dm = encode(grocycode.encode("utf-8"))
|
||||||
|
|
@ -148,7 +120,7 @@ def _ellipsize(
|
||||||
|
|
||||||
|
|
||||||
def make_text_panel(
|
def make_text_panel(
|
||||||
product: str, due_date: Optional[str], max_width: int = 360, padding: int = 4
|
product: str, due_date: Optional[str], max_width: int = 480, padding: int = 4
|
||||||
) -> Image.Image:
|
) -> Image.Image:
|
||||||
"""Render product (wrapped to 2 lines) + due_date in a fixed-height strip.
|
"""Render product (wrapped to 2 lines) + due_date in a fixed-height strip.
|
||||||
|
|
||||||
|
|
@ -294,19 +266,15 @@ def make_text_panel(
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
@app.post("/print", summary="Print Code128 + DataMatrix side-by-side")
|
@app.post("/print", summary="Print DataMatrix + text side-by-side")
|
||||||
async def print_from_grocy(req: PrintRequest):
|
async def print_from_grocy(req: PrintRequest):
|
||||||
try:
|
try:
|
||||||
loop = asyncio.get_running_loop()
|
loop = asyncio.get_running_loop()
|
||||||
code_img, dm_img = await asyncio.gather(
|
dm_img = await loop.run_in_executor(None, make_datamatrix_scaled, req.grocycode)
|
||||||
# use default x-dimension and DPI; only pass the payload
|
|
||||||
loop.run_in_executor(None, make_code128_exact, req.grocycode),
|
|
||||||
loop.run_in_executor(None, make_datamatrix_scaled, req.grocycode),
|
|
||||||
)
|
|
||||||
# Render a compact text panel; width-capped to keep label length reasonable
|
# Render a compact text panel; width-capped to keep label length reasonable
|
||||||
text_panel = make_text_panel(req.product, req.due_date, max_width=360)
|
text_panel = make_text_panel(req.product, req.due_date, max_width=360)
|
||||||
# compose expects a list of images
|
# compose expects a list of images
|
||||||
label_img = compose_row([code_img, dm_img, text_panel], spacing=12)
|
label_img = compose_row([dm_img, text_panel], spacing=12)
|
||||||
send_to_printer(label_img, req.printer_ip, req.model, req.label)
|
send_to_printer(label_img, req.printer_ip, req.model, req.label)
|
||||||
except Exception:
|
except Exception:
|
||||||
# optionally: log e with traceback and return a generic message
|
# optionally: log e with traceback and return a generic message
|
||||||
|
|
@ -315,5 +283,5 @@ async def print_from_grocy(req: PrintRequest):
|
||||||
"status": "printed",
|
"status": "printed",
|
||||||
"model": req.model,
|
"model": req.model,
|
||||||
"label": req.label,
|
"label": req.label,
|
||||||
"layout": "code128 | datamatrix | text",
|
"layout": "datamatrix | text",
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue