WeChatMsg_NY/newYear/utils/card_util.py
2025-01-22 17:35:47 +08:00

243 lines
8.7 KiB
Python

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import os
import json
import shutil
from datetime import datetime
def ensure_directory(directory):
"""确保目录存在,如果不存在则创建"""
if not os.path.exists(directory):
os.makedirs(directory)
def inject_data_to_template(template_path, data):
"""将数据注入到模板中
Args:
template_path: 模板文件路径
data: 包含以下字段的字典:
- year: 年份
- greeting_text: 新年祝福寄语(主标题)
- poem_text: 新年祝福诗
- idioms_text: 新年祝福成语
- wishes_text: 新年祝福愿望
- signature: 署名
"""
with open(template_path, 'r', encoding='utf-8') as f:
template_content = f.read()
# 处理祝福诗(分割成两句)
poem_lines = data.get('poem_text', '梦想飞扬似朝阳,岁岁安康伴春寒').split(',')
if len(poem_lines) < 2:
poem_lines = [poem_lines[0], poem_lines[0]] # 如果只有一句,重复使用
# 处理祝福成语(分割成三个)
idioms = data.get('idioms_text', '福满人间,万事胜意,喜乐安康').split(',')
while len(idioms) < 3: # 确保有3个成语
idioms.append(idioms[-1])
# 准备所有替换数据
replace_data = {
'year': data.get('year', '2025'),
'greeting_text': data.get('greeting_text', '新年快乐'),
'idioms_text_1': poem_lines[0],
'idioms_text_2': poem_lines[1],
'wishes_text': data.get('wishes_text', '愿你在新的一年里\\n事事顺遂 万事胜意'),
'signature': data.get('signature', '署名'),
'tag_1': idioms[0],
'tag_2': idioms[1],
'tag_3': idioms[2]
}
# 替换所有占位符
for key, value in replace_data.items():
placeholder = '{' + key + '}'
template_content = template_content.replace(placeholder, str(value))
# 创建临时文件来存储注入数据后的HTML
temp_html_path = 'temp_generated.html'
with open(temp_html_path, 'w', encoding='utf-8') as f:
f.write(template_content)
return temp_html_path
def capture_local_html(html_path, output_path, wait_time=2):
"""截取HTML页面为图片"""
print(f"\n=== 开始截取HTML页面 ===")
print(f"HTML文件路径: {html_path}")
print(f"输出路径: {output_path}")
if not os.path.exists(html_path):
error_msg = f'HTML文件不存在: {html_path}'
print(f"错误: {error_msg}")
raise FileNotFoundError(error_msg)
abs_path = os.path.abspath(html_path)
file_url = f'file:///{abs_path}'
print(f"文件URL: {file_url}")
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--hide-scrollbars')
chrome_options.add_argument('--disable-gpu')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-dev-shm-usage')
# 设置足够大的初始窗口,确保能完整显示内容
chrome_options.add_argument('--window-size=1920,1080')
driver = None
try:
print("\n1. 初始化Chrome WebDriver...")
driver = webdriver.Chrome(options=chrome_options)
print("\n2. 加载HTML页面...")
driver.get(file_url)
print("\n3. 等待页面元素加载...")
wait = WebDriverWait(driver, 10)
card_container = wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'card-container')))
print(f"\n4. 等待页面渲染 ({wait_time}秒)...")
import time
time.sleep(wait_time)
print("\n5. 获取卡片位置和尺寸...")
# 获取卡片容器的精确位置和尺寸
card_rect = driver.execute_script("""
const container = document.querySelector('.card-container');
const rect = container.getBoundingClientRect();
return {
left: rect.left,
top: rect.top,
width: rect.width,
height: rect.height,
devicePixelRatio: window.devicePixelRatio
};
""")
print(f"卡片信息: {card_rect}")
print("\n6. 截取完整页面...")
driver.save_screenshot('temp_full.png')
print("\n7. 裁剪卡片区域...")
from PIL import Image
img = Image.open('temp_full.png')
# 计算裁剪坐标(考虑设备像素比)
dpr = card_rect['devicePixelRatio']
left = int(card_rect['left'] * dpr)
top = int(card_rect['top'] * dpr)
right = int((card_rect['left'] + card_rect['width']) * dpr)
bottom = int((card_rect['top'] + card_rect['height']) * dpr)
print(f"裁剪坐标: left={left}, top={top}, right={right}, bottom={bottom}")
# 确保裁剪区域不超出图片范围
img_width, img_height = img.size
left = max(0, left)
top = max(0, top)
right = min(img_width, right)
bottom = min(img_height, bottom)
# 裁剪并保存
card_img = img.crop((left, top, right, bottom))
# 确保输出目录存在
output_dir = os.path.dirname(output_path)
if output_dir:
ensure_directory(output_dir)
print("\n8. 保存卡片图片...")
card_img.save(output_path, quality=100) # 使用最高质量
print(f'卡片截图已保存至: {output_path}')
print("\n9. 清理临时文件...")
os.remove('temp_full.png')
print("=== 截图完成 ===\n")
except Exception as e:
error_msg = f'截图过程发生错误: {str(e)}'
print(f"\nError: {error_msg}")
raise Exception(error_msg)
finally:
if driver:
print("\n10. 关闭WebDriver...")
driver.quit()
def generate_card(template_number, data, user_id):
"""生成贺卡并保存相关信息"""
print(f"\n=== 开始生成贺卡 ===")
print(f"模板编号: {template_number}")
print(f"用户ID: {user_id}")
try:
# 确保目录存在
print("\n1. 检查并创建必要的目录...")
ensure_directory('newYear/generate_img')
ensure_directory('newYear/version_history')
# 构建文件路径
template_path = f'newYear/template/template_{template_number}.html'
img_filename = f'{user_id}.png'
img_path = os.path.join('newYear/generate_img', img_filename)
json_path = os.path.join('newYear/version_history', f'{user_id}.json')
print(f"\n2. 检查模板文件: {template_path}")
if not os.path.exists(template_path):
raise FileNotFoundError(f'模板文件不存在: {template_path}')
print("\n3. 注入数据到模板...")
temp_html_path = inject_data_to_template(template_path, data)
print(f"临时HTML文件已创建: {temp_html_path}")
print("\n4. 生成贺卡图片...")
capture_local_html(temp_html_path, img_path, wait_time=2)
print("\n5. 更新JSON文件...")
# 只保存必要的文本数据和路径信息
json_data = {
'template_number': template_number,
'image_path': img_path,
'generation_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
'template_data': {
'year': data.get('year', '2025'),
'greeting_text': data.get('greeting_text', ''),
'poem_text': data.get('poem_text', ''),
'idioms_text': data.get('idioms_text', ''),
'wishes_text': data.get('wishes_text', ''),
'signature': data.get('signature', '')
}
}
with open(json_path, 'w', encoding='utf-8') as f:
json.dump(json_data, f, ensure_ascii=False, indent=4)
print(f"JSON文件已保存: {json_path}")
print("=== 贺卡生成完成 ===\n")
return img_path
except Exception as e:
error_msg = f'生成贺卡失败: {str(e)}'
print(f"\nError: {error_msg}")
raise Exception(error_msg)
# 使用示例
if __name__ == '__main__':
# 示例数据
test_data = {
'blessing_text': '新年快乐!',
'memory_text': '愿你在新的一年里事事顺心',
'signature': '小明'
}
# 生成卡片
img_path = generate_card(
template_number=1, # 使用模板1
data=test_data,
user_id='test_user'
)