updated font handling

This commit is contained in:
Jörn-Michael Miehe 2023-11-01 01:30:33 +01:00
parent 7951363be8
commit 8a254d2958
6 changed files with 67 additions and 25 deletions

View file

@ -92,14 +92,6 @@ class Puzzle(BaseModel):
close_after: int = 90
class TTFont(BaseModel):
# Dateiname (in "/files")
file: str
# Schriftgröße für den Font
size: int = 50
class Image(BaseModel):
# Quadrat, Seitenlänge in px
size: int = 1000
@ -107,10 +99,6 @@ class Image(BaseModel):
# Rand in px, wo keine Buchstaben untergebracht werden
border: int = 60
# Schriftarten
# TODO
fonts: list[TTFont]
class Config(BaseModel):
# Login-Daten für Admin-Modus

View file

@ -1,4 +1,5 @@
import re
from dataclasses import dataclass
from datetime import date
from io import BytesIO
from typing import cast
@ -11,8 +12,10 @@ from .calendar_config import CalendarConfig, get_calendar_config
from .config import Config, get_config
from .dav.webdav import WebDAV
from .helpers import (
RE_TTF,
EventDates,
Random,
list_fonts,
list_images_auto,
list_images_manual,
load_image,
@ -109,11 +112,46 @@ async def get_all_image_names(
return auto_image_names
@dataclass(slots=True, frozen=True)
class TTFont:
# Dateiname
file_name: str
# Schriftgröße für den Font
size: int = 50
@property
async def font(self) -> "ImageFont._Font":
return ImageFont.truetype(
font=BytesIO(await WebDAV.read_bytes(self.file_name)),
size=100,
)
async def get_all_ttfonts(
font_names: list[str] = Depends(list_fonts),
) -> list[TTFont]:
result = []
for name in font_names:
assert (size_match := RE_TTF.search(name)) is not None
result.append(
TTFont(
file_name=name,
size=int(size_match.group(1)),
)
)
return result
async def gen_day_auto_image(
day: int,
cfg: Config,
auto_image_names: dict[int, str],
day_parts: dict[int, str],
ttfonts: list[TTFont],
) -> Image.Image:
"""
Automatisch generiertes Bild erstellen
@ -125,18 +163,14 @@ async def gen_day_auto_image(
rnd = await Random.get(day)
font = ImageFont.truetype(
font=BytesIO(await WebDAV.read_bytes("files/Lena.ttf")), # TODO
size=100,
)
# Buchstaben verstecken
for letter in day_parts[day]:
xy_range = range(cfg.image.border, (cfg.image.size - cfg.image.border))
await image.hide_text(
xy=cast(_XY, tuple(rnd.choices(xy_range, k=2))),
text=letter,
font=font,
font=await rnd.choice(ttfonts).font,
)
return image.img
@ -148,6 +182,7 @@ async def get_day_image(
cfg: Config = Depends(get_config),
auto_image_names: dict[int, str] = Depends(get_all_auto_image_names),
day_parts: dict[int, str] = Depends(get_all_parts),
ttfonts: list[TTFont] = Depends(get_all_ttfonts),
) -> Image.Image | None:
"""
Bild für einen Tag abrufen
@ -167,5 +202,9 @@ async def get_day_image(
except RuntimeError:
# Erstelle automatisch generiertes Bild
return await gen_day_auto_image(
day=day, cfg=cfg, auto_image_names=auto_image_names, day_parts=day_parts
day=day,
cfg=cfg,
auto_image_names=auto_image_names,
day_parts=day_parts,
ttfonts=ttfonts,
)

View file

@ -13,7 +13,7 @@ from .dav.webdav import WebDAV
T = TypeVar("T")
RE_IMG = re.compile(r"\.(gif|jpe?g|tiff?|png|bmp)$", flags=re.IGNORECASE)
RE_TTF = re.compile(r"\.(ttf)$", flags=re.IGNORECASE)
RE_TTF = re.compile(r"_(\d+)\.ttf$", flags=re.IGNORECASE)
class Random(random.Random):

View file

@ -7,7 +7,13 @@ from advent22_api.core.helpers import EventDates
from ..core.calendar_config import CalendarConfig, DoorsSaved, get_calendar_config
from ..core.config import Config, Image, get_config
from ..core.depends import get_all_event_dates, get_all_image_names, get_all_parts
from ..core.depends import (
TTFont,
get_all_event_dates,
get_all_image_names,
get_all_parts,
get_all_ttfonts,
)
from ..core.settings import SETTINGS, RedisSettings
from ._security import require_admin, user_is_admin
@ -39,6 +45,10 @@ class ConfigModel(BaseModel):
config_file: str
background: str
class __Font(BaseModel):
file: str
size: int
class __WebDAV(BaseModel):
url: str
cache_ttl: int
@ -48,6 +58,7 @@ class ConfigModel(BaseModel):
puzzle: __Puzzle
calendar: __Calendar
image: Image
fonts: list[__Font]
redis: RedisSettings
webdav: __WebDAV
@ -58,6 +69,7 @@ async def get_config_model(
cfg: Config = Depends(get_config),
cal_cfg: CalendarConfig = Depends(get_calendar_config),
event_dates: EventDates = Depends(get_all_event_dates),
ttfonts: list[TTFont] = Depends(get_all_ttfonts),
) -> ConfigModel:
"""
Kombiniert aus privaten `settings`, `config` und `calendar_config`
@ -83,6 +95,9 @@ async def get_config_model(
"background": cal_cfg.background,
},
"image": cfg.image,
"fonts": [
{"file": ttfont.file_name, "size": ttfont.size} for ttfont in ttfonts
],
"redis": SETTINGS.redis,
"webdav": {
"url": SETTINGS.webdav.url,

View file

@ -101,10 +101,10 @@
<dt>Schriftarten</dt>
<dd
v-for="(font, index) in config_model.image.fonts"
v-for="(font, index) in config_model.fonts"
:key="`font-${index}`"
>
{{ font.file }} (Größe {{ font.size }})
{{ font.file }} ({{ font.size }} pt)
</dd>
</dl>
</div>
@ -200,8 +200,8 @@ export default class extends Vue {
image: {
size: 500,
border: 0,
fonts: [{ file: "consetetur", size: 0 }],
},
fonts: [{ file: "consetetur", size: 0 }],
redis: {
host: "0.0.0.0",
port: 6379,

View file

@ -19,8 +19,8 @@ export interface ConfigModel {
image: {
size: number;
border: number;
fonts: { file: string; size: number }[];
};
fonts: { file: string; size: number }[];
redis: {
host: string;
port: number;