- 在所有布局类中添加 _add_object() 调用 - 渲染时同时记录元素位置到 _fabric_objects - V2 引擎直接从布局类获取 Fabric 对象 - 移除硬编码的 fallback 位置
105 lines
2.8 KiB
Python
105 lines
2.8 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
布局抽象基类
|
|
"""
|
|
|
|
from abc import ABC, abstractmethod
|
|
from typing import Tuple, Optional
|
|
from PIL import Image, ImageDraw
|
|
|
|
from ..schemas.content import PosterContent
|
|
from ..schemas.theme import Theme
|
|
from ..renderers.text import TextRenderer
|
|
from ..renderers.shape import ShapeRenderer
|
|
from ..renderers.effect import EffectRenderer
|
|
|
|
|
|
class BaseLayout(ABC):
|
|
"""
|
|
所有布局的抽象基类
|
|
|
|
布局负责:
|
|
1. 计算内容区域位置和尺寸
|
|
2. 协调各渲染器绘制内容
|
|
3. 生成最终海报图像
|
|
4. 记录元素位置 (用于 Fabric.js)
|
|
"""
|
|
|
|
# 默认尺寸 (小红书 3:4)
|
|
DEFAULT_SIZE = (1080, 1440)
|
|
|
|
# 默认边距
|
|
MARGIN = 48
|
|
PADDING = 32
|
|
|
|
def __init__(self, size: Tuple[int, int] = None):
|
|
self.width, self.height = size or self.DEFAULT_SIZE
|
|
self.size = (self.width, self.height)
|
|
|
|
# 渲染器
|
|
self.text = TextRenderer()
|
|
self.shape = ShapeRenderer()
|
|
self.effect = EffectRenderer()
|
|
|
|
# 元素记录 (用于 Fabric.js)
|
|
self._fabric_objects = []
|
|
|
|
def _reset_objects(self):
|
|
"""重置元素记录"""
|
|
self._fabric_objects = []
|
|
|
|
def _add_object(self, obj: dict):
|
|
"""添加元素"""
|
|
self._fabric_objects.append(obj)
|
|
|
|
def get_fabric_objects(self) -> list:
|
|
"""获取 Fabric.js 对象列表"""
|
|
return self._fabric_objects.copy()
|
|
|
|
@abstractmethod
|
|
def generate(self, content: PosterContent, theme: Theme) -> Image.Image:
|
|
"""
|
|
生成海报
|
|
|
|
Args:
|
|
content: 海报内容
|
|
theme: 主题配置
|
|
|
|
Returns:
|
|
生成的海报图像
|
|
"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
def calculate_content_height(self, content: PosterContent, theme: Theme) -> int:
|
|
"""
|
|
计算内容区域高度 (用于动态适配)
|
|
|
|
Args:
|
|
content: 海报内容
|
|
theme: 主题配置
|
|
|
|
Returns:
|
|
内容区域高度
|
|
"""
|
|
pass
|
|
|
|
def create_canvas(self, background: Tuple[int, int, int] = (255, 255, 255)) -> Image.Image:
|
|
"""创建画布"""
|
|
return Image.new("RGBA", self.size, (*background, 255))
|
|
|
|
def create_gradient_background(self, theme: Theme) -> Image.Image:
|
|
"""创建渐变背景"""
|
|
colors = theme.gradient_rgb
|
|
return self.effect.create_gradient(self.size, colors[0], colors[1])
|
|
|
|
def paste_with_alpha(self, canvas: Image.Image, layer: Image.Image, pos: Tuple[int, int]):
|
|
"""粘贴带透明度的图层"""
|
|
canvas.paste(layer, pos, layer)
|
|
|
|
@property
|
|
def layout_name(self) -> str:
|
|
"""布局名称"""
|
|
return self.__class__.__name__.replace("Layout", "").lower()
|