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

使用Python实现播放“.gif”文件增强版

使用Python实现播放“.gif”文件增强版

使用Python和第三方库Pillow实现实现播放gif文件,以前介绍过一个简单实现https://blog.csdn.net/cnds123/article/details/137992560 ,那个功能比较简单,实用意义不大。现在介绍一个增强版的。

关于“.gif”文件

GIF(Graphics Interchange Format,图形交换格式)是一种由CompuServe公司开发的图像格式,通过连续帧实现动画效果,文件体积小且画面连贯‌ 。GIF本质是静态图片的无损压缩格式,虽支持动画效果,但缺乏音频流且色彩深度有限(仅8位)。

下面介绍用Python实现的控制播放器,用户可细致的控制,包括:打开、播放、暂停、停止,设置播放速度,逐帧控制——前一帧、后一帧。

界面截图:

打开:停止当前播放,加载新GIF文件。

播放:启动动画循环。

暂停:停止动画循环。

停止:暂停播放并重置到第一帧。

前一帧:允许用户逐步后退到前一帧,自动暂停播放。

后一帧:允许用户逐步前进到后一帧,自动暂停播放。

循环处理,当到达第一帧时后退会跳转到最后一帧,反之亦然。

滑动条控制:添加了速度滑动条,允许用户在10ms到500ms之间调整帧延迟。

使用GIF原始速度:可以自动设置GIF的原始平均延迟时间。

状态栏:显示播放中还是暂停状态,当前设置的延迟时间,显示当前帧位置和总帧数(例如:"帧 5/24"),当前设置的帧延迟时间。

这个GIF播放器基于以下三个核心库构建:

    Tkinter - Python的标准GUI库,用于创建窗口、按钮等界面元素。

    PIL/Pillow - Python图像处理库,用于读取和处理GIF文件。

    tkinter.filedialog - 文件选择对话框,用于选择GIF文件。

确保已安装所需的库pillow,关于pillow简要介绍和安装可见https://blog.csdn.net/cnds123/article/details/137992560

源码如下:

import tkinter as tk
from tkinter import filedialog, ttk
from PIL import Image, ImageTkclass GifPlayer:def __init__(self, master):self.master = masterself.master.title("GIF Player")self.master.geometry("500x550")  # 增加高度以容纳新控件 ☆#self.master.minsize(400, 450)# 初始化变量self.frames = []  # 存储GIF的所有帧self.current_frame = 0  # 当前帧索引self.is_playing = False  # 播放状态self.gif_image = None  # PIL Image对象self.frame_delay = 100  # 默认帧延迟(毫秒)self.original_delays = []  # 存储原始GIF帧延迟# 创建主框架,用于管理布局main_frame = tk.Frame(self.master)main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)# 创建显示GIF的标签self.label = tk.Label(main_frame, text="请打开一个GIF文件", bg="white", relief=tk.SUNKEN, bd=1)self.label.pack(fill=tk.BOTH, expand=True)# 创建状态显示标签self.status_label = tk.Label(main_frame, text="状态: 未加载", relief=tk.SUNKEN, bd=1)self.status_label.pack(fill=tk.X, pady=(5, 0))# 创建控制面板框架control_frame = tk.Frame(main_frame)control_frame.pack(side=tk.BOTTOM, fill=tk.X, pady=10)# 基本控制部分basic_control_frame = tk.Frame(control_frame)basic_control_frame.pack(fill=tk.X, pady=5)# 打开按钮self.open_button = tk.Button(basic_control_frame, text="打开", command=self.open_gif)self.open_button.pack(side=tk.LEFT, padx=5)# 播放按钮self.play_button = tk.Button(basic_control_frame, text="播放", command=self.play_gif)self.play_button.pack(side=tk.LEFT, padx=5)# 暂停按钮self.pause_button = tk.Button(basic_control_frame, text="暂停", command=self.pause_gif)self.pause_button.pack(side=tk.LEFT, padx=5)# 停止按钮self.stop_button = tk.Button(basic_control_frame, text="停止", command=self.stop_gif)self.stop_button.pack(side=tk.LEFT, padx=5)       # 前一帧按钮self.prev_frame_button = tk.Button(basic_control_frame, text="前一帧", command=self.prev_frame)self.prev_frame_button.pack(side=tk.LEFT, padx=5)# 后一帧按钮self.next_frame_button = tk.Button(basic_control_frame, text="后一帧", command=self.next_frame)self.next_frame_button.pack(side=tk.LEFT, padx=5)# 速度控制部分speed_control_frame = tk.Frame(control_frame)speed_control_frame.pack(fill=tk.X, pady=5)# 速度标签tk.Label(speed_control_frame, text="速度:").pack(side=tk.LEFT, padx=5)# 速度滑动条self.speed_scale = tk.Scale(speed_control_frame, from_=10, to=500, orient=tk.HORIZONTAL,showvalue=False,  # 不显示默认数值False, 否者用 True            command=self.set_speed)self.speed_scale.set(self.frame_delay)  # 设置初始值self.speed_scale.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5)# 使用原始延迟按钮self.use_original_delay_button = tk.Button(speed_control_frame, text="使用GIF原始速度", command=self.use_original_delay)self.use_original_delay_button.pack(side=tk.LEFT, padx=5)# 初始化按钮状态self.update_button_state()def open_gif(self):"""打开文件对话框选择GIF文件并加载"""# 打开文件对话框,只显示GIF文件file_path = filedialog.askopenfilename(title="选择GIF文件",filetypes=[("GIF文件", "*.gif"), ("所有文件", "*.*")])# 如果用户选择了文件if file_path:# 停止当前播放self.stop_gif()try:# 打开新的GIF文件self.gif_image = Image.open(file_path)# 获取屏幕尺寸,用于限制GIF显示大小screen_width = self.master.winfo_screenwidth()screen_height = self.master.winfo_screenheight()# 设置最大显示尺寸(留出空间给窗口边框和按钮)max_width = int(screen_width * 0.7)max_height = int(screen_height * 0.7)   # ☆# 提取所有帧和原始延迟self.frames = []self.original_delays = []try:for frame in range(self.gif_image.n_frames):self.gif_image.seek(frame)  # 定位到指定帧# 获取帧延迟时间(毫秒)delay = self.gif_image.info.get('duration', 100)self.original_delays.append(delay)frame_image = self.gif_image.copy().convert("RGBA")  # 复制并转换帧# 如果GIF尺寸过大,则进行缩放if frame_image.width > max_width or frame_image.height > max_height:# 计算缩放比例,保持宽高比ratio = min(max_width / frame_image.width, max_height / frame_image.height)new_width = int(frame_image.width * ratio)new_height = int(frame_image.height * ratio)frame_image = frame_image.resize((new_width, new_height), Image.Resampling.LANCZOS)photo = ImageTk.PhotoImage(frame_image)  # 转换为Tkinter可用的格式self.frames.append(photo)except EOFError:pass  # 处理帧读取完毕的情况# 重置当前帧索引self.current_frame = 0# 显示第一帧if self.frames:self.label.config(image=self.frames[0], text="")# 调整窗口大小以适应GIF,但不超过最大尺寸img_width = self.frames[0].width()img_height = self.frames[0].height()# 设置窗口大小,考虑按钮区域window_width = min(img_width + 50, max_width)window_height = min(img_height + 150, max_height)  # 增加高度以容纳新控件 ☆self.master.geometry(f"{window_width}x{window_height}")# 更新窗口标题显示文件名self.master.title(f"GIF Player - {file_path.split('/')[-1]}")# 更新状态显示self.update_status()# 更新按钮状态self.update_button_state()except Exception as e:# 如果加载失败,显示错误信息self.label.config(image="", text=f"无法加载GIF文件:\n{str(e)}")self.frames = []self.update_button_state()self.status_label.config(text="状态: 加载失败")def update_button_state(self):"""根据当前状态更新按钮的可用性"""has_frames = len(self.frames) > 0# 只有在有帧的情况下,播放、暂停和停止按钮才可用self.play_button.config(state=tk.NORMAL if has_frames else tk.DISABLED)self.pause_button.config(state=tk.NORMAL if has_frames else tk.DISABLED)self.stop_button.config(state=tk.NORMAL if has_frames else tk.DISABLED)self.prev_frame_button.config(state=tk.NORMAL if has_frames else tk.DISABLED)self.next_frame_button.config(state=tk.NORMAL if has_frames else tk.DISABLED)self.speed_scale.config(state=tk.NORMAL if has_frames else tk.DISABLED)self.use_original_delay_button.config(state=tk.NORMAL if has_frames else tk.DISABLED)def update_status(self):"""更新状态显示"""if self.frames:status = f"状态: 帧 {self.current_frame+1}/{len(self.frames)}"if self.is_playing:status += " - 播放中"else:status += " - 暂停"status += f" - 延迟: {self.frame_delay}ms"self.status_label.config(text=status)else:self.status_label.config(text="状态: 未加载")def set_speed(self, value):"""设置播放速度"""self.frame_delay = int(value)self.update_status()def use_original_delay(self):"""使用GIF的原始延迟时间"""if self.frames and self.original_delays:# 计算平均延迟avg_delay = sum(self.original_delays) // len(self.original_delays)self.frame_delay = avg_delayself.speed_scale.set(avg_delay)self.update_status()def play_gif(self):"""开始播放GIF动画"""if not self.is_playing and self.frames:self.is_playing = Trueself.update_status()self.play_next_frame()  # 开始播放循环def pause_gif(self):"""暂停播放GIF动画"""self.is_playing = Falseself.update_status()def stop_gif(self):"""停止播放GIF动画并回到第一帧"""self.is_playing = Falseif self.frames:self.current_frame = 0self.label.config(image=self.frames[self.current_frame])self.update_status()def prev_frame(self):"""显示前一帧"""if self.frames:self.is_playing = Falseself.current_frame = (self.current_frame - 1) % len(self.frames)self.label.config(image=self.frames[self.current_frame])self.update_status()def next_frame(self):"""显示后一帧"""if self.frames:self.is_playing = Falseself.current_frame = (self.current_frame + 1) % len(self.frames)self.label.config(image=self.frames[self.current_frame])self.update_status()def play_next_frame(self):"""播放下一帧并设置定时器播放后续帧"""if self.is_playing and self.frames:# 显示当前帧self.label.config(image=self.frames[self.current_frame])# 更新到下一帧(循环播放)self.current_frame = (self.current_frame + 1) % len(self.frames)# 更新状态显示self.update_status()# 设置定时器,使用当前延迟时间播放下一帧self.master.after(self.frame_delay, self.play_next_frame)if __name__ == "__main__":# 创建主窗口并启动GIF播放器root = tk.Tk()player = GifPlayer(root)root.mainloop()

http://www.dtcms.com/a/537091.html

相关文章:

  • 论述网站建设的具体步骤有哪些网站管理与建设教程
  • OpenAI首款AI浏览器Atlas上线仅一周即被恶意提示词攻破
  • Dompdf库html生成pdf时editor编辑器中文本长度被截断不会自动换行问题处理
  • 广西网站建设价格低qq炫舞做字网站
  • VMD分解+核主成分降维+物理信息神经网络!VMD-KPCA-PINN多变量时序光伏功率预测,MATLAB代码
  • 利用论坛推广网站工程公司税率是多少
  • 个人微信接口开发,个微API
  • 深圳做网站排名哪家专业六盘水市诚信网站建设公司
  • 在哪找做调查赚钱的网站网站建设全攻略
  • 使用亮数据爬虫API零门槛快速爬取Tiktok数据
  • 网站建设 团队介绍网站建设电商学堂
  • Android Studio新手开发第三十三天
  • 九牛科技网站开发微信营销做电影网站侵权
  • 基于dcmtk的dicom工具 第十章 读取dicom文件图像数据并显示
  • wordpress站点浏览网站建设和网站优化的区别
  • 天锐绿盾防泄密系统注册机,支持2025年V7.51版本注册
  • c语言实现队列【由浅入深-数据结构】
  • Flink ExecutionConfig 实战并行度、序列化、对象重用与全局参数
  • 家政类网站开发成本wordpress 音乐不中断
  • STM32-SPI协议
  • 西安网站开发php网站插件
  • LinearRAG—重新定义GraphRAG:无需关系抽取的线性图构建新范式 -香港理工
  • 第4章-程序计数器
  • HashMap 与 HashSet
  • 怎么在虚拟主机上建网站wordpress rest图片
  • 小米手机之间数据转移的6种方法
  • 前端开发中的表格标签
  • PaddleOCR-VL本地部署流程
  • 2.2 复合类型
  • 做网站图片自动切换宁波软件开发