from io import BytesIO import pytest from PIL import Image from pigway_frame_flow.renderers.photo_caption import render_captioned_photo from pigway_frame_flow.renderers.photo_layout import PhotoLayout, WatermarkLayout @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)