moviepy字幕移動

msms123發表於2024-12-06

moviepy==1.0.2
整塊字幕移動

# 字幕整塊平移🆗
from moviepy.editor import VideoFileClip, CompositeVideoClip, ImageClip
from PIL import Image, ImageFont, ImageDraw
import numpy as np

def wrap_text(text, font, max_width):
    """
    自動換行函式:根據指定的最大寬度對文字進行折行
    :param text: 字幕文字
    :param font: PIL字型物件
    :param max_width: 每行最大寬度
    :return: 換行後的文字列表
    """
    lines = []
    current_line = ""
    for char in text:  # 中文按字元處理
        test_line = current_line + char
        line_width = font.getbbox(test_line)[2]  # 使用 getbbox(文字邊界) 獲取寬度
        if line_width <= max_width:
            current_line = test_line
        else:
            lines.append(current_line)
            current_line = char
    if current_line:  # 新增最後一行
        lines.append(current_line)
    return lines

def generate_subtitle_image(text, font_path, font_size, video_width, video_height, white_space):
    """
    生成帶有字幕的影像,自動換行
    :param text: 字幕文字
    :param font_path: 字型路徑
    :param font_size: 字型大小
    :param video_width: 影片寬度
    :param video_height: 影片高度
    :param white_space: 影片左右留白
    :return: 帶有字幕的影像(numpy陣列)
    """
    font = ImageFont.truetype(font_path, font_size)
    max_width = video_width - white_space  # 留左右邊距

    # 自動換行
    wrapped_text = wrap_text(text, font, max_width)

    # 建立字幕影像
    image = Image.new("RGBA", (video_width, video_height), (255, 255, 255, 0))  # 透明背景
    draw = ImageDraw.Draw(image)

    # 繪製字幕:居中顯示,每行水平居中,底部顯示
    line_height = font.getbbox("測試")[3]  # 使用 getbbox 獲取行高
    y_position = video_height - line_height * len(wrapped_text) - 20  # 字幕距底部20畫素
    for line in wrapped_text:
        text_width = font.getbbox(line)[2]
        x_position = (video_width - text_width) // 2  # 居中
        draw.text((x_position, y_position), line, font=font, fill="white")
        y_position += line_height

    return np.array(image)

def add_scroll_effect(subtitle_image, video_clip, duration=3):
    """
    給字幕新增平移效果(從上至下)
    :param subtitle_image: 字幕影像(numpy陣列)
    :param video_clip: 影片剪輯
    :param duration: 平移的持續時間
    :return: 帶平移效果的字幕剪輯
    """
    subtitle_clip = ImageClip(subtitle_image, duration=duration)

    # 獲取字幕的最終y座標(影片底部附近)
    final_y_position = video_clip.h - subtitle_clip.h - 20  # 字幕停留在影片底部

    # 設定字幕從頂部滑入,平移至底部
    subtitle_clip = subtitle_clip.set_position(lambda t: ("center", min(final_y_position, -subtitle_clip.h + t * (video_clip.h + subtitle_clip.h) / duration)))

    return subtitle_clip

def output(subtitle_clip, video_clip, output_path):
    # 合成影片
    composite_clip = CompositeVideoClip([video_clip, subtitle_clip])

    # 輸出影片
    composite_clip.write_videofile(output_path, codec="libx264", fps=24)

if __name__ == '__main__':

    # 影片路徑
    video_path = "1127.mp4"
    output_path = "output_with_falling_subtitles.mp4"

    # 載入影片並獲取寬高
    video_clip = VideoFileClip(video_path)
    video_width, video_height = video_clip.w, video_clip.h

    # 字幕文字
    subtitle_text = "這是一個字幕示例,平移到影片底部"
    # 字幕樣式
    custom_font_path = r"C:\Windows\Fonts\msyh.ttc"  # 替換為實際字型路徑
    font_size = 50
    white_space = 20  # 字幕左右留白

    # 生成字幕影像
    subtitle_image = generate_subtitle_image(
        subtitle_text, custom_font_path, font_size, video_width, video_height, white_space
    )

    # 給字幕新增平移效果
    subtitle_clip = add_scroll_effect(subtitle_image, video_clip)

    # 合成影片並應用字幕效果
    output(subtitle_clip, video_clip, output_path)

從右到左

#整個字幕從右到左🆗
from moviepy.editor import VideoFileClip, CompositeVideoClip, ImageClip
from PIL import Image, ImageFont, ImageDraw
import numpy as np

def wrap_text(text, font, max_width):
    """
    自動換行函式:根據指定的最大寬度對文字進行折行
    :param text: 字幕文字
    :param font: PIL字型物件
    :param max_width: 每行最大寬度
    :return: 換行後的文字列表
    """
    lines = []
    current_line = ""
    for char in text:  # 中文按字元處理
        test_line = current_line + char
        line_width = font.getbbox(test_line)[2]  # 使用 getbbox(文字邊界) 獲取寬度
        if line_width <= max_width:
            current_line = test_line
        else:
            lines.append(current_line)
            current_line = char
    if current_line:  # 新增最後一行
        lines.append(current_line)
    return lines

def generate_subtitle_image(text, font_path, font_size, video_width, video_height, white_space):
    """
    生成帶有字幕的影像,自動換行
    :param text: 字幕文字
    :param font_path: 字型路徑
    :param font_size: 字型大小
    :param video_width: 影片寬度
    :param video_height: 影片高度
    :param white_space: 影片左右留白
    :return: 帶有字幕的影像(numpy陣列)
    """
    font = ImageFont.truetype(font_path, font_size)
    max_width = video_width - white_space  # 留左右邊距

    # 自動換行
    wrapped_text = wrap_text(text, font, max_width)

    # 建立字幕影像
    image = Image.new("RGBA", (video_width, video_height), (255, 255, 255, 0))  # 透明背景
    draw = ImageDraw.Draw(image)

    # 繪製字幕:居中顯示,每行水平居中,底部顯示
    line_height = font.getbbox("測試")[3]  # 使用 getbbox 獲取行高
    y_position = video_height - line_height * len(wrapped_text) - 20  # 字幕距底部20畫素
    for line in wrapped_text:
        text_width = font.getbbox(line)[2]
        x_position = (video_width - text_width) // 2  # 居中
        draw.text((x_position, y_position), line, font=font, fill="white")
        y_position += line_height

    return np.array(image)

def add_scroll_effect(subtitle_image, video_clip, text, font_path, font_size, white_space, duration=5, stay_duration=5):
    """
    給字幕新增從右到左滾動效果,並最終固定在影片底部
    :param subtitle_image: 字幕影像(numpy陣列)
    :param video_clip: 影片剪輯
    :param text: 字幕文字
    :param font_path: 字型路徑
    :param font_size: 字型大小
    :param white_space: 字幕左右留白
    :param duration: 滾動持續時間
    :param stay_duration: 字幕停留時間(以秒為單位)
    :return: 帶滾動效果的字幕剪輯
    """
    subtitle_clip = ImageClip(subtitle_image, duration=duration + stay_duration)

    # 設定字幕初始位置在螢幕右邊,使用 `set_position` 來實現滾動
    def scroll_position(t):
        max_x_position = video_clip.w + subtitle_clip.w
        if t < duration:  # 在滾動時間內,字幕從右到左
            return max_x_position - (max_x_position * t / duration), video_clip.h - subtitle_clip.h - 20
        else:  # 滾動結束後,字幕保持在底部
            return (video_clip.w - subtitle_clip.w) // 2, video_clip.h - subtitle_clip.h - 20

    # 設定字幕開始時間和持續時間
    subtitle_clip = subtitle_clip.set_position(scroll_position).set_start(0).set_duration(duration + stay_duration)

    return subtitle_clip

def output(subtitle_clip, video_clip, output_path):
    # 合成影片
    composite_clip = CompositeVideoClip([video_clip, subtitle_clip])

    # 輸出影片
    composite_clip.write_videofile(output_path, codec="libx264", fps=24)

if __name__ == '__main__':
    # 影片路徑
    video_path = "1127.mp4"
    output_path = "output_with_falling_subtitles.mp4"

    # 載入影片並獲取寬高
    video_clip = VideoFileClip(video_path)
    video_width, video_height = video_clip.w, video_clip.h

    # 字幕文字
    subtitle_text = "ewrqwrwgf這是一個字幕示例,平移到影片底部"
    # 字幕樣式
    custom_font_path = r"C:\Windows\Fonts\msyh.ttc"  # 替換為實際字型路徑
    font_size = 50
    white_space = 20  # 字幕左右留白

    # 生成字幕影像
    subtitle_image = generate_subtitle_image(subtitle_text, custom_font_path, font_size, video_width, video_height, white_space)

    # 給字幕新增平移效果
    subtitle_clip = add_scroll_effect(subtitle_image, video_clip, subtitle_text, custom_font_path, font_size, white_space, stay_duration=10)

    # 合成影片並應用字幕效果
    output(subtitle_clip, video_clip, output_path)

單個字幕移動可參照,字元動態效果

相關文章