Files
pigway-frame-flow/tests/test_photo_watermark.py
T

87 lines
2.8 KiB
Python
Raw Normal View History

from io import BytesIO
import pytest
from PIL import Image, ImageDraw
from pigway_frame_flow.renderers.photo_caption import render_captioned_photo
from pigway_frame_flow.renderers.photo_layout import PhotoLayout, WatermarkLayout
def test_watermark_includes_filename_and_recognized_people(service, monkeypatch):
drawn = []
original = ImageDraw.ImageDraw.text
def text(draw, xy, value, *args, **kwargs):
drawn.append(value)
return original(draw, xy, value, *args, **kwargs)
monkeypatch.setattr(ImageDraw.ImageDraw, "text", text)
stream = BytesIO()
Image.new("RGB", (160, 120), "blue").save(stream, "JPEG")
render_captioned_photo(
stream.getvalue(),
{
"date": "2026-10-17",
"title": "Family",
"filename": "one.jpg",
"people": "Alice · Bob",
},
service.renderer.font,
size=(1600, 1200),
)
assert drawn == ["2026-10-17 · Alice · Bob · Family · one.jpg"]
@pytest.mark.parametrize("size", [(1600, 1200), (1200, 1600)])
@pytest.mark.parametrize("fit", ["contain", "cover", "smart"])
def test_watermark_has_no_letterboxing(service, size, fit):
stream = BytesIO()
Image.new("RGB", (400, 100), "blue").save(stream, "JPEG")
data = render_captioned_photo(
stream.getvalue(),
{"title": "Family", "date": "2026-10-06", "place": "Shanghai"},
service.renderer.font,
fit=fit,
size=size,
)
with Image.open(BytesIO(data)) as image:
assert image.size == size
layout = WatermarkLayout().layout(size, {})
for point in [
(10, 10),
(size[0] - 10, 10),
(10, size[1] - layout.footer_height - 10),
]:
assert image.getpixel(point)[2] > image.getpixel(point)[0] + 100
assert image.getpixel((size[0] - 10, size[1] - 10))[0] > 240
assert layout.footer_height / min(size) <= 0.06
def test_layout_provider_is_injectable(service):
class Custom:
def layout(self, size, caption):
return PhotoLayout(100, 30, 40)
stream = BytesIO()
Image.new("RGB", (160, 120), "blue").save(stream, "JPEG")
data = render_captioned_photo(
stream.getvalue(),
{"title": "Custom", "date": "2026-10-06"},
service.renderer.font,
size=(1600, 1200),
layout_provider=Custom(),
)
with Image.open(BytesIO(data)) as image:
assert image.getpixel((1500, 1120))[0] > 240
def test_long_multiline_caption_does_not_wrap_or_hang(service):
stream = BytesIO()
Image.new("RGB", (160, 120), "blue").save(stream, "JPEG")
data = render_captioned_photo(
stream.getvalue(),
{"title": "Long title\n" * 100, "date": "2026-10-06", "place": "Place " * 100},
service.renderer.font,
)
assert Image.open(BytesIO(data)).size == (1200, 1600)