Add Picture screen: upload a file or point at a URL
New screen alongside clock/weather/navidrome. Upload goes through the web UI (validated with PIL before accepting, stored under web/static/uploads/, gitignored), or point it at a URL re-fetched every 30 minutes. Cover/contain fit modes (new fit_cover/fit_contain helpers in render_utils.py, generalized from the square-only cover-art cropping already used by the Navidrome screen), plus the same contrast-boost/grayscale options that screen has.
This commit is contained in:
1 parent
61348be674
commit
bfe4616f20
8 files changed
+232
-4
No files matched your search
+24
-1
@@ -8,7 +8,7 @@ text and full-color cover art without worrying about the palette themselves.
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from PIL import ImageFont
|
||||
from PIL import Image, ImageFont
|
||||
|
||||
FONTS_DIR = Path(__file__).resolve().parent.parent / "fonts"
|
||||
|
||||
@@ -77,3 +77,26 @@ def wrap_to_lines(draw, text: str, font: ImageFont.FreeTypeFont, max_width: int,
|
||||
|
||||
lines.append(current)
|
||||
return lines[:max_lines]
|
||||
|
||||
|
||||
def fit_cover(image: Image.Image, width: int, height: int) -> Image.Image:
|
||||
"""Resize+crop to fill exactly width x height, mirroring CSS's
|
||||
object-fit: cover -- no letterboxing, but edges may be cropped off."""
|
||||
src_w, src_h = image.size
|
||||
scale = max(width / src_w, height / src_h)
|
||||
scaled = image.resize((round(src_w * scale), round(src_h * scale)), Image.LANCZOS)
|
||||
left = (scaled.width - width) // 2
|
||||
top = (scaled.height - height) // 2
|
||||
return scaled.crop((left, top, left + width, top + height))
|
||||
|
||||
|
||||
def fit_contain(image: Image.Image, width: int, height: int, background=(255, 255, 255)) -> Image.Image:
|
||||
"""Resize to fit entirely within width x height, centered on a solid
|
||||
background -- mirrors CSS's object-fit: contain, full image always
|
||||
visible, letterboxed instead of cropped."""
|
||||
src_w, src_h = image.size
|
||||
scale = min(width / src_w, height / src_h)
|
||||
scaled = image.resize((round(src_w * scale), round(src_h * scale)), Image.LANCZOS)
|
||||
canvas = Image.new("RGB", (width, height), background)
|
||||
canvas.paste(scaled, ((width - scaled.width) // 2, (height - scaled.height) // 2))
|
||||
return canvas
|
||||
Reference in new issue
Block a user