"""Renders a plain typed/printed name as an RGBA stamp (case_type "2b": no handwriting). Produces a tightly-cropped RGBA image shaped exactly like a :class:`~src.rendering.signature_preprocessor.SignaturePreprocessor` output, so it can flow through the existing :class:`~src.placement.placement_engine.PlacementEngine` and :class:`~src.rendering.renderer.Renderer` unchanged. """ from __future__ import annotations import numpy as np from PIL import Image, ImageDraw, ImageFont from src.utils.logging_utils import get_logger logger = get_logger(__name__) _FONT_CANDIDATES: tuple[str, ...] = ( "C:/Windows/Fonts/arial.ttf", "C:/Windows/Fonts/calibri.ttf", "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", "/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf", "/System/Library/Fonts/Helvetica.ttc", ) _FONT_SIZE_PX = 64 _PAD_PX = 6 def _load_font(size: int = _FONT_SIZE_PX) -> "ImageFont.ImageFont": for path in _FONT_CANDIDATES: try: return ImageFont.truetype(path, size) except OSError: continue logger.warning("No truetype font found; falling back to PIL's bitmap default font.") return ImageFont.load_default() def render_printed_name_stamp(name: str, ink_color: tuple[int, int, int] = (15, 15, 20)) -> np.ndarray: """Render ``name`` as plain typed text, returned as a tightly-cropped RGBA stamp. Args: name: The printed/typed name to render (no handwriting stroke texture). ink_color: Flat RGB color for the text (matches the pipeline's ink color pool). Returns: An ``(H, W, 4)`` uint8 RGBA array: opaque text on a transparent background. """ font = _load_font() scratch = Image.new("RGBA", (8, 8), (0, 0, 0, 0)) scratch_draw = ImageDraw.Draw(scratch) text_bbox = scratch_draw.textbbox((0, 0), name, font=font) text_w = max(text_bbox[2] - text_bbox[0], 1) text_h = max(text_bbox[3] - text_bbox[1], 1) canvas_w, canvas_h = text_w + 2 * _PAD_PX, text_h + 2 * _PAD_PX image = Image.new("RGBA", (canvas_w, canvas_h), (0, 0, 0, 0)) draw = ImageDraw.Draw(image) draw.text((_PAD_PX - text_bbox[0], _PAD_PX - text_bbox[1]), name, font=font, fill=(*ink_color, 255)) return np.array(image, dtype=np.uint8)