import gradio as gr from PIL import Image import os import tempfile from typing import List def create_gif( image_files: List[str], # 修改为直接接收文件路径列表 scale: float = 1.0, frame_duration: int = 200, loop: bool = True ) -> tuple: """ 将多张图片合并为GIF动画 参数: image_files: 图片文件路径列表 scale: 缩放比例(0.1-2.0) frame_duration: 每帧持续时间(毫秒) loop: 是否循环播放 返回: (输出路径, 错误信息) """ try: # 验证输入 if not image_files: return None, "错误: 请至少选择一张图片*(Wrong, At least choose one image)" images = [] for file_info in image_files: path = file_info if isinstance(file_info, str) else file_info.name # 处理两种输入方式 if not os.path.exists(path): return None, f"错误: 文件不存在 - {path}" valid_ext = ('.jpg', '.jpeg', '.png', '.webp') if not path.lower().endswith(valid_ext): return None, f"错误: 不支持的文件格式 - {path}" img = Image.open(path) if scale != 1.0: new_size = (int(img.width * scale), int(img.height * scale)) img = img.resize(new_size, Image.LANCZOS) images.append(img) # 设置输出路径 output_dir = tempfile.gettempdir() output_path = os.path.join(output_dir, "output.gif") # 保存为GIF images[0].save( output_path, save_all=True, append_images=images[1:], duration=frame_duration, loop=0 if loop else 1, optimize=True ) return output_path, "GIF创建成功!(GIF already here)" except Exception as e: return None, f"错误: {str(e)}" # Gradio界面 with gr.Blocks(title="多图转GIF转换器(image2Gif)") as demo: gr.Markdown("## 🎞️ 多图转GIF转换器I2GIF") gr.Markdown("上传多张图片,设置参数后生成GIF动画格式图片,需要统一大小(upload your images to make GIF)") with gr.Row(): with gr.Column(): file_input = gr.Files( label="选择多张图片(choose images in same size)", file_types=["image"], file_count="multiple" ) with gr.Accordion("高级选项(Advanced)", open=False): scale_slider = gr.Slider(0.1, 2.0, value=1.0, step=0.1, label="缩放比例(scale)") duration_slider = gr.Slider(50, 2000, value=200, step=50, label="每帧时长(毫秒)(ms per frame)") loop_checkbox = gr.Checkbox(value=True, label="循环播放(loop)") convert_btn = gr.Button("生成GIF(Merge GIF)", variant="primary") with gr.Column(): output_gif = gr.Image(label="生成的GIF", interactive=False) output_download = gr.File(label="下载GIF", visible=False) output_message = gr.Textbox(label="状态信息", interactive=False) # 处理转换 def process_files( files: List, # 修改为普通List类型 scale: float, duration: int, loop: bool ) -> tuple: if not files: return None, None, "请先上传图片*(Please upload your images first)" output_path, msg = create_gif(files, scale=scale, frame_duration=duration, loop=loop) if output_path: return output_path, output_path, msg else: return None, None, msg convert_btn.click( process_files, inputs=[file_input, scale_slider, duration_slider, loop_checkbox], outputs=[output_gif, output_download, output_message] ) # 启动应用 if __name__ == "__main__": demo.launch()