import os
from gtts import gTTS
from moviepy.editor import *
from PIL import Image, ImageDraw, ImageFont
# ===================== 配置 =====================
os.environ['HTTP_PROXY'] = "http://127.0.0.1:33210"
os.environ['HTTPS_PROXY'] = "http://127.0.0.1:33210"
VIDEO_SIZE = (720, 480)
WORD_FONT_SIZE = 120
SYNONYM_FONT_SIZE = 50
DURATION_PER_REPEAT = 0.5
REPEATS = 10
OUTPUT_DIR = "videos"
WOODEN_FISH_FILE = "wooden_fish.mp3"
words_dict = {
"deserve": ["earn", "rate", "be entitled to"],
"Institutional ": ["organizational"],
"countless ": ["innumerable", "numerous"]
}
os.makedirs(OUTPUT_DIR, exist_ok=True)
# ===================== 工具函数 =====================
def create_text_image(word, synonyms, size=VIDEO_SIZE):
"""生成图片,主词 + 近义词"""
img = Image.new("RGB", size, color="black")
draw = ImageDraw.Draw(img)
try:
word_font = ImageFont.truetype("arial.ttf", WORD_FONT_SIZE)
syn_font = ImageFont.truetype("arial.ttf", SYNONYM_FONT_SIZE)
except:
word_font = ImageFont.load_default()
syn_font = ImageFont.load_default()
# 主词
bbox_word = draw.textbbox((0,0), word, font=word_font)
word_width = bbox_word[2] - bbox_word[0]
word_height = bbox_word[3] - bbox_word[1]
x_word = (size[0] - word_width) / 2
y_word = size[1]*0.25 - word_height/2
draw.text((x_word, y_word), word, font=word_font, fill="white")
# 近义词
synonyms_text = ", ".join(synonyms)
bbox_syn = draw.textbbox((0,0), synonyms_text, font=syn_font)
syn_width = bbox_syn[2] - bbox_syn[0]
syn_height = bbox_syn[3] - bbox_syn[1]
x_syn = (size[0] - syn_width) / 2
y_syn = size[1]*0.75 - syn_height/2
draw.text((x_syn, y_syn), synonyms_text, font=syn_font, fill="yellow")
return img
def generate_video_for_word(word, synonyms):
# 生成语音
tts = gTTS(word, lang="en")
voice_file = os.path.join(OUTPUT_DIR, f"{word}_voice.mp3")
tts.save(voice_file)
voice_clip_full = AudioFileClip(voice_file)
# 木鱼
if os.path.exists(WOODEN_FISH_FILE):
wood_clip_full = AudioFileClip(WOODEN_FISH_FILE).volumex(0.4)
else:
wood_clip_full = None
clips = []
audio_clips = []
for i in range(REPEATS):
start_time = i * DURATION_PER_REPEAT
# 生成图片
img = create_text_image(word, synonyms)
frame_path = os.path.join(OUTPUT_DIR, f"{word}_frame_{i}.png")
img.save(frame_path)
# 创建 ImageClip
txt_clip = ImageClip(frame_path).set_duration(DURATION_PER_REPEAT)
# 弹跳动画:文字缩放
txt_clip = txt_clip.resize(lambda t: 0.5 + 0.5*t*2 if t < 0.5 else 1) # 弹出效果
txt_clip = txt_clip.set_start(start_time).set_position('center')
clips.append(txt_clip)
os.remove(frame_path)
# 音频片段
voice_seg = voice_clip_full.subclip(0, min(DURATION_PER_REPEAT, voice_clip_full.duration)).set_start(start_time)
if wood_clip_full:
wood_seg = wood_clip_full.subclip(0, DURATION_PER_REPEAT).set_start(start_time)
audio_seg = CompositeAudioClip([voice_seg, wood_seg])
else:
audio_seg = voice_seg
audio_clips.append(audio_seg)
# 合并音频
final_audio = CompositeAudioClip(audio_clips)
# 合成视频
video = CompositeVideoClip(clips, size=VIDEO_SIZE).set_audio(final_audio)
output_file = os.path.join(OUTPUT_DIR, f"{word}.mp4")
video.write_videofile(output_file, fps=24)
os.remove(voice_file)
print(f"生成完成: {output_file}")
# ===================== 主程序 =====================
for word, synonyms in words_dict.items():
generate_video_for_word(word, synonyms)
print("所有视频生成完成!")
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。