Files
Fichero/fichero/imaging.py
Hamza 1fdbbe20bd Restructure into fichero/ package and fix review issues
Split monolithic printer.py into fichero/{printer,imaging,cli}.py.
Add asyncio.Lock to prevent notification buffer races, replace sys.exit
with PrinterNotFound/PrinterTimeout/PrinterNotReady exceptions, name all
magic sleep values as DELAY_* constants, add image_to_raster validation,
add --font-size and --label-height to text subcommand, add input
validation to set command, add type annotations to public API, fix
misleading paper type comment, remove duplicate PROTOCOL.md section,
update README for new CLI entry point and library usage.
2026-02-24 01:07:25 +01:00

51 lines
1.6 KiB
Python

"""Image processing for Fichero D11s thermal label printer."""
import logging
from PIL import Image, ImageDraw, ImageFont
from fichero.printer import PRINTHEAD_PX
log = logging.getLogger(__name__)
def prepare_image(img: Image.Image, max_rows: int = 240) -> Image.Image:
"""Convert any image to 96px wide, 1-bit, black on white."""
img = img.convert("L")
w, h = img.size
new_h = int(h * (PRINTHEAD_PX / w))
if new_h > max_rows:
log.warning("Image height %dpx exceeds max %dpx, cropping bottom", new_h, max_rows)
new_h = max_rows
img = img.resize((PRINTHEAD_PX, new_h), Image.LANCZOS)
img = img.point(lambda x: 1 if x < 128 else 0, "1")
return img
def image_to_raster(img: Image.Image) -> bytes:
"""Pack 1-bit image into raw raster bytes, MSB first."""
if img.mode != "1":
raise ValueError(f"Expected mode '1', got '{img.mode}'")
if img.width != PRINTHEAD_PX:
raise ValueError(f"Expected width {PRINTHEAD_PX}, got {img.width}")
return img.tobytes()
def text_to_image(text: str, font_size: int = 24, label_height: int = 240) -> Image.Image:
"""Render text in landscape, then rotate 90 degrees for label printing."""
canvas_w = label_height
canvas_h = PRINTHEAD_PX
img = Image.new("L", (canvas_w, canvas_h), 255)
draw = ImageDraw.Draw(img)
font = ImageFont.load_default(size=font_size)
bbox = draw.textbbox((0, 0), text, font=font)
tw, th = bbox[2] - bbox[0], bbox[3] - bbox[1]
x = (canvas_w - tw) // 2
y = (canvas_h - th) // 2
draw.text((x, y), text, fill=0, font=font)
img = img.rotate(90, expand=True)
return img