69 lines
2.3 KiB
Python
69 lines
2.3 KiB
Python
"""Full-bleed photo with a compact, single-line camera-style watermark."""
|
|
|
|
from io import BytesIO
|
|
|
|
from PIL import Image, ImageDraw
|
|
|
|
from pigway_frame_flow.renderers.images import convert
|
|
from pigway_frame_flow.renderers.photo_layout import WatermarkLayout
|
|
|
|
|
|
def render_captioned_photo(
|
|
data,
|
|
caption,
|
|
font_loader,
|
|
fit="cover",
|
|
profile="color",
|
|
*,
|
|
size=(1200, 1600),
|
|
layout_provider=None,
|
|
):
|
|
width, height = size
|
|
layout = (layout_provider or WatermarkLayout()).layout(size, caption)
|
|
if not (
|
|
0 < layout.footer_height < height
|
|
and 0 < layout.margin < width / 2
|
|
and layout.font_size > 0
|
|
):
|
|
raise ValueError("Invalid photo layout")
|
|
photo_height = height - layout.footer_height
|
|
# Legacy tasks used contain: watermark photos now fill the photo area,
|
|
# keeping aspect ratio and cropping rather than stretching or letterboxing.
|
|
photo_data = convert(
|
|
data,
|
|
"smart" if fit == "smart" else "cover",
|
|
profile,
|
|
size=(width, photo_height),
|
|
)
|
|
canvas = Image.new("RGB", size, "white")
|
|
with Image.open(BytesIO(photo_data)) as photo:
|
|
canvas.paste(photo, (0, 0))
|
|
draw = ImageDraw.Draw(canvas)
|
|
values = [
|
|
" ".join(str(caption.get(key, "")).split())
|
|
for key in ("title", "date", "place")
|
|
]
|
|
text = " · ".join(value for value in values if value)
|
|
font_size = layout.font_size
|
|
font = font_loader(font_size)
|
|
available = width - 2 * layout.margin
|
|
while font_size > 24 and draw.textlength(text, font=font) > available:
|
|
font_size -= 2
|
|
font = font_loader(font_size)
|
|
# Shorten the title before touching the date/location. Never wrap the band.
|
|
while draw.textlength(text, font=font) > available and len(values[0]) > 2:
|
|
values[0] = values[0].rstrip("…")[:-1] + "…"
|
|
text = " · ".join(value for value in values if value)
|
|
while draw.textlength(text, font=font) > available and len(text) > 2:
|
|
text = text.rstrip("…")[:-1] + "…"
|
|
draw.text(
|
|
(width - layout.margin, photo_height + layout.footer_height / 2),
|
|
text,
|
|
font=font,
|
|
fill="black",
|
|
anchor="rm",
|
|
)
|
|
out = BytesIO()
|
|
canvas.save(out, "JPEG", quality=93, optimize=True)
|
|
return out.getvalue()
|