Render curated date-folder photos with title date and place captions

This commit is contained in:
Pigway
2026-10-05 01:36:05 +08:00
parent f5ab1ade77
commit 011339d511
15 changed files with 386 additions and 18 deletions
+8 -4
View File
@@ -14,7 +14,7 @@ from pigway_frame_flow.storage.database import now_iso
Image.MAX_IMAGE_PIXELS = 25_000_000
def convert(data, fit="contain", profile="color"):
def convert(data, fit="contain", profile="color", *, size=(1200, 1600)):
try:
with Image.open(BytesIO(data)) as source:
if source.format not in {"JPEG", "PNG", "WEBP"}:
@@ -27,7 +27,7 @@ def convert(data, fit="contain", profile="color"):
img = canvas.convert("RGB")
if fit == "contain":
result = ImageOps.pad(
img, (1200, 1600), method=Image.Resampling.LANCZOS, color="white"
img, size, method=Image.Resampling.LANCZOS, color="white"
)
else:
center = (0.5, 0.5)
@@ -38,7 +38,11 @@ def convert(data, fit="contain", profile="color"):
thumb.thumbnail((240, 240))
edges = thumb.convert("L").filter(ImageFilter.FIND_EDGES)
w, h = edges.size
cw, ch = (int(h * 0.75), h) if w / h > 0.75 else (w, int(w / 0.75))
cw, ch = (
(int(h * size[0] / size[1]), h)
if w / h > size[0] / size[1]
else (w, int(w * size[1] / size[0]))
)
choices = []
for step in range(11):
x, y = int((w - cw) * step / 10), int((h - ch) * step / 10)
@@ -53,7 +57,7 @@ def convert(data, fit="contain", profile="color"):
(y / (h - ch)) if h != ch else 0.5,
)
result = ImageOps.fit(
img, (1200, 1600), method=Image.Resampling.LANCZOS, centering=center
img, size, method=Image.Resampling.LANCZOS, centering=center
)
if profile == "grayscale":
result = ImageOps.grayscale(result).convert("RGB")
@@ -0,0 +1,29 @@
"""Native frame image with a separate, high-contrast caption area."""
from io import BytesIO
from PIL import Image, ImageDraw
from pigway_frame_flow.renderers.images import convert
def render_captioned_photo(data, caption, font_loader, fit="contain", profile="color"):
photo_data = convert(data, fit, profile, size=(1200, 1280))
canvas = Image.new("RGB", (1200, 1600), "white")
with Image.open(BytesIO(photo_data)) as photo:
canvas.paste(photo, (0, 0))
draw = ImageDraw.Draw(canvas)
lines = [(caption["title"], 1320, 52), (caption["date"], 1410, 40)]
if caption.get("place"):
lines.append((caption["place"], 1480, 38))
for text, y, size in lines:
font = font_loader(size)
while size > 24 and draw.textlength(text, font=font) > 1080:
size -= 2
font = font_loader(size)
while draw.textlength(text, font=font) > 1080 and text:
text = text[:-2] + "…"
draw.text((600, y), text, font=font, fill="black", anchor="mt")
out = BytesIO()
canvas.save(out, "JPEG", quality=93, optimize=True)
return out.getvalue()