首页 > 其他分享 >moviepy添加字幕

moviepy添加字幕

时间:2024-11-27 17:46:55浏览次数:6  
标签:moviepy text width 字幕 添加 import line font

给视频增加字幕,根据视频宽度和字幕的长度对比,判断是否要换行

单个字幕

import os
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 output(subtitle_image):
    # 创建字幕ImageClip
    subtitle_clip = ImageClip(subtitle_image, duration=video_clip.duration)

    # 合成视频
    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_112750长.mp4"

    # 加载视频并获取宽高
    video_clip = VideoFileClip(video_path)
    video_width, video_height = video_clip.w, video_clip.h
    print(f"视频宽度: {video_width}px, 视频高度: {video_height}px")

    # 字幕文本
    subtitle_text = "sdakjslfkdfgdfsfagfasfgsagf"
    print(f"字幕原始文本长度: {len(subtitle_text)}")

    # 字幕样式
    custom_font_path = r"C:\Windows\Fonts\msyh.ttc"  # 替换为实际字体路径
    if not os.path.exists(custom_font_path):
        print(f"字体文件不存在:{custom_font_path}")
    else:
        print(f"字体文件存在:{custom_font_path}")
    font_size = 50
    white_space = 20  #字幕左右留白

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

    output(subtitle_image)

多段字幕

from moviepy.editor import VideoFileClip, CompositeVideoClip, ImageClip
from PIL import Image, ImageFont, ImageDraw
import numpy as np


# 自动换行函数
def wrap_text(text, font, max_width):
    lines = []
    current_line = ""
    for char in text:
        test_line = current_line + char
        line_width = font.getbbox(test_line)[2]
        if line_width <= max_width:
            current_line = test_line
        else:
            if current_line:
                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, line_spacing=10):
    font = ImageFont.truetype(font_path, font_size)
    max_width = video_width - 40  # Subtract some padding
    wrapped_text = wrap_text(text, font, max_width)

    # 计算每行的高度,基于行数和行距来计算总高度
    line_height = font.getbbox("测试")[3]
    image_height = line_height * len(wrapped_text) + line_spacing * (len(wrapped_text) - 1) + 20  # 额外的顶部和底部填充
    image = Image.new("RGBA", (video_width, image_height), (255, 255, 255, 0))
    draw = ImageDraw.Draw(image)

    y_position = 10
    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 + line_spacing

    return np.array(image), image_height


# 动态调整字体大小(如果需要)
def adjust_font_size(text, font_path, max_width, max_height, initial_font_size=40):
    font_size = initial_font_size
    font = ImageFont.truetype(font_path, font_size)

    # 不断减小字体,直到文本适配屏幕宽度和高度
    while True:
        wrapped_text = wrap_text(text, font, max_width)
        line_height = font.getbbox("测试")[3]
        total_height = line_height * len(wrapped_text) + (len(wrapped_text) - 1) * 10  # 行高和行间距
        if total_height <= max_height and all(font.getbbox(line)[2] <= max_width for line in wrapped_text):
            break
        font_size -= 1  # 字体过大时减小字体
        font = ImageFont.truetype(font_path, font_size)

    return font, wrapped_text, line_height


def output(subtitle_clips):
    # 合成视频
    composite_clip = CompositeVideoClip([video_clip] + subtitle_clips)
    composite_clip.write_videofile(output_path, codec="libx264", fps=24)


def letter_generation(subtitles):
    # 生成字幕片段
    subtitle_clips = []
    for subtitle in subtitles:
        # 调整字体大小以适配视频宽度和高度
        font, wrapped_text, line_height = adjust_font_size(
            subtitle["text"], custom_font_path, video_width - 40, video_height // 4, initial_font_size
        )

        # 生成字幕图像
        subtitle_image, subtitle_height = generate_subtitle_image(
            subtitle["text"], custom_font_path, font.size, video_width, line_spacing
        )

        # 设置字幕位置并考虑底部留白(底部空隙 20 像素)
        subtitle_clip = (
            ImageClip(subtitle_image, duration=subtitle["end"] - subtitle["start"])
            .set_start(subtitle["start"])
            .set_position(("center", video_height - subtitle_height - 30))  # 给字幕底部增加 30 像素空隙
        )
        subtitle_clips.append(subtitle_clip)
    output(subtitle_clips)



if __name__ == '__main__':
    # 主逻辑
    video_path = "1127.mp4"
    output_path = "output_with_subtitles1.mp4"

    # 视频片段
    video_clip = VideoFileClip(video_path)
    video_width, video_height = video_clip.w, video_clip.h

    # 字体配置
    custom_font_path = r"C:\Windows\Fonts\msyh.ttc"  # 替换为实际字体路径
    initial_font_size = 40
    line_spacing = 10  # 设置行距

    # 字幕列表,每段字幕包含文本、开始时间、结束时间
    subtitles = [
        {"text": "这是第一段字幕,显示时间是0到5秒adfa", "start": 0, "end": 5},
        {"text": "这是第二段字幕,显示时间是5到10秒,这段字幕会自动换行af。", "start": 5, "end": 10},
        {"text": "第三段字幕更短,显示时间是10到15秒asda。", "start": 10, "end": 15},
    ]
    letter_generation(subtitles)

标签:moviepy,text,width,字幕,添加,import,line,font
From: https://www.cnblogs.com/msmsga/p/18572764

相关文章

  • 总结一下目前使用moviepy遇到的问题
    我的moviepy版本是1.0.21·有时在movipy输出文件时报错‘NoneType’objecthasnoattribute'stdout’问题。原因是保存了一个clip后,使用了close函数将clip对象关闭。我的解决方法是:删除moviepy库文件下的audio\io子目录下AudioFileClip.py的析构方法__del__2·还有个就......
  • css 判断在支持某些属性的情况下再添加样式
    :root{--safe-area-inset-top:0px;--safe-area-inset-right:0px;--safe-area-inset-bottom:0px;--safe-area-inset-left:0px;--safe-area-inset-constant-top:0px;--safe-area-inset-constant-right:0px;--safe-area-inset-constant-bottom:0px;......
  • 使用 Pyinstaller 打包为 windows exe程序 添加管理员权限的多种方式
    使用Pyinstaller打包为windowsexe程序添加管理员权限的多种方式本文提供几种在使用Pyinstaller打包后,为包体exe提升管理员权限的方式。注意事项:管理员权限的必要性:确保程序确实需要管理员权限,否则用户可能会质疑程序的安全性。数字签名:最好对生成的.exe文件进行数字......
  • C# ClosedXML 导出 Excel 添加下拉选项 CellDropdown
    注意string左右两边引号不能省略privatevoidAddCellDropdown(stringpath){//使用ClosedXML打开Excel文件using(varworkbook=newXLWorkbook(path)){//Shee1页面varworksheet1=workbook.Worksh......
  • 【RAG 项目实战 08】为 RAG 添加历史对话能力
    【RAG项目实战08】为RAG添加历史对话能力NLPGithub项目:NLP项目实践:fasterai/nlp-project-practice介绍:该仓库围绕着NLP任务模型的设计、训练、优化、部署和应用,分享大模型算法工程师的日常工作和实战经验AI藏经阁:https://gitee.com/fasterai/ai-e-book介绍:该......
  • 2024 最新 Kali Linux 定制化魔改,完整版添加常见60渗透工具
    系统版本:kalilinux2024.1固件类型:BIOS用户:zss密码:ss系统压缩大小:18.8GB,解出来:36.00GB左右,请提前预留好足够的空间下载链接https://pan.quark.cn/s/e5ca0a5847a4这个版本添加工具武器库比如我们pip命令后面忘了是什么了,我们就可以输入pip然后在......
  • 【转】[C#] Aspose.pdf 添加文字水印
    转自:https://www.cnblogs.com/Shi-zy/p/15494760.html另一篇:https://www.cnblogs.com/z5337/p/7344636.html用aspose.word把word转pdf的代码段:DocumentpdfDocument=newDocument(@"D:\pdfdir\jhrs.com.pdf");for(intpageCount=1;pa......
  • 如何在ixBrowser中添加并使用Netnut
    如何在ixBrowser中添加并使用Netnut步骤1:首先进入Netnut官网,点击进入工作台,若你已经购买了代理,你可以在上方选择代理类型,国家,输入目标访问地址,并获取去代理信息;步骤2:打开ixBrowser,点击创建窗口,选择平台并输入窗口信息;步骤3:点击下一步进入代理配置界面,选择代理方式为自定......
  • 【转】cesium之添加天地图
    转自 https://www.cnblogs.com/s313139232/p/16351468.html公共参数:vartoken='7b56038c276128a86a5b946404bf4df4';//服务域名vartdtUrl='https://t{s}.tianditu.gov.cn/';//服务负载子域varsubdomains=['......
  • 微信小程序布局图片上面添加文字
    效果图:补充知识:CSSposition相对定位和绝对定位一、position的四个值:static、relative、absolute、fixed。绝对定位:absolute和fixed统称为绝对定位相对定位:relative默认值:static二、relative定位与absolute定位的区别relative:定位是相对于自身位置定位(设置偏移量......