243 lines
8.7 KiB
Python
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'
|
|
) |