使用Python制作GIF动图并打包为exe可执行程序

 更新时间:2025年07月03日 10:56:57   作者:XMYX-0  
在工作或个人项目中,常常会遇到需要将多张图片合成GIF动图的需求,同时添加版权水印保护作品,本文分享一个使用Python和Pillow库实现的GIF生成工具,配备简单的Tkinter图形界面,无论你是Python初学者,还是想快速做一个实用小工具,本文都会帮你搞定

使用 Python 制作 GIF 动图,并打包为 EXE 可执行程序(含图形界面)

在工作或个人项目中,常常会遇到需要将多张图片合成 GIF 动图的需求,同时添加版权水印保护作品。本文分享一个使用 Python 和 Pillow 库实现的 GIF 生成工具,配备简单的 Tkinter 图形界面,支持:

  • 批量上传图片,合成 GIF 动图
  • 固定文字水印自动添加
  • 可选图片水印(Logo)叠加
  • 一键生成,操作简单
  • 使用 PyInstaller 打包为 Windows 独立 EXE

无论你是 Python 初学者,还是想快速做一个实用小工具,这篇文章都会帮你搞定。

环境准备

Python 3.6+

Pillow:图像处理库,安装命令:

pip install pillow
  • Tkinter:Python 内置图形界面库(Windows 下默认包含)
  • PyInstaller:后续将介绍如何打包

功能预览

功能说明
多图片上传支持多选 PNG/JPG/JPEG/BMP 等常见格式
GIF 动画生成支持循环播放,帧间隔可自定义
简洁图形界面按钮操作:选择图片、生成 GIF
一键生成直接点击按钮即可生成
EXE 打包使用 PyInstaller 一键打包,免 Python 环境

完整代码(图形界面 + 功能)

gif_creator.py

import tkinter as tk
from tkinter import filedialog, messagebox, ttk
from PIL import Image, ImageTk
import os
import threading
import webbrowser

class GifMakerApp:
    def __init__(self, root):
        self.root = root
        self.root.title("GIF 动图生成器")
        self.image_paths = []

        self.build_ui()

    def build_ui(self):
        # 图片列表框
        self.listbox = tk.Listbox(self.root, selectmode=tk.SINGLE, width=50, height=8)
        self.listbox.grid(row=0, column=0, columnspan=3, padx=10, pady=5)

        # 上移/下移按钮
        tk.Button(self.root, text="↑ 上移", command=self.move_up).grid(row=1, column=0, sticky="ew", padx=10)
        tk.Button(self.root, text="↓ 下移", command=self.move_down).grid(row=1, column=1, sticky="ew", padx=10)

        # 选择图片
        tk.Button(self.root, text="选择图片", command=self.select_images).grid(row=2, column=0, columnspan=2, pady=5)

        # 帧间隔时间
        tk.Label(self.root, text="帧间隔 (ms):").grid(row=3, column=0, sticky="e")
        self.duration_var = tk.IntVar(value=1000)
        tk.Entry(self.root, textvariable=self.duration_var, width=8).grid(row=3, column=1, sticky="w")

        # 选择保存路径
        tk.Button(self.root, text="保存路径", command=self.choose_output_path).grid(row=4, column=0, pady=5)
        self.output_path_var = tk.StringVar(value="output.gif")
        tk.Entry(self.root, textvariable=self.output_path_var, width=30).grid(row=4, column=1)

        # 进度条
        self.progress = ttk.Progressbar(self.root, orient="horizontal", length=300, mode="determinate")
        self.progress.grid(row=5, column=0, columnspan=3, pady=5)

        # 生成按钮
        tk.Button(self.root, text="生成 GIF", command=self.generate_gif_thread).grid(row=6, column=0, columnspan=3, pady=10)

    def select_images(self):
        file_paths = filedialog.askopenfilenames(
            title="选择多张图片",
            filetypes=[("图片文件", "*.png *.jpg *.jpeg *.bmp")]
        )
        if file_paths:
            self.image_paths = list(file_paths)
            self.refresh_listbox()

    def refresh_listbox(self):
        self.listbox.delete(0, tk.END)
        for path in self.image_paths:
            self.listbox.insert(tk.END, os.path.basename(path))

    def move_up(self):
        index = self.listbox.curselection()
        if not index or index[0] == 0:
            return
        idx = index[0]
        self.image_paths[idx-1], self.image_paths[idx] = self.image_paths[idx], self.image_paths[idx-1]
        self.refresh_listbox()
        self.listbox.select_set(idx-1)

    def move_down(self):
        index = self.listbox.curselection()
        if not index or index[0] == len(self.image_paths) - 1:
            return
        idx = index[0]
        self.image_paths[idx+1], self.image_paths[idx] = self.image_paths[idx], self.image_paths[idx+1]
        self.refresh_listbox()
        self.listbox.select_set(idx+1)

    def choose_output_path(self):
        path = filedialog.asksaveasfilename(
            defaultextension=".gif",
            filetypes=[("GIF 文件", "*.gif")],
            title="选择 GIF 保存路径"
        )
        if path:
            self.output_path_var.set(path)

    def generate_gif_thread(self):
        t = threading.Thread(target=self.generate_gif)
        t.start()

    def generate_gif(self):
        if not self.image_paths:
            messagebox.showwarning("未选择图片", "请先选择图片!")
            return

        try:
            duration = int(self.duration_var.get())
        except ValueError:
            messagebox.showerror("无效间隔", "请输入合法的帧间隔(整数)")
            return

        output_path = self.output_path_var.get().strip()
        if not output_path:
            messagebox.showerror("路径错误", "请输入有效的保存路径")
            return

        try:
            frames = []
            self.progress["maximum"] = len(self.image_paths)
            self.progress["value"] = 0

            from PIL import ImageFont, ImageDraw

            # ...在循环中每次读取图片时
            for idx, path in enumerate(self.image_paths):
                img = Image.open(path).convert("RGBA")

                if idx == 0:
                    w, h = img.size
                else:
                    img = img.resize((w, h))

                # 添加水印
                draw = ImageDraw.Draw(img)
                text = "@ CSDN博主XMYX-0"
                font_size = 50


                try:
                    # Windows 通用字体路径(可自定义)
                    # font = ImageFont.truetype("arial.ttf", font_size)
                    font = ImageFont.truetype("C:/Windows/Fonts/simhei.ttf", font_size)
                except:
                    font = ImageFont.load_default()

                bbox = draw.textbbox((0, 0), text, font=font)
                text_width = bbox[2] - bbox[0]
                text_height = bbox[3] - bbox[1]

                position = (w - text_width - 10, h - text_height - 10)  # 右下角

                draw.text(position, text, font=font, fill=(255, 0, 0, 128))  # 半透明红色水印

                frames.append(img)
                self.progress["value"] += 1
                self.root.update_idletasks()

            frames[0].save(
                output_path,
                save_all=True,
                append_images=frames[1:],
                duration=duration,
                loop=0
            )

            messagebox.showinfo("成功", f"GIF 已生成:\n{output_path}")
            webbrowser.open(output_path)

        except Exception as e:
            messagebox.showerror("错误", f"生成失败:\n{str(e)}")

if __name__ == "__main__":
    root = tk.Tk()
    app = GifMakerApp(root)
    root.mainloop()

如何打包成 Windows 可执行程序(.exe)

我们可以使用 PyInstaller 进行打包:

安装命令

pip install pyinstaller

打包命令

pyinstaller --noconsole --onefile --icon=app.ico gif_creator.py
参数说明
--noconsole不显示黑色终端窗口(适用于 GUI 程序)
--onefile打包为一个独立 .exe 文件
--icon=app.ico自定义图标(可选)

生成后可在 dist/ 目录找到 gif_creator.exe,可直接发送给他人使用,无需安装 Python。

小贴士与拓展建议

  • 字体问题:如果打包后字体显示异常,建议把字体文件放到项目里,使用绝对路径加载。
  • 水印透明度:可在代码中调整 (255, 0, 0, 128) 中最后的 128 控制透明度,范围 0~255。
  • 图片大小限制:上传图片尺寸过大时,合成 GIF 文件会很大,建议做图片缩放。
  • 帧间隔调整duration=1000 单位为毫秒,可根据需求调整动画速度。

总结

本项目展示了如何使用 Python 构建一个实用的 GIF 动图生成工具,并加入水印功能,最终打包成 Windows 可执行文件,真正做到“一键使用、无需安装”。

以上就是使用Python制作GIF动图并打包为exe可执行程序的详细内容,更多关于Python制作GIF并打包为exe的资料请关注脚本之家其它相关文章!

相关文章

  • Python装饰器原理与基本用法分析

    Python装饰器原理与基本用法分析

    这篇文章主要介绍了Python装饰器原理与基本用法,结合实例形式分析了Python装饰器的基本功能、原理、用法与操作注意事项,需要的朋友可以参考下
    2020-01-01
  • 在Python中实现shuffle给列表洗牌

    在Python中实现shuffle给列表洗牌

    今天小编就为大家分享一篇在Python中实现shuffle给列表洗牌,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-11-11
  • Python爬虫信息输入及页面的切换方法

    Python爬虫信息输入及页面的切换方法

    今天小编就为大家分享一篇Python爬虫信息输入及页面的切换方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-05-05
  • 安装Keras,tensorflow,并实现将虚拟环境添加到jupyter notebook

    安装Keras,tensorflow,并实现将虚拟环境添加到jupyter notebook

    这篇文章主要介绍了安装Keras,tensorflow,并实现将虚拟环境添加到jupyter notebook,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-03-03
  • python中实现指定时间调用函数示例代码

    python中实现指定时间调用函数示例代码

    函数function是python编程核心内容之一,也是比较重要的一块。下面这篇文章主要给大家介绍了关于python中实现指定时间调用函数的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-09-09
  • python 实现 redis 数据库的操作

    python 实现 redis 数据库的操作

    这篇文章主要介绍了python 包 redis 数据库的操作教程,redis 是一个 Key-Value 数据库,下文基于python的相关资料展开对redis 数据库操作的详细介绍,需要的小伙伴可以参考一下
    2022-04-04
  • matlab中imadjust函数的作用及应用举例

    matlab中imadjust函数的作用及应用举例

    这篇文章主要介绍了matlab中imadjust函数的作用及应用举例,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-02-02
  • Python使用matplotlib模块绘制图像并设置标题与坐标轴等信息示例

    Python使用matplotlib模块绘制图像并设置标题与坐标轴等信息示例

    这篇文章主要介绍了Python使用matplotlib模块绘制图像并设置标题与坐标轴等信息,结合实例形式分析了Python中matplotlib模块进行坐标系图形绘制的相关操作技巧,需要的朋友可以参考下
    2018-05-05
  • python装饰器decorator介绍

    python装饰器decorator介绍

    这篇文章主要介绍了python装饰器decorator介绍,decorator设计模式允许动态地对现有的对象或函数包装以至于修改现有的职责和行为,简单地讲用来动态地扩展现有的功能,需要的朋友可以参考下
    2014-11-11
  • 使用Python给头像戴上圣诞帽的图像操作过程解析

    使用Python给头像戴上圣诞帽的图像操作过程解析

    这篇文章主要介绍了使用Python给头像戴上圣诞帽的过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-09-09

最新评论