67 lines
2.1 KiB
Python
67 lines
2.1 KiB
Python
from __future__ import annotations
|
|
|
|
from PIL import Image, ImageDraw, ImageFont
|
|
|
|
from .text_renderer import load_font
|
|
|
|
WIFI_INDICATOR_BRIGHTNESS = 50
|
|
WIFI_SCROLL_PIXELS_PER_SECOND = 16.0
|
|
WIFI_SCROLL_FPS = 20.0
|
|
WIFI_SCROLL_GAP_PIXELS = 16
|
|
WIFI_TEXT_SIZE = 10
|
|
|
|
|
|
def _draw_binary_text(
|
|
image: Image.Image,
|
|
position: tuple[int, int],
|
|
message: str,
|
|
*,
|
|
font: ImageFont.ImageFont,
|
|
) -> None:
|
|
probe = ImageDraw.Draw(image)
|
|
bbox = probe.textbbox((0, 0), message, font=font)
|
|
width = max(1, bbox[2] - bbox[0])
|
|
height = max(1, bbox[3] - bbox[1])
|
|
mask = Image.new("L", (width, height), 0)
|
|
ImageDraw.Draw(mask).text((-bbox[0], -bbox[1]), message, font=font, fill=255)
|
|
# Promote every covered font sample to a complete LED pixel. At this size,
|
|
# retaining grayscale antialiasing makes thin strokes disappear at 50%.
|
|
mask = mask.point(lambda value: 255 if value >= 64 else 0)
|
|
image.paste((255, 255, 255), (position[0] + bbox[0], position[1] + bbox[1]), mask)
|
|
|
|
|
|
def text_width(message: str) -> int:
|
|
font = load_font("default", WIFI_TEXT_SIZE, message)
|
|
draw = ImageDraw.Draw(Image.new("RGB", (1, 1)))
|
|
box = draw.textbbox((0, 0), message, font=font)
|
|
return max(1, box[2] - box[0])
|
|
|
|
|
|
def _draw_disconnected_icon(draw: ImageDraw.ImageDraw) -> None:
|
|
# A compact WiFi fan with a red slash remains recognizable on 64x64.
|
|
white = (255, 255, 255)
|
|
red = (255, 48, 48)
|
|
draw.arc((19, 4, 45, 28), 205, 335, fill=white, width=2)
|
|
draw.arc((23, 10, 41, 28), 205, 335, fill=white, width=2)
|
|
draw.arc((28, 17, 36, 27), 205, 335, fill=white, width=2)
|
|
draw.rectangle((31, 27, 33, 29), fill=white)
|
|
draw.line((19, 4, 45, 30), fill=red, width=3)
|
|
|
|
|
|
def render_wifi_indicator(
|
|
message: str,
|
|
*,
|
|
offset: float,
|
|
connected: bool,
|
|
size: tuple[int, int] = (64, 64),
|
|
) -> Image.Image:
|
|
image = Image.new("RGB", size, (0, 0, 0))
|
|
draw = ImageDraw.Draw(image)
|
|
font = load_font("default", WIFI_TEXT_SIZE, message)
|
|
if not connected:
|
|
_draw_disconnected_icon(draw)
|
|
x = size[0] - int(offset)
|
|
y = 26 if connected else 42
|
|
_draw_binary_text(image, (x, y), message, font=font)
|
|
return image
|