news 2026/6/15 14:13:59

python_图片、字幕文本、音频一键组合

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
python_图片、字幕文本、音频一键组合

python_图片、字幕文本、音频一键组合

importosimportreimportrandomimportpyJianYingDraftasdraftfrompyJianYingDraftimportTrackType,TextStyle,ClipSettings,TextBackground,KeyframePropertyfromPILimportImage# 用于获取图片尺寸defsplit_subtitle(subtitle):"""将字幕按指定标点符号拆分短句,保留标点符号在句尾"""# 使用正则表达式拆分,保留分隔符在句尾separators=r'([,。!,!?;])'parts=re.split(separators,subtitle)# 组合拆分后的部分,形成完整短句sentences=[]foriinrange(0,len(parts)-1,2):ifparts[i]orparts[i+1]:# 避免空字符串sentences.append(parts[i]+parts[i+1])# 处理可能剩余的部分(如果字幕不以标点结尾)iflen(parts)%2==1andparts[-1].strip():sentences.append(parts[-1].strip())returnsentencesdefcreate_clip_draft(draft_name,image_paths,subtitle_texts,audio_paths,draft_folder_path,add_camera_movement=True):# 定义6种运镜效果的关键帧设置函数defadd_zoom_in(segment,duration):"""从远到近(放大)"""# 缩放关键帧segment.add_keyframe(KeyframeProperty.uniform_scale,0,1)segment.add_keyframe(KeyframeProperty.uniform_scale,duration,1.25)# 位置关键帧segment.add_keyframe(KeyframeProperty.position_x,0,0)segment.add_keyframe(KeyframeProperty.position_x,duration,0)segment.add_keyframe(KeyframeProperty.position_y,0,0)segment.add_keyframe(KeyframeProperty.position_y,duration,0)defadd_zoom_out(segment,duration):"""从近到远(缩小)"""# 缩放关键帧segment.add_keyframe(KeyframeProperty.uniform_scale,0,1.25)segment.add_keyframe(KeyframeProperty.uniform_scale,duration,1)# 位置关键帧segment.add_keyframe(KeyframeProperty.position_x,0,0)segment.add_keyframe(KeyframeProperty.position_x,duration,0)segment.add_keyframe(KeyframeProperty.position_y,0,0)segment.add_keyframe(KeyframeProperty.position_y,duration,0)defadd_move_up(segment,duration):"""从下到上"""# 缩放关键帧segment.add_keyframe(KeyframeProperty.uniform_scale,0,1.25)segment.add_keyframe(KeyframeProperty.uniform_scale,duration,1.25)# 位置关键帧segment.add_keyframe(KeyframeProperty.position_x,0,0)segment.add_keyframe(KeyframeProperty.position_x,duration,0)segment.add_keyframe(KeyframeProperty.position_y,0,-0.25)segment.add_keyframe(KeyframeProperty.position_y,duration,0.25)defadd_move_down(segment,duration):"""从上到下"""# 缩放关键帧segment.add_keyframe(KeyframeProperty.uniform_scale,0,1.25)segment.add_keyframe(KeyframeProperty.uniform_scale,duration,1.25)# 位置关键帧segment.add_keyframe(KeyframeProperty.position_x,0,0)segment.add_keyframe(KeyframeProperty.position_x,duration,0)segment.add_keyframe(KeyframeProperty.position_y,0,0.25)segment.add_keyframe(KeyframeProperty.position_y,duration,-0.25)defadd_move_left(segment,duration):"""从右到左"""# 缩放关键帧segment.add_keyframe(KeyframeProperty.uniform_scale,0,1.25)segment.add_keyframe(KeyframeProperty.uniform_scale,duration,1.25)# 位置关键帧segment.add_keyframe(KeyframeProperty.position_x,0,-0.25)segment.add_keyframe(KeyframeProperty.position_x,duration,0.25)segment.add_keyframe(KeyframeProperty.position_y,0,0)segment.add_keyframe(KeyframeProperty.position_y,duration,0)defadd_move_right(segment,duration):"""从左到右"""# 缩放关键帧segment.add_keyframe(KeyframeProperty.uniform_scale,0,1.25)segment.add_keyframe(KeyframeProperty.uniform_scale,duration,1.25)# 位置关键帧segment.add_keyframe(KeyframeProperty.position_x,0,0.25)segment.add_keyframe(KeyframeProperty.position_x,duration,-0.25)segment.add_keyframe(KeyframeProperty.position_y,0,0)segment.add_keyframe(KeyframeProperty.position_y,duration,0)# 运镜效果列表camera_effects=[add_zoom_in,add_zoom_out,add_move_up,add_move_down,add_move_left,add_move_right]# 检查列表是否为空ifnotimage_paths:raiseValueError("图片列表不能为空")# 检查列表长度是否一致iflen(image_paths)!=len(subtitle_texts)orlen(image_paths)!=len(audio_paths):raiseValueError("图片、字幕、音频列表长度不一致,无法创建草稿")# 检查路径存在性ifnotos.path.exists(draft_folder_path):raiseFileNotFoundError(f"剪映草稿文件夹不存在:{draft_folder_path}")missing_files=[]forimg_pathinimage_paths:ifnotos.path.exists(img_path):missing_files.append(f"图片:{img_path}")foraudio_pathinaudio_paths:ifnotos.path.exists(audio_path):missing_files.append(f"音频:{audio_path}")ifmissing_files:raiseFileNotFoundError(f"以下文件不存在:\n"+"\n".join(missing_files))# 获取第一张图片的尺寸try:withImage.open(image_paths[0])asimg:img_width,img_height=img.sizeexceptExceptionase:raiseRuntimeError(f"获取第一张图片尺寸失败:{str(e)}")# 判断横竖屏并设置参数ifimg_width>img_height:# 横屏draft_width=img_width draft_height=img_height font_size=6.0subtitle_y=-0.8else:# 竖屏draft_width=img_width draft_height=img_height font_size=13.0subtitle_y=-0.3# 初始化草稿文件夹管理器try:draft_folder=draft.DraftFolder(draft_folder_path)exceptFileNotFoundErrorase:raiseFileNotFoundError(f"草稿文件夹处理错误:{str(e)}")# 检查草稿是否已存在ifdraft_folder.has_draft(draft_name):raiseFileExistsError(f"草稿 '{draft_name}' 已存在,不允许覆盖")# 根据第一张图片尺寸创建草稿try:script=draft_folder.create_draft(draft_name,width=draft_width,height=draft_height,allow_replace=False)exceptExceptionase:raiseRuntimeError(f"创建草稿失败:{str(e)}")# 添加轨道(视频、音频、文本)script.add_track(TrackType.video,"主视频轨道")\.add_track(TrackType.audio,"音频轨道")\.add_track(TrackType.text,"字幕轨道")current_time=0# 单位:微秒(1秒 = 1e6微秒)separators=r'([,。!,!?;])'# 处理每一组素材foriinrange(len(image_paths)):img_path=image_paths[i]subtitle=subtitle_texts[i]audio_path=audio_paths[i]# 获取音频时长(微秒)try:audio_material=draft.AudioMaterial(audio_path)audio_duration=audio_material.durationexceptExceptionase:raiseRuntimeError(f"处理音频{audio_path}时出错:{str(e)}")# 计算当前片段的时间范围start_time=current_time end_time=current_time+audio_duration time_range=draft.trange(start_time,end_time-start_time)# 添加音频片段audio_segment=draft.AudioSegment(audio_path,time_range)script.add_segment(audio_segment,"音频轨道")# 添加图片片段image_segment=draft.VideoSegment(img_path,time_range)# 设置图片居中显示image_segment.clip_settings=ClipSettings(transform_x=0,transform_y=0,)# 添加关键帧确保图片保持比例缩放image_segment.add_keyframe(KeyframeProperty.uniform_scale,time_offset=0,value=1.0)# 如果需要添加运镜效果,随机选择一种效果应用ifadd_camera_movement:effect=random.choice(camera_effects)effect(image_segment,audio_duration)script.add_segment(image_segment,"主视频轨道")# 拆分字幕为短句sentences=split_subtitle(subtitle)total_length=len(subtitle)# 如果没有拆分出短句(无标点符号),使用原字幕ifnotsentences:sentences=[subtitle]# 计算每个短句的显示时间并添加current_sub_time=start_timeforsentenceinsentences:# 计算短句长度占比(避免除零错误)iftotal_length==0:ratio=1.0/len(sentences)else:ratio=len(sentence)/total_length# 计算当前短句的显示时长sentence_duration=int(audio_duration*ratio)# 确保至少有100ms的显示时间sentence_duration=max(sentence_duration,100000)# 100,000微秒 = 0.1秒# 计算当前短句的时间范围sentence_end_time=current_sub_time+sentence_duration sentence_time_range=draft.trange(current_sub_time,sentence_end_time-current_sub_time)# 添加字幕片段text_segment=draft.TextSegment(re.sub(separators,'',sentence),sentence_time_range,font=draft.FontType.文轩体,style=TextStyle(color=(0.0,0.0,0.0),# 黑色字体size=font_size,# 根据横竖屏设置字体大小align=1,# 居中对齐auto_wrapping=True,# 开启自动换行max_line_width=0.8,# 每行最大宽度为屏幕宽度的80%),background=TextBackground(color="#FFFF00",# 黄色背景alpha=0.8,# 背景透明度round_radius=0.1,# 背景圆角height=0.15,# 背景高度width=0.8# 背景宽度),clip_settings=ClipSettings(transform_y=subtitle_y# 根据横竖屏设置字幕Y轴位置))script.add_segment(text_segment,"字幕轨道")# 更新当前字幕时间current_sub_time=sentence_end_time# 更新当前时间current_time=end_time# 保存草稿try:script.save()exceptExceptionase:raiseRuntimeError(f"保存草稿失败:{str(e)}")print(f"剪映草稿{draft_name}创建成功!")# 使用示例(实际使用时请注释或删除)if__name__=="__main__":try:create_clip_draft(draft_name="示例草稿31",image_paths=[r"D:\Desktop\test_folder\jianying_materials_2\images\03.png",r"D:\Desktop\test_folder\jianying_materials_2\images\04.png",r"D:\Desktop\test_folder\jianying_materials_2\images\05.png"],subtitle_texts=["这可能是最常见的用法。当一个人发现自己喜欢的东西(比如一个机会、一件物品)对别人来说更重要","第二句字幕,wewe","第三句字幕,你好,喂喂喂"],audio_paths=[r"D:\Desktop\test_folder\jianying_materials_2\audios\01.mp3",r"D:\Desktop\test_folder\jianying_materials_2\audios\02.mp3",r"D:\Desktop\test_folder\jianying_materials_2\audios\03.mp3"],draft_folder_path=r"D:\download_software\JianyingPro Drafts",add_camera_movement=True# 控制是否添加运镜效果)exceptExceptionase:print(f"错误:{str(e)}")
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/15 11:24:03

ComfyUI-SeedVR2视频超分辨率技术全面指南

项目亮点速览 【免费下载链接】ComfyUI-SeedVR2_VideoUpscaler Non-Official SeedVR2 Vudeo Upscaler for ComfyUI 项目地址: https://gitcode.com/gh_mirrors/co/ComfyUI-SeedVR2_VideoUpscaler 🔥 核心优势:基于SeedVR2算法的专业级视频放大解决…

作者头像 李华
网站建设 2026/6/14 13:26:56

Qt关闭主窗体与quit()的深度解析

在Qt框架中,关闭主窗体(通过close()方法)和调用QApplication::quit()都是退出程序的方式,但它们在触发机制、资源管理、事件流程等方面存在显著差异。以下从技术实现和实际影响两个维度详细分析:1. 触发机制与事件循环…

作者头像 李华
网站建设 2026/6/15 12:20:40

Ubuntu进程终止全解析

在Ubuntu中,使用pkill -f 应用程序名终止应用程序的过程涉及信号传递、进程管理、资源回收等多个系统级操作。以下是详细的技术解析:1. 命令执行与信号发送pkill -f的工作原理pkill通过遍历系统进程列表(如/proc文件系统)&#xf…

作者头像 李华
网站建设 2026/6/15 1:42:57

5步掌握深空摄影堆栈神器:DeepSkyStacker让宇宙之美触手可及

想要拍摄出令人惊叹的深空星图却总是被噪点和模糊困扰?DeepSkyStacker这款专业的深空摄影堆栈工具能够帮你轻松解决这些问题。作为一款完全免费的开源软件,它通过智能的图像对齐和堆栈处理,让业余天文爱好者也能创作出专业级的宇宙影像。 【免…

作者头像 李华
网站建设 2026/6/15 13:32:04

17、RAC 环境下的应用开发技术解析

RAC 环境下的应用开发技术解析 在 RAC(Real Application Clusters)环境中进行应用开发,需要考虑诸多特定的开发概念和技术。本文将详细介绍 RAC 环境下应用开发的相关要点,包括实例与服务识别、多 SGA 应用、存储考虑、节点亲和性,以及一些高级编程技术,如透明应用故障转…

作者头像 李华
网站建设 2026/6/14 10:59:51

34、Python 数据持久化:简单与关系序列化方法详解

Python 数据持久化:简单与关系序列化方法详解 在 Python 编程中,数据持久化是一个重要的话题,它允许我们将数据保存到磁盘,以便后续使用。本文将介绍几种常见的数据持久化方法,包括简单序列化和关系序列化,并通过具体的代码示例进行详细说明。 简单序列化 简单序列化主…

作者头像 李华