TravelContentCreator/poster/templates/collage_template.py

125 lines
4.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Collage风格拼图风格海报模板
"""
import logging
import random
from typing import List, Tuple, Optional
from PIL import Image, ImageDraw
from .base_template import BaseTemplate
logger = logging.getLogger(__name__)
class CollageTemplate(BaseTemplate):
"""
拼图风格模板,用于将多张图片组合成一张海报。
支持多种布局样式,如网格、非对称、电影胶片等。
"""
def generate(self,
image_paths: List[str],
style: str = 'grid_2x2',
**kwargs) -> Image.Image:
"""
生成拼图海报
Args:
image_paths (List[str]): 用于制作拼图的图片路径列表
style (str): 拼图样式 (例如 'grid_2x2', 'asymmetric', 'filmstrip')
Returns:
Image.Image: 生成的拼图海报图像
"""
if not self._validate_inputs(['image_paths'], image_paths=image_paths):
return None
if not image_paths:
logger.error("生成拼图失败: 图片列表不能为空。")
return None
images = [self.image_processor.load_image(p) for p in image_paths if p]
images = [img for img in images if img] # 过滤掉加载失败的图片
if not images:
logger.error("所有图片都加载失败。")
return None
# 根据样式选择对应的私有方法
style_method_name = f"_create_{style}_collage"
style_method = getattr(self, style_method_name, self._create_grid_2x2_collage)
logger.info(f"使用 '{style}' 风格创建拼图...")
return style_method(images, self.size)
def _resize_and_crop(self, img, target_size):
"""辅助方法:调整并裁剪图片以适应目标尺寸"""
return self.image_processor.resize_and_crop(img, target_size)
# --- 各种拼图样式的实现 ---
def _create_grid_2x2_collage(self, images: List[Image.Image], target_size: Tuple[int, int]) -> Image.Image:
"""创建 2x2 网格拼图"""
if len(images) < 4:
logger.warning(f"2x2网格需要4张图但只提供了{len(images)}张。将使用重复图片。")
images.extend([random.choice(images) for _ in range(4 - len(images))])
w, h = target_size
img_w, img_h = w // 2, h // 2
canvas = self.create_canvas()
resized_images = [self._resize_and_crop(img, (img_w, img_h)) for img in images[:4]]
canvas.paste(resized_images[0], (0, 0))
canvas.paste(resized_images[1], (img_w, 0))
canvas.paste(resized_images[2], (0, img_h))
canvas.paste(resized_images[3], (img_w, img_h))
return canvas
def _create_asymmetric_collage(self, images: List[Image.Image], target_size: Tuple[int, int]) -> Image.Image:
"""创建非对称拼图(左一右二)"""
if len(images) < 3:
logger.warning(f"非对称拼图需要3张图将使用重复图片。")
images.extend([random.choice(images) for _ in range(3 - len(images))])
w, h = target_size
main_w = int(w * 0.6)
side_w = w - main_w
side_h = h // 2
canvas = self.create_canvas()
main_img = self._resize_and_crop(images[0], (main_w, h))
side_img1 = self._resize_and_crop(images[1], (side_w, side_h))
side_img2 = self._resize_and_crop(images[2], (side_w, side_h))
canvas.paste(main_img, (0, 0))
canvas.paste(side_img1, (main_w, 0))
canvas.paste(side_img2, (main_w, side_h))
return canvas
def _create_filmstrip_collage(self, images: List[Image.Image], target_size: Tuple[int, int]) -> Image.Image:
"""创建电影胶片风格拼图"""
num_images = min(len(images), 4) # 最多4张
w, h = target_size
padding = 10
img_h = (h - (num_images + 1) * padding) // num_images
canvas = self.create_canvas(background_color=(30, 30, 30, 255))
current_y = padding
for img in images[:num_images]:
resized_img = self._resize_and_crop(img, (w - 2 * padding, img_h))
canvas.paste(resized_img, (padding, current_y))
current_y += img_h + padding
return canvas
def _validate_inputs(self, required_keys: list, **kwargs) -> bool:
return super()._validate_inputs(required_keys, **kwargs)