Compare commits
2 Commits
4d157453ce
...
29551abc2e
| Author | SHA1 | Date | |
|---|---|---|---|
| 29551abc2e | |||
| 9da9324484 |
Binary file not shown.
@ -542,57 +542,60 @@ class VibrantTemplate(BaseTemplate):
|
|||||||
logger.error("无法加载图片")
|
logger.error("无法加载图片")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
# 参考原始合成模式的PSD版本实现
|
||||||
main_image = self.image_processor.resize_image(image=main_image, target_size=self.size)
|
main_image = self.image_processor.resize_image(image=main_image, target_size=self.size)
|
||||||
estimated_height = self._estimate_content_height(content)
|
estimated_height = self._estimate_content_height(content)
|
||||||
gradient_start = self._detect_gradient_start_position(main_image, estimated_height)
|
gradient_start = self._detect_gradient_start_position(main_image, estimated_height)
|
||||||
|
|
||||||
# 创建新的PSD文档(使用透明背景)
|
# === 第一步:创建与常规模式完全相同的最终结果作为Reference ===
|
||||||
psd = PSDImage.new("RGBA", self.size, color=(0, 0, 0, 0))
|
canvas = self._create_composite_image(main_image, gradient_start, theme_color)
|
||||||
logger.info(f"创建PSD文档,尺寸: {self.size}")
|
canvas = self._render_texts(canvas, content, gradient_start)
|
||||||
|
final_canvas = canvas.resize((1350, 1800), Image.LANCZOS)
|
||||||
|
|
||||||
# 1. 添加背景图层
|
# === 第二步:为PSD创建可编辑的图层版本 ===
|
||||||
background_layer = PixelLayer.frompil(main_image, psd, "Background")
|
final_size = (1350, 1800)
|
||||||
psd.append(background_layer)
|
psd = PSDImage.new("RGBA", final_size, color=(0, 0, 0, 0))
|
||||||
logger.info("✓ 添加背景图层")
|
logger.info(f"创建PSD文档,尺寸: {final_size}")
|
||||||
|
|
||||||
# 2. 添加毛玻璃效果层
|
# 图层1:完美一致的参考图层
|
||||||
|
composite_layer = PixelLayer.frompil(final_canvas, psd, "Perfect Reference")
|
||||||
|
psd.append(composite_layer)
|
||||||
|
logger.info("✓ 添加完美参考图层")
|
||||||
|
|
||||||
|
# === 第三步:提供丰富的可编辑图层 ===
|
||||||
|
|
||||||
|
# 图层2:纯背景图层(无任何效果)
|
||||||
|
background_only = main_image.resize(final_size, Image.LANCZOS)
|
||||||
|
bg_layer = PixelLayer.frompil(background_only, psd, "Background Image")
|
||||||
|
psd.append(bg_layer)
|
||||||
|
logger.info("✓ 添加纯背景图层")
|
||||||
|
|
||||||
|
# 图层3:毛玻璃效果图层
|
||||||
glass_overlay = self._create_glass_overlay_layer(main_image, gradient_start, theme_color)
|
glass_overlay = self._create_glass_overlay_layer(main_image, gradient_start, theme_color)
|
||||||
if glass_overlay:
|
if glass_overlay:
|
||||||
glass_layer = PixelLayer.frompil(glass_overlay, psd, "Glass Effect")
|
glass_scaled = glass_overlay.resize(final_size, Image.LANCZOS)
|
||||||
|
glass_layer = PixelLayer.frompil(glass_scaled, psd, "Glass Overlay")
|
||||||
psd.append(glass_layer)
|
psd.append(glass_layer)
|
||||||
logger.info("✓ 添加毛玻璃效果层")
|
logger.info("✓ 添加毛玻璃效果图层")
|
||||||
|
|
||||||
# 3-7. 添加文字图层
|
# 图层4-9:分离的文字图层
|
||||||
text_layers = self._create_text_layers(content, gradient_start)
|
detailed_text_layers = self._create_detailed_text_layers(content, gradient_start, self.size)
|
||||||
for layer_name, layer_image in text_layers.items():
|
for layer_name, layer_image in detailed_text_layers.items():
|
||||||
if layer_image:
|
if layer_image:
|
||||||
text_layer = PixelLayer.frompil(layer_image, psd, layer_name)
|
text_scaled = layer_image.resize(final_size, Image.LANCZOS)
|
||||||
|
text_layer = PixelLayer.frompil(text_scaled, psd, layer_name)
|
||||||
psd.append(text_layer)
|
psd.append(text_layer)
|
||||||
logger.info(f"✓ Added {layer_name} layer")
|
logger.info(f"✓ 添加文字图层: {layer_name}")
|
||||||
|
|
||||||
# 应用与常规模式相同的尺寸调整 (1350x1800)
|
# 图层10:整体文字图层(备用)
|
||||||
final_size = (1350, 1800)
|
text_only_canvas = self._create_text_only_layer(content, gradient_start, self.size)
|
||||||
|
if text_only_canvas:
|
||||||
|
text_only_scaled = text_only_canvas.resize(final_size, Image.LANCZOS)
|
||||||
|
all_text_layer = PixelLayer.frompil(text_only_scaled, psd, "All Text (Backup)")
|
||||||
|
psd.append(all_text_layer)
|
||||||
|
logger.info("✓ 添加整体文字备用图层")
|
||||||
|
|
||||||
# 调整PSD文档尺寸以匹配常规输出
|
logger.info(f"PSD包含{len(list(psd))}个图层:1个参考层+{len(list(psd))-1}个编辑层")
|
||||||
if psd.size != final_size:
|
|
||||||
logger.info(f"调整PSD尺寸: {psd.size} -> {final_size}")
|
|
||||||
# 重新创建PSD文档以匹配最终尺寸
|
|
||||||
final_psd = PSDImage.new("RGBA", final_size, color=(0, 0, 0, 0))
|
|
||||||
|
|
||||||
# 调整并添加所有图层
|
|
||||||
for layer in psd:
|
|
||||||
try:
|
|
||||||
if hasattr(layer, 'composite'):
|
|
||||||
layer_image = layer.composite()
|
|
||||||
if layer_image:
|
|
||||||
# 调整图层尺寸
|
|
||||||
resized_layer = layer_image.resize(final_size, Image.LANCZOS)
|
|
||||||
final_layer = PixelLayer.frompil(resized_layer, final_psd, layer.name)
|
|
||||||
final_psd.append(final_layer)
|
|
||||||
except Exception as e:
|
|
||||||
logger.warning(f"调整图层 {layer.name} 失败: {e}")
|
|
||||||
|
|
||||||
psd = final_psd
|
|
||||||
|
|
||||||
# 保存PSD文件
|
# 保存PSD文件
|
||||||
psd.save(output_path)
|
psd.save(output_path)
|
||||||
@ -615,6 +618,8 @@ class VibrantTemplate(BaseTemplate):
|
|||||||
logger.error(f"创建毛玻璃层失败: {e}")
|
logger.error(f"创建毛玻璃层失败: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def _create_text_layers(self, content: Dict[str, Any], gradient_start: int) -> Dict[str, Optional[Image.Image]]:
|
def _create_text_layers(self, content: Dict[str, Any], gradient_start: int) -> Dict[str, Optional[Image.Image]]:
|
||||||
"""创建各个文字图层"""
|
"""创建各个文字图层"""
|
||||||
layers = {}
|
layers = {}
|
||||||
@ -659,6 +664,151 @@ class VibrantTemplate(BaseTemplate):
|
|||||||
|
|
||||||
return layers
|
return layers
|
||||||
|
|
||||||
|
def _create_text_only_layer(self, content: Dict[str, Any], gradient_start: int, canvas_size: tuple) -> Optional[Image.Image]:
|
||||||
|
"""创建纯文字图层(透明背景),模拟_render_texts的渲染逻辑"""
|
||||||
|
try:
|
||||||
|
# 创建透明画布
|
||||||
|
text_canvas = Image.new('RGBA', canvas_size, (0, 0, 0, 0))
|
||||||
|
draw = ImageDraw.Draw(text_canvas)
|
||||||
|
|
||||||
|
width, height = canvas_size
|
||||||
|
center_x = width // 2
|
||||||
|
|
||||||
|
# 使用与原始方法相同的布局计算
|
||||||
|
left_margin, right_margin = self._calculate_content_margins(content, width, center_x)
|
||||||
|
|
||||||
|
# 页脚
|
||||||
|
footer_y = height - 30
|
||||||
|
self._render_footer(draw, content, footer_y, left_margin, right_margin)
|
||||||
|
|
||||||
|
# 标题和副标题
|
||||||
|
title_y = gradient_start + 40
|
||||||
|
current_y = self._render_title_subtitle(draw, content, title_y, center_x, left_margin, right_margin)
|
||||||
|
|
||||||
|
# 左右栏内容
|
||||||
|
content_area_width = right_margin - left_margin
|
||||||
|
left_column_width = int(content_area_width * 0.5)
|
||||||
|
right_column_x = left_margin + left_column_width
|
||||||
|
|
||||||
|
content_start_y = current_y + 30
|
||||||
|
self._render_left_column(draw, content, content_start_y, left_margin, left_column_width, height)
|
||||||
|
self._render_right_column(draw, content, content_start_y, right_column_x, right_margin)
|
||||||
|
|
||||||
|
return text_canvas
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"创建纯文字图层失败: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _create_text_only_layer(self, content: Dict[str, Any], gradient_start: int, canvas_size: tuple) -> Optional[Image.Image]:
|
||||||
|
"""创建纯文字图层(透明背景),模拟_render_texts的渲染逻辑"""
|
||||||
|
try:
|
||||||
|
# 创建透明画布
|
||||||
|
text_canvas = Image.new('RGBA', canvas_size, (0, 0, 0, 0))
|
||||||
|
draw = ImageDraw.Draw(text_canvas)
|
||||||
|
|
||||||
|
width, height = canvas_size
|
||||||
|
center_x = width // 2
|
||||||
|
|
||||||
|
# 使用与原始方法相同的布局计算
|
||||||
|
left_margin, right_margin = self._calculate_content_margins(content, width, center_x)
|
||||||
|
|
||||||
|
# 页脚
|
||||||
|
footer_y = height - 30
|
||||||
|
self._render_footer(draw, content, footer_y, left_margin, right_margin)
|
||||||
|
|
||||||
|
# 标题和副标题
|
||||||
|
title_y = gradient_start + 40
|
||||||
|
current_y = self._render_title_subtitle(draw, content, title_y, center_x, left_margin, right_margin)
|
||||||
|
|
||||||
|
# 左右栏内容
|
||||||
|
content_area_width = right_margin - left_margin
|
||||||
|
left_column_width = int(content_area_width * 0.5)
|
||||||
|
right_column_x = left_margin + left_column_width
|
||||||
|
|
||||||
|
content_start_y = current_y + 30
|
||||||
|
self._render_left_column(draw, content, content_start_y, left_margin, left_column_width, height)
|
||||||
|
self._render_right_column(draw, content, content_start_y, right_column_x, right_margin)
|
||||||
|
|
||||||
|
return text_canvas
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"创建纯文字图层失败: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _create_detailed_text_layers(self, content: Dict[str, Any], gradient_start: int, canvas_size: tuple) -> Dict[str, Optional[Image.Image]]:
|
||||||
|
"""创建详细的分离文字图层,每个文字元素独立可编辑"""
|
||||||
|
layers = {}
|
||||||
|
|
||||||
|
try:
|
||||||
|
width, height = canvas_size
|
||||||
|
center_x = width // 2
|
||||||
|
left_margin, right_margin = self._calculate_content_margins(content, width, center_x)
|
||||||
|
|
||||||
|
# 1. 标题图层
|
||||||
|
title_canvas = Image.new('RGBA', canvas_size, (0, 0, 0, 0))
|
||||||
|
title_draw = ImageDraw.Draw(title_canvas)
|
||||||
|
title_y = gradient_start + 40
|
||||||
|
|
||||||
|
title_text = content.get("title", "默认标题")
|
||||||
|
title_target_width = int((right_margin - left_margin) * 0.98)
|
||||||
|
title_size, title_actual_width = self._calculate_optimal_font_size_enhanced(
|
||||||
|
title_text, title_target_width, max_size=140, min_size=40
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
title_font = ImageFont.truetype(self.chinese_font_path, title_size)
|
||||||
|
except:
|
||||||
|
title_font = self.text_renderer._load_default_font(title_size)
|
||||||
|
text_w, text_h = self.text_renderer.get_text_size(title_text, title_font)
|
||||||
|
title_x = center_x - text_w // 2
|
||||||
|
|
||||||
|
self.text_renderer.draw_text_with_outline(title_draw, (title_x, title_y), title_text, title_font,
|
||||||
|
text_color=(255, 255, 255, 255), outline_color=(0, 30, 80, 200), outline_width=4)
|
||||||
|
layers["Title Text"] = title_canvas
|
||||||
|
|
||||||
|
# 2. 副标题图层
|
||||||
|
subtitle_canvas = Image.new('RGBA', canvas_size, (0, 0, 0, 0))
|
||||||
|
subtitle_draw = ImageDraw.Draw(subtitle_canvas)
|
||||||
|
|
||||||
|
subtitle_text = content.get("slogan", "")
|
||||||
|
if subtitle_text:
|
||||||
|
subtitle_target_width = int((right_margin - left_margin) * 0.95)
|
||||||
|
subtitle_size, subtitle_actual_width = self._calculate_optimal_font_size_enhanced(
|
||||||
|
subtitle_text, subtitle_target_width, max_size=75, min_size=20
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
subtitle_font = ImageFont.truetype(self.chinese_font_path, subtitle_size)
|
||||||
|
except:
|
||||||
|
subtitle_font = self.text_renderer._load_default_font(subtitle_size)
|
||||||
|
sub_text_w, sub_text_h = self.text_renderer.get_text_size(subtitle_text, subtitle_font)
|
||||||
|
subtitle_x = center_x - sub_text_w // 2
|
||||||
|
subtitle_y = title_y + text_h + 30
|
||||||
|
|
||||||
|
self.text_renderer.draw_text_with_shadow(subtitle_draw, (subtitle_x, subtitle_y), subtitle_text, subtitle_font,
|
||||||
|
text_color=(255, 255, 255, 255), shadow_color=(0, 0, 0, 180), shadow_offset=(2, 2))
|
||||||
|
layers["Subtitle Text"] = subtitle_canvas
|
||||||
|
|
||||||
|
# 3. 页脚图层
|
||||||
|
footer_canvas = Image.new('RGBA', canvas_size, (0, 0, 0, 0))
|
||||||
|
footer_draw = ImageDraw.Draw(footer_canvas)
|
||||||
|
|
||||||
|
footer_y = height - 30
|
||||||
|
try:
|
||||||
|
footer_font = ImageFont.truetype(self.chinese_font_path, 18)
|
||||||
|
except:
|
||||||
|
footer_font = self.text_renderer._load_default_font(18)
|
||||||
|
|
||||||
|
if tag := content.get("tag"):
|
||||||
|
footer_draw.text((left_margin, footer_y), tag, font=footer_font, fill=(255, 255, 255))
|
||||||
|
if pagination := content.get("pagination"):
|
||||||
|
width_pg, _ = self.text_renderer.get_text_size(pagination, footer_font)
|
||||||
|
footer_draw.text((right_margin - width_pg, footer_y), pagination, font=footer_font, fill=(255, 255, 255))
|
||||||
|
|
||||||
|
layers["Footer"] = footer_canvas
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"创建详细文字图层失败: {e}")
|
||||||
|
|
||||||
|
return {k: v for k, v in layers.items() if v is not None}
|
||||||
|
|
||||||
def _draw_text_with_outline_simple(self, draw: ImageDraw.Draw, position: Tuple[int, int],
|
def _draw_text_with_outline_simple(self, draw: ImageDraw.Draw, position: Tuple[int, int],
|
||||||
text: str, font: ImageFont.FreeTypeFont,
|
text: str, font: ImageFont.FreeTypeFont,
|
||||||
text_color: Tuple[int, int, int, int] = (255, 255, 255, 255),
|
text_color: Tuple[int, int, int, int] = (255, 255, 255, 255),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user