updated font handling
This commit is contained in:
parent
7951363be8
commit
8a254d2958
6 changed files with 67 additions and 25 deletions
|
@ -92,14 +92,6 @@ class Puzzle(BaseModel):
|
||||||
close_after: int = 90
|
close_after: int = 90
|
||||||
|
|
||||||
|
|
||||||
class TTFont(BaseModel):
|
|
||||||
# Dateiname (in "/files")
|
|
||||||
file: str
|
|
||||||
|
|
||||||
# Schriftgröße für den Font
|
|
||||||
size: int = 50
|
|
||||||
|
|
||||||
|
|
||||||
class Image(BaseModel):
|
class Image(BaseModel):
|
||||||
# Quadrat, Seitenlänge in px
|
# Quadrat, Seitenlänge in px
|
||||||
size: int = 1000
|
size: int = 1000
|
||||||
|
@ -107,10 +99,6 @@ class Image(BaseModel):
|
||||||
# Rand in px, wo keine Buchstaben untergebracht werden
|
# Rand in px, wo keine Buchstaben untergebracht werden
|
||||||
border: int = 60
|
border: int = 60
|
||||||
|
|
||||||
# Schriftarten
|
|
||||||
# TODO
|
|
||||||
fonts: list[TTFont]
|
|
||||||
|
|
||||||
|
|
||||||
class Config(BaseModel):
|
class Config(BaseModel):
|
||||||
# Login-Daten für Admin-Modus
|
# Login-Daten für Admin-Modus
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import re
|
import re
|
||||||
|
from dataclasses import dataclass
|
||||||
from datetime import date
|
from datetime import date
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from typing import cast
|
from typing import cast
|
||||||
|
@ -11,8 +12,10 @@ from .calendar_config import CalendarConfig, get_calendar_config
|
||||||
from .config import Config, get_config
|
from .config import Config, get_config
|
||||||
from .dav.webdav import WebDAV
|
from .dav.webdav import WebDAV
|
||||||
from .helpers import (
|
from .helpers import (
|
||||||
|
RE_TTF,
|
||||||
EventDates,
|
EventDates,
|
||||||
Random,
|
Random,
|
||||||
|
list_fonts,
|
||||||
list_images_auto,
|
list_images_auto,
|
||||||
list_images_manual,
|
list_images_manual,
|
||||||
load_image,
|
load_image,
|
||||||
|
@ -109,11 +112,46 @@ async def get_all_image_names(
|
||||||
return auto_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(
|
async def gen_day_auto_image(
|
||||||
day: int,
|
day: int,
|
||||||
cfg: Config,
|
cfg: Config,
|
||||||
auto_image_names: dict[int, str],
|
auto_image_names: dict[int, str],
|
||||||
day_parts: dict[int, str],
|
day_parts: dict[int, str],
|
||||||
|
ttfonts: list[TTFont],
|
||||||
) -> Image.Image:
|
) -> Image.Image:
|
||||||
"""
|
"""
|
||||||
Automatisch generiertes Bild erstellen
|
Automatisch generiertes Bild erstellen
|
||||||
|
@ -125,18 +163,14 @@ async def gen_day_auto_image(
|
||||||
|
|
||||||
rnd = await Random.get(day)
|
rnd = await Random.get(day)
|
||||||
|
|
||||||
font = ImageFont.truetype(
|
|
||||||
font=BytesIO(await WebDAV.read_bytes("files/Lena.ttf")), # TODO
|
|
||||||
size=100,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Buchstaben verstecken
|
# Buchstaben verstecken
|
||||||
for letter in day_parts[day]:
|
for letter in day_parts[day]:
|
||||||
xy_range = range(cfg.image.border, (cfg.image.size - cfg.image.border))
|
xy_range = range(cfg.image.border, (cfg.image.size - cfg.image.border))
|
||||||
|
|
||||||
await image.hide_text(
|
await image.hide_text(
|
||||||
xy=cast(_XY, tuple(rnd.choices(xy_range, k=2))),
|
xy=cast(_XY, tuple(rnd.choices(xy_range, k=2))),
|
||||||
text=letter,
|
text=letter,
|
||||||
font=font,
|
font=await rnd.choice(ttfonts).font,
|
||||||
)
|
)
|
||||||
|
|
||||||
return image.img
|
return image.img
|
||||||
|
@ -148,6 +182,7 @@ async def get_day_image(
|
||||||
cfg: Config = Depends(get_config),
|
cfg: Config = Depends(get_config),
|
||||||
auto_image_names: dict[int, str] = Depends(get_all_auto_image_names),
|
auto_image_names: dict[int, str] = Depends(get_all_auto_image_names),
|
||||||
day_parts: dict[int, str] = Depends(get_all_parts),
|
day_parts: dict[int, str] = Depends(get_all_parts),
|
||||||
|
ttfonts: list[TTFont] = Depends(get_all_ttfonts),
|
||||||
) -> Image.Image | None:
|
) -> Image.Image | None:
|
||||||
"""
|
"""
|
||||||
Bild für einen Tag abrufen
|
Bild für einen Tag abrufen
|
||||||
|
@ -167,5 +202,9 @@ async def get_day_image(
|
||||||
except RuntimeError:
|
except RuntimeError:
|
||||||
# Erstelle automatisch generiertes Bild
|
# Erstelle automatisch generiertes Bild
|
||||||
return await gen_day_auto_image(
|
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,
|
||||||
)
|
)
|
||||||
|
|
|
@ -13,7 +13,7 @@ from .dav.webdav import WebDAV
|
||||||
|
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
RE_IMG = re.compile(r"\.(gif|jpe?g|tiff?|png|bmp)$", flags=re.IGNORECASE)
|
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):
|
class Random(random.Random):
|
||||||
|
|
|
@ -7,7 +7,13 @@ from advent22_api.core.helpers import EventDates
|
||||||
|
|
||||||
from ..core.calendar_config import CalendarConfig, DoorsSaved, get_calendar_config
|
from ..core.calendar_config import CalendarConfig, DoorsSaved, get_calendar_config
|
||||||
from ..core.config import Config, Image, get_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 ..core.settings import SETTINGS, RedisSettings
|
||||||
from ._security import require_admin, user_is_admin
|
from ._security import require_admin, user_is_admin
|
||||||
|
|
||||||
|
@ -39,6 +45,10 @@ class ConfigModel(BaseModel):
|
||||||
config_file: str
|
config_file: str
|
||||||
background: str
|
background: str
|
||||||
|
|
||||||
|
class __Font(BaseModel):
|
||||||
|
file: str
|
||||||
|
size: int
|
||||||
|
|
||||||
class __WebDAV(BaseModel):
|
class __WebDAV(BaseModel):
|
||||||
url: str
|
url: str
|
||||||
cache_ttl: int
|
cache_ttl: int
|
||||||
|
@ -48,6 +58,7 @@ class ConfigModel(BaseModel):
|
||||||
puzzle: __Puzzle
|
puzzle: __Puzzle
|
||||||
calendar: __Calendar
|
calendar: __Calendar
|
||||||
image: Image
|
image: Image
|
||||||
|
fonts: list[__Font]
|
||||||
redis: RedisSettings
|
redis: RedisSettings
|
||||||
webdav: __WebDAV
|
webdav: __WebDAV
|
||||||
|
|
||||||
|
@ -58,6 +69,7 @@ async def get_config_model(
|
||||||
cfg: Config = Depends(get_config),
|
cfg: Config = Depends(get_config),
|
||||||
cal_cfg: CalendarConfig = Depends(get_calendar_config),
|
cal_cfg: CalendarConfig = Depends(get_calendar_config),
|
||||||
event_dates: EventDates = Depends(get_all_event_dates),
|
event_dates: EventDates = Depends(get_all_event_dates),
|
||||||
|
ttfonts: list[TTFont] = Depends(get_all_ttfonts),
|
||||||
) -> ConfigModel:
|
) -> ConfigModel:
|
||||||
"""
|
"""
|
||||||
Kombiniert aus privaten `settings`, `config` und `calendar_config`
|
Kombiniert aus privaten `settings`, `config` und `calendar_config`
|
||||||
|
@ -83,6 +95,9 @@ async def get_config_model(
|
||||||
"background": cal_cfg.background,
|
"background": cal_cfg.background,
|
||||||
},
|
},
|
||||||
"image": cfg.image,
|
"image": cfg.image,
|
||||||
|
"fonts": [
|
||||||
|
{"file": ttfont.file_name, "size": ttfont.size} for ttfont in ttfonts
|
||||||
|
],
|
||||||
"redis": SETTINGS.redis,
|
"redis": SETTINGS.redis,
|
||||||
"webdav": {
|
"webdav": {
|
||||||
"url": SETTINGS.webdav.url,
|
"url": SETTINGS.webdav.url,
|
||||||
|
|
|
@ -101,10 +101,10 @@
|
||||||
|
|
||||||
<dt>Schriftarten</dt>
|
<dt>Schriftarten</dt>
|
||||||
<dd
|
<dd
|
||||||
v-for="(font, index) in config_model.image.fonts"
|
v-for="(font, index) in config_model.fonts"
|
||||||
:key="`font-${index}`"
|
:key="`font-${index}`"
|
||||||
>
|
>
|
||||||
{{ font.file }} (Größe {{ font.size }})
|
{{ font.file }} ({{ font.size }} pt)
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
|
@ -200,8 +200,8 @@ export default class extends Vue {
|
||||||
image: {
|
image: {
|
||||||
size: 500,
|
size: 500,
|
||||||
border: 0,
|
border: 0,
|
||||||
fonts: [{ file: "consetetur", size: 0 }],
|
|
||||||
},
|
},
|
||||||
|
fonts: [{ file: "consetetur", size: 0 }],
|
||||||
redis: {
|
redis: {
|
||||||
host: "0.0.0.0",
|
host: "0.0.0.0",
|
||||||
port: 6379,
|
port: 6379,
|
||||||
|
|
|
@ -19,8 +19,8 @@ export interface ConfigModel {
|
||||||
image: {
|
image: {
|
||||||
size: number;
|
size: number;
|
||||||
border: number;
|
border: number;
|
||||||
fonts: { file: string; size: number }[];
|
|
||||||
};
|
};
|
||||||
|
fonts: { file: string; size: number }[];
|
||||||
redis: {
|
redis: {
|
||||||
host: string;
|
host: string;
|
||||||
port: number;
|
port: number;
|
||||||
|
|
Loading…
Reference in a new issue