switch to use grocy feature
This commit is contained in:
parent
a5e0f82771
commit
ec60d1ffcd
1 changed files with 26 additions and 22 deletions
48
app.py
48
app.py
|
|
@ -1,8 +1,7 @@
|
||||||
# app.py
|
# app.py
|
||||||
import asyncio
|
import asyncio
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from io import BytesIO
|
from typing import List, Optional
|
||||||
from typing import List
|
|
||||||
|
|
||||||
from barcode import Code128
|
from barcode import Code128
|
||||||
from barcode.writer import ImageWriter
|
from barcode.writer import ImageWriter
|
||||||
|
|
@ -20,10 +19,25 @@ if not hasattr(Image, "ANTIALIAS"):
|
||||||
app = FastAPI(title="QL-1060N Stacked Barcode Printer")
|
app = FastAPI(title="QL-1060N Stacked Barcode Printer")
|
||||||
|
|
||||||
|
|
||||||
|
class PrintRequest(BaseModel):
|
||||||
|
# from LABEL_PRINTER_PARAMS
|
||||||
|
printer_ip: str = Field(..., description="QL-1060N IP on LAN")
|
||||||
|
model: str = Field(..., description="Brother model")
|
||||||
|
label: str = Field(..., description="12 mm tape")
|
||||||
|
# grocy payload:
|
||||||
|
grocycode: str = Field(..., description="Raw GrocyCode")
|
||||||
|
product: str = Field(..., description="Product name")
|
||||||
|
due_date: str = Field(None, description="Due date from stock entry")
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
# ignore any other fields Grocy might send
|
||||||
|
extra = "ignore"
|
||||||
|
|
||||||
|
|
||||||
@lru_cache(maxsize=256)
|
@lru_cache(maxsize=256)
|
||||||
def make_code128(data: str) -> Image.Image:
|
def make_code128(grocycode: str, product_name: str, due_date: Optional[str]) -> Image.Image:
|
||||||
# 1) Instantiate the barcode object (checksum auto-added for Code128)
|
# 1) Instantiate the barcode object (checksum auto-added for Code128)
|
||||||
code = Code128(data, writer=ImageWriter())
|
code = Code128(grocycode, writer=ImageWriter())
|
||||||
|
|
||||||
# 2) Render to a PIL.Image, passing any writer options and optional text override
|
# 2) Render to a PIL.Image, passing any writer options and optional text override
|
||||||
pil_img = code.render(
|
pil_img = code.render(
|
||||||
|
|
@ -35,7 +49,7 @@ def make_code128(data: str) -> Image.Image:
|
||||||
"text_distance": 5.0, # gap between bars and text
|
"text_distance": 5.0, # gap between bars and text
|
||||||
# you can also pass 'format': 'PNG' here if needed
|
# you can also pass 'format': 'PNG' here if needed
|
||||||
},
|
},
|
||||||
text=data, # explicitly draw your data string under the bars
|
text=" | ".join([product_name, due_date]), # explicitly draw your data string under the bars
|
||||||
)
|
)
|
||||||
|
|
||||||
# 3) Convert to 1-bit for your Brother QL workflow
|
# 3) Convert to 1-bit for your Brother QL workflow
|
||||||
|
|
@ -43,21 +57,12 @@ def make_code128(data: str) -> Image.Image:
|
||||||
|
|
||||||
|
|
||||||
@lru_cache(maxsize=256)
|
@lru_cache(maxsize=256)
|
||||||
def make_datamatrix(data: str) -> Image.Image:
|
def make_datamatrix(grocycode: str) -> Image.Image:
|
||||||
dm = encode(data.encode("utf-8"))
|
dm = encode(grocycode.encode("utf-8"))
|
||||||
pil_img = Image.frombytes("RGB", (dm.width, dm.height), dm.pixels)
|
pil_img = Image.frombytes("RGB", (dm.width, dm.height), dm.pixels)
|
||||||
return pil_img.convert("1")
|
return pil_img.convert("1")
|
||||||
|
|
||||||
|
|
||||||
class PrintRequest(BaseModel):
|
|
||||||
data: str = Field(..., description="String to encode")
|
|
||||||
printer_ip: str = Field(
|
|
||||||
"192.168.178.49", description="Brother QL-1060N IP on your LAN"
|
|
||||||
)
|
|
||||||
model: str = Field("QL-1060N", description="Brother model")
|
|
||||||
label: str = Field("12", description="12 mm continuous tape")
|
|
||||||
|
|
||||||
|
|
||||||
def compose_label(images: List[Image.Image]) -> Image.Image:
|
def compose_label(images: List[Image.Image]) -> Image.Image:
|
||||||
"""
|
"""
|
||||||
Horizontally stack each barcode image with padding,
|
Horizontally stack each barcode image with padding,
|
||||||
|
|
@ -119,16 +124,15 @@ def send_to_printer(image: Image.Image, printer_ip: str, model: str, label: str)
|
||||||
|
|
||||||
|
|
||||||
@app.post("/print", summary="Print Code128 + DataMatrix side-by-side")
|
@app.post("/print", summary="Print Code128 + DataMatrix side-by-side")
|
||||||
async def print_stacked(req: PrintRequest):
|
async def print_from_grocy(req: PrintRequest):
|
||||||
try:
|
try:
|
||||||
loop = asyncio.get_running_loop()
|
loop = asyncio.get_running_loop()
|
||||||
code_task = loop.run_in_executor(None, make_code128, req.data)
|
code_img, dm_img = await asyncio.gather(
|
||||||
dm_task = loop.run_in_executor(None, make_datamatrix, req.data)
|
loop.run_in_executor(None, make_code128, req.grocycode, req.product, req.due_date),
|
||||||
code_img, dm_img = await asyncio.gather(code_task, dm_task)
|
loop.run_in_executor(None, make_datamatrix, req.grocycode),
|
||||||
|
)
|
||||||
label_img = compose_label([code_img, dm_img])
|
label_img = compose_label([code_img, dm_img])
|
||||||
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 as e:
|
except Exception as e:
|
||||||
raise HTTPException(status_code=500, detail=str(e))
|
raise HTTPException(status_code=500, detail=str(e))
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue