Compare commits

...

4 commits

6 changed files with 34 additions and 26 deletions

View file

@ -6,8 +6,8 @@
"image": "mcr.microsoft.com/vscode/devcontainers/python:1-3.11-bookworm",
// Features to add to the dev container. More info: https://containers.dev/features.
"features": {
"ghcr.io/devcontainers-contrib/features/poetry:2": {},
"ghcr.io/devcontainers-contrib/features/apt-get-packages:1": {
"ghcr.io/devcontainers-extra/features/poetry:2": {},
"ghcr.io/devcontainers-extra/features/apt-get-packages:1": {
"packages": "git-flow, git-lfs"
},
"ghcr.io/itsmechlark/features/redis-server:1": {}

View file

@ -3,20 +3,24 @@ from dataclasses import dataclass
from typing import Self, TypeAlias, cast
import numpy as np
from PIL import Image, ImageDraw, ImageFont
from PIL import Image as PILImage
from PIL import ImageDraw
from PIL.Image import Image, Resampling
from PIL.ImageFont import FreeTypeFont
from .config import Config
_RGB: TypeAlias = tuple[int, int, int]
_XY: TypeAlias = tuple[float, float]
_Box: TypeAlias = tuple[int, int, int, int]
@dataclass(slots=True, frozen=True)
class AdventImage:
img: Image.Image
img: Image
@classmethod
async def from_img(cls, img: Image.Image, cfg: Config) -> Self:
async def from_img(cls, img: Image, cfg: Config) -> Self:
"""
Einen quadratischen Ausschnitt aus der Mitte des Bilds nehmen
"""
@ -42,7 +46,7 @@ class AdventImage:
return cls(
img.resize(
size=(cfg.image.size, cfg.image.size),
resample=Image.LANCZOS,
resample=Resampling.LANCZOS,
)
)
@ -50,10 +54,10 @@ class AdventImage:
self,
xy: _XY,
text: str | bytes,
font: "ImageFont._Font",
font: FreeTypeFont,
anchor: str | None = "mm",
**text_kwargs,
) -> "Image._Box | None":
) -> _Box | None:
"""
Koordinaten (links, oben, rechts, unten) des betroffenen
Rechtecks bestimmen, wenn das Bild mit einem Text
@ -61,7 +65,7 @@ class AdventImage:
"""
# Neues 1-Bit Bild, gleiche Größe
mask = Image.new(mode="1", size=self.img.size, color=0)
mask = PILImage.new(mode="1", size=self.img.size)
# Text auf Maske auftragen
ImageDraw.Draw(mask).text(
@ -78,14 +82,15 @@ class AdventImage:
async def get_average_color(
self,
box: "Image._Box",
box: _Box,
) -> tuple[int, int, int]:
"""
Durchschnittsfarbe eines rechteckigen Ausschnitts in
einem Bild berechnen
"""
pixel_data = self.img.crop(box).getdata()
pixel_data = np.asarray(self.img.crop(box))
print(pixel_data)
mean_color: np.ndarray = np.mean(pixel_data, axis=0)
return cast(_RGB, tuple(mean_color.astype(int)))
@ -94,7 +99,7 @@ class AdventImage:
self,
xy: _XY,
text: str | bytes,
font: "ImageFont._Font",
font: FreeTypeFont,
anchor: str | None = "mm",
**text_kwargs,
) -> None:

View file

@ -5,7 +5,9 @@ from io import BytesIO
from typing import cast
from fastapi import Depends
from PIL import Image, ImageFont
from PIL import ImageFont
from PIL.Image import Image
from PIL.ImageFont import FreeTypeFont
from .advent_image import _XY, AdventImage
from .calendar_config import CalendarConfig, get_calendar_config
@ -138,7 +140,7 @@ class TTFont:
size: int = 50
@property
async def font(self) -> "ImageFont._Font":
async def font(self) -> FreeTypeFont:
return ImageFont.truetype(
font=BytesIO(await WebDAV.read_bytes(self.file_name)),
size=100,
@ -169,7 +171,7 @@ async def gen_day_auto_image(
auto_image_names: dict[int, str],
day_parts: dict[int, str],
ttfonts: list[TTFont],
) -> Image.Image:
) -> Image:
"""
Automatisch generiertes Bild erstellen
"""
@ -200,7 +202,7 @@ async def get_day_image(
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:
) -> Image | None:
"""
Bild für einen Tag abrufen
"""

View file

@ -6,7 +6,8 @@ from io import BytesIO
from typing import Any, Awaitable, Callable, Iterable, Self, Sequence, TypeVar
from fastapi.responses import StreamingResponse
from PIL import Image
from PIL import Image as PILImage
from PIL.Image import Image, Resampling
from .config import get_config
from .dav.webdav import WebDAV
@ -103,7 +104,7 @@ list_images_manual = list_helper("/images_manual", RE_IMG)
list_fonts = list_helper("/files", RE_TTF)
async def load_image(file_name: str) -> Image.Image:
async def load_image(file_name: str) -> Image:
"""
Versuche, Bild aus Datei zu laden
"""
@ -111,17 +112,17 @@ async def load_image(file_name: str) -> Image.Image:
if not await WebDAV.exists(file_name):
raise RuntimeError(f"DAV-File {file_name} does not exist!")
return Image.open(BytesIO(await WebDAV.read_bytes(file_name)))
return PILImage.open(BytesIO(await WebDAV.read_bytes(file_name)))
async def api_return_ico(img: Image.Image) -> StreamingResponse:
async def api_return_ico(img: Image) -> StreamingResponse:
"""
ICO-Bild mit API zurückgeben
"""
# JPEG-Daten in Puffer speichern
img_buffer = BytesIO()
img.resize(size=(256, 256), resample=Image.LANCZOS)
img.resize(size=(256, 256), resample=Resampling.LANCZOS)
img.save(img_buffer, format="ICO")
img_buffer.seek(0)
@ -132,7 +133,7 @@ async def api_return_ico(img: Image.Image) -> StreamingResponse:
)
async def api_return_jpeg(img: Image.Image) -> StreamingResponse:
async def api_return_jpeg(img: Image) -> StreamingResponse:
"""
JPEG-Bild mit API zurückgeben
"""

View file

@ -2,7 +2,7 @@ from datetime import datetime
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.responses import StreamingResponse
from PIL import Image
from PIL.Image import Image
from ..core.calendar_config import CalendarConfig, DoorsSaved, get_calendar_config
from ..core.config import Config, Site, get_config
@ -75,7 +75,7 @@ async def get_doors(
async def get_image_for_day(
user_can_view: bool = Depends(user_can_view_day),
is_admin: bool = Depends(user_is_admin),
image: Image.Image | None = Depends(get_day_image),
image: Image | None = Depends(get_day_image),
) -> StreamingResponse:
"""
Bild für einen Tag erstellen

View file

@ -6,10 +6,10 @@
"image": "mcr.microsoft.com/vscode/devcontainers/javascript-node:1-18-bookworm",
// Features to add to the dev container. More info: https://containers.dev/features.
"features": {
"ghcr.io/devcontainers-contrib/features/apt-get-packages:1": {
"ghcr.io/devcontainers-extra/features/apt-get-packages:1": {
"packages": "git-flow, git-lfs"
},
"ghcr.io/devcontainers-contrib/features/vue-cli:2": {}
"ghcr.io/devcontainers-extra/features/vue-cli:2": {}
},
// Configure tool-specific properties.
"customizations": {