File size: 2,286 Bytes
97b64b9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
"""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)