当前位置: 首页 > news >正文

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)}")
http://www.jsqmd.com/news/84529/

相关文章:

  • 鸿蒙不是 Electron!深度解析 HarmonyOS 应用开发与跨端技术选型
  • Qt关闭主窗体与quit()的深度解析
  • 12bit 100MHz pipelined SAR ADC模数转换器 设计 65nm工艺,电...
  • LangChain从入门到进阶(7):学会让AI调用MCP「喂饭教程」
  • 一、在freertos上使用esp01s模块并配置使用sta模式进行数据通信传输测试。
  • 鸿蒙原生应用深度实战:用 ArkTS + Stage 模型开发高性能跨端音乐播放器
  • Qt主窗体关闭与quit()的退出机制差异
  • 16、深入了解 Oracle Clusterware:功能、安装与管理
  • Ubuntu下Qt/C++程序终止全攻略
  • C++ 后端面试必刷大厂算法题(附代码实现)第一期
  • 前期工作总结
  • ComfyUI-SeedVR2视频超分辨率技术全面指南
  • 智能零碳管理系统功能与实现
  • 智乃的数字【牛客tracker 每日一题】
  • [UUCTF 2022 新生赛]ezpop
  • 17、RAC 环境下的应用开发技术解析
  • 生成式AI重构内容创作生态:人机协同成核心竞争力
  • GitHub中文排行榜终极指南:新手快速发现优质开源项目的完整教程
  • qt为什么转向用cmake放弃qmake
  • 盛水最多的容器(滑动窗口 双指针)
  • MAUI跨平台云同步终极指南:轻松实现多设备数据无缝流动
  • color
  • Qwen3-Embedding-4B:重新定义多语言文本检索的边界
  • 详细介绍:MySQL 数据增删改查
  • NNG 开源项目教程
  • 深度探究Span:.NET内存布局与零拷贝原理及实践
  • 【鸿蒙开发案例篇】拒绝裸奔!鸿蒙6实现PDF动态加密
  • 24
  • NNG协议
  • helm 部署 elasticsearch 栈