“GifSpliter” GIF分割器
用PyQt5重写了一个“GIF分割器”的小应用:

功能:
- 主要就是为了能快速分解GIF文件,将所有帧保存成PNG格式。
- 支持文件拖拽进窗口,也是唯一的文件输入方式,就是简单暴力,直接方便,xD。
- 可选择的输出位置:可以指定位置,也可以在原文件所在位置给你输出分割帧。
- 可以拖拽文件夹输入,只要你文件夹里有gif,都给你处理了。
- 支持混合输入模式。可以同时选中多个gif,或者gif+文件夹的多个文件输入。
现成的软件 GifSpliter_v3.2:
链接:https://pan.baidu.com/s/1JJLOF1vDYpd7pRzrtr93Xg?pwd=ucuo
提取码:ucuo
–来自百度网盘超级会员V6的分享
为什么做这个?
COMSOL仿真导出GIF图很方便,但是想要导出不同时刻参数下的多个图像很不方便。那……不如直接导出GIF后再分割?
但是网上没有这种轻量级的,简单暴力,合我需求的应用,那直接自己撸一个小工具!
现在,直接选中文件拖进去,等几秒就好了,多好?
Update History
v3.2 231031
- 丰富了控制台打印信息,增加了彩色的控制台输出,并添加了处理进度条;

v3.1 230831
保留了控制台窗口,并优化了控制台输出,现在可以通过控制台输出信息查看处理
情况
v3.0 230631
- PyQt5设计了全新的窗口;
- 增加了文件夹模式;
- 增加了多种输出模式的选择;
v2.0
- 增加了多文件处理模式。
v1.0
- Tinkter界面,单gif文件的处理方式,默认输出到exe所在文件夹。
SourceCode
import sys
import os
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from ui_GifSpliter import *
from spliter import GifSplitter
import res_rc
class MyGifSpliter(QWidget):
def __init__(self, parent=None):
super().__init__(parent) # 调用父类构造函数
self.__ui = Ui_GifSpliter()
self.__ui.setupUi(self)
self.appDir = sys.path[0]
print(self.appDir)
self.gifDir = self.appDir
self.gifDir = self.appDir
self.specDir = self.appDir
self.outDir = self.appDir
self.__ui.textEdit_DirSpec.setText(self.appDir)
# 调用Drops方法
# self.drawn()
self.__ui.radioButton_DirSpec.clicked.connect(self.do_setSpecDir)
# 鼠标拖入事件
def dragEnterEvent(self, event):
if event.mimeData().hasUrls:
event.accept()
else:
event.ignore()
# 鼠标放开执行
def dropEvent(self, event):
"""获取拖拽文件的路径"""
files = []
for url in event.mimeData().urls():
path = url.toLocalFile()
files.append(path)
# 打印拖住进入窗口的文件路径
self.gifDir = os.path.split(files[0])[0]
# print(f'拖拽文件路径为:"{self.gifDir}"')
# 判断输出模式
if self.__ui.radioButton_DirGif.isEnabled():
self.outDir = self.gifDir + '/分割后PNG'
if not os.path.exists(self.outDir):
os.mkdir(self.outDir)
elif self.__ui.radioButton_DirApp.isEnabled():
self.outDir = self.appDir
elif self.__ui.radioButton_DirSpec.isEnabled():
self.outDir = self.specDir
# print(f'输出文件夹为:"{self.outDir}"')
# 处理获取的文件
for file in files:
# 文件夹
if os.path.isdir(file):
# print(f'{file}是文件夹')
self.gifDir = file
self.outDir = self.gifDir + '/分割后PNG'
if not os.path.exists(self.outDir):
os.mkdir(self.outDir)
GifSplitter.split_gifs_in_folder(file, save_folder=self.outDir)
print(f'\033[92m完成对文件夹:"{file}"的处理~~~\033[0m')
# 文件
else:
# 判断扩展名是否为.gif
if file.lower().endswith('.gif'):
# print(f'{file}是gif文件')
GifSplitter(file).export_frames(save_folder=self.outDir)
else:
print(f'\033[91m! "{os.path.basename(file)}" 不是GIF文件~~~!\033[0m')
if self.__ui.checkBox_openDirSpec.isChecked():
os.startfile(self.outDir)
#设定背景图片
# def drawn(self):
# self.__ui.palette = QPalette()
# self.__ui.palette.setBrush(QPalette.Background, QBrush(QPixmap("BackGround1.png")))
# self.setPalette(self.__ui.palette)
# 根据radioButton设定文件路径
def do_setSpecDir(self):
if self.__ui.radioButton_DirSpec.isChecked():
self.specDir = QFileDialog.getExistingDirectory(None,"选取PNG输出文件夹","")
self.__ui.textEdit_DirSpec.setText(self.specDir)
print(f'设定指定输出路径为:{self.specDir}')
if __name__ == "__main__":
app = QApplication(sys.argv)
e = MyGifSpliter()
e.show()
sys.exit(app.exec_())
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui_GifSpliter.ui'
#
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_GifSpliter(object):
def setupUi(self, GifSpliter):
GifSpliter.setObjectName("GifSpliter")
GifSpliter.resize(640, 480)
GifSpliter.setMinimumSize(QtCore.QSize(640, 480))
GifSpliter.setMaximumSize(QtCore.QSize(640, 480))
font = QtGui.QFont()
font.setFamily("微软雅黑")
font.setPointSize(11)
font.setBold(True)
font.setUnderline(False)
font.setWeight(75)
GifSpliter.setFont(font)
GifSpliter.setAcceptDrops(True)
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(":/icon/C cyn.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
GifSpliter.setWindowIcon(icon)
GifSpliter.setStyleSheet("")
self.verticalLayout_2 = QtWidgets.QVBoxLayout(GifSpliter)
self.verticalLayout_2.setSizeConstraint(QtWidgets.QLayout.SetMinimumSize)
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.label = QtWidgets.QLabel(GifSpliter)
self.label.setMinimumSize(QtCore.QSize(0, 0))
font = QtGui.QFont()
font.setFamily("微软雅黑")
font.setBold(False)
font.setWeight(50)
self.label.setFont(font)
self.label.setAcceptDrops(True)
self.label.setFrameShape(QtWidgets.QFrame.NoFrame)
self.label.setFrameShadow(QtWidgets.QFrame.Plain)
self.label.setLineWidth(1)
self.label.setTextFormat(QtCore.Qt.AutoText)
self.label.setAlignment(QtCore.Qt.AlignCenter)
self.label.setOpenExternalLinks(True)
self.label.setObjectName("label")
self.verticalLayout_2.addWidget(self.label)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setSizeConstraint(QtWidgets.QLayout.SetMinimumSize)
self.horizontalLayout.setObjectName("horizontalLayout")
self.radioButton_DirGif = QtWidgets.QRadioButton(GifSpliter)
self.radioButton_DirGif.setChecked(True)
self.radioButton_DirGif.setObjectName("radioButton_DirGif")
self.horizontalLayout.addWidget(self.radioButton_DirGif)
self.radioButton_DirSpec = QtWidgets.QRadioButton(GifSpliter)
self.radioButton_DirSpec.setChecked(False)
self.radioButton_DirSpec.setObjectName("radioButton_DirSpec")
self.horizontalLayout.addWidget(self.radioButton_DirSpec)
self.radioButton_DirApp = QtWidgets.QRadioButton(GifSpliter)
self.radioButton_DirApp.setChecked(False)
self.radioButton_DirApp.setObjectName("radioButton_DirApp")
self.horizontalLayout.addWidget(self.radioButton_DirApp)
self.verticalLayout_2.addLayout(self.horizontalLayout)
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setSizeConstraint(QtWidgets.QLayout.SetMinimumSize)
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.label_2 = QtWidgets.QLabel(GifSpliter)
self.label_2.setObjectName("label_2")
self.horizontalLayout_2.addWidget(self.label_2)
self.textEdit_DirSpec = QtWidgets.QTextEdit(GifSpliter)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Ignored)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.textEdit_DirSpec.sizePolicy().hasHeightForWidth())
self.textEdit_DirSpec.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setPointSize(9)
font.setBold(False)
font.setWeight(50)
self.textEdit_DirSpec.setFont(font)
self.textEdit_DirSpec.setObjectName("textEdit_DirSpec")
self.horizontalLayout_2.addWidget(self.textEdit_DirSpec)
self.checkBox_openDirSpec = QtWidgets.QCheckBox(GifSpliter)
self.checkBox_openDirSpec.setObjectName("checkBox_openDirSpec")
self.horizontalLayout_2.addWidget(self.checkBox_openDirSpec)
self.verticalLayout_2.addLayout(self.horizontalLayout_2)
self.verticalLayout_2.setStretch(0, 1)
self.retranslateUi(GifSpliter)
QtCore.QMetaObject.connectSlotsByName(GifSpliter)
def retranslateUi(self, GifSpliter):
_translate = QtCore.QCoreApplication.translate
GifSpliter.setWindowTitle(_translate("GifSpliter", "GIF文件分割器 v3.0"))
self.label.setText(_translate("GifSpliter", "<html><head/><body><p align=\"center\">GIF文件分割器: 可以快速将GIF文件分割成逐帧PNG文件</p><p align=\"center\">-------------------------------------------------------------</p><p align=\"center\">使用方法:</p><p align=\"center\">将GIF文件或含有多个GIF的文件夹拖拽进此窗口即可</p><p align=\"center\">程序会自动分解所有拖拽进来的GIF并分解成单张PNG文件</p><p align=\"center\">可以在下面单选按钮中选择PNG文件输出位置</p><p align=\"center\">如果需要选择生成到特定文件夹,需要指定输出文件夹</p><p align=\"center\"><br/>-------------------------------------------------------------</p><p align=\"center\"><a href=\"https://guagefangzhen.cn/\"><span style=\" text-decoration: underline; color:#0000ff;\">更多分享:https://guagefangzhen.cn</span></a><br/></p></body></html>"))
self.radioButton_DirGif.setText(_translate("GifSpliter", "生成到GIF所在目录"))
self.radioButton_DirSpec.setText(_translate("GifSpliter", "生成到指定目录"))
self.radioButton_DirApp.setText(_translate("GifSpliter", "生成到程序所在目录"))
self.label_2.setText(_translate("GifSpliter", "指定输出目录:"))
self.textEdit_DirSpec.setHtml(_translate("GifSpliter", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n"
"</style></head><body style=\" font-family:\'SimSun\'; font-size:9pt; font-weight:400; font-style:normal;\">\n"
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">指定分割帧文件输出路径</p></body></html>"))
self.checkBox_openDirSpec.setText(_translate("GifSpliter", "分割后打开目录"))
import res_rc
# 用于定义gif分割程序
import os
import imageio
class GifSplitter:
def __init__(self, gif_file):
self.gif_file = gif_file
self.gif = imageio.get_reader(gif_file)
def get_gif_info(self):
"""获取gif信息"""
info = {}
info['file_name'] = os.path.basename(self.gif_file)
info['folder_path'] = os.path.dirname(self.gif_file)
info['total_frames'] = len(self.gif)
return info
def export_frames(self, save_folder=None):
"""导出gif所有帧为png图片"""
if save_folder is None:
save_folder = os.path.join(self.get_gif_info()['folder_path'],
'splitted')
if not os.path.exists(save_folder):
os.mkdir(save_folder)
for i, frame in enumerate(self.gif):
imageio.imsave(os.path.join(save_folder, '{}-{:03d}.png'.format(
self.get_gif_info()['file_name'], i)), frame)
print(f'完成分割: "{(os.path.basename(self.gif_file))}" | 输出文件夹-->"{save_folder}"')
@classmethod
def split_gifs_in_folder(cls, folder_path, save_folder=None):
"""分割文件夹内所有的gif文件"""
print(f'拖拽文件夹为:"{folder_path}"')
print(f'输出文件夹为:"{save_folder}"')
if save_folder is None:
save_folder = os.path.join(folder_path, 'splitted')
if not os.path.exists(save_folder):
os.mkdir(save_folder)
gif_files = [file for file in os.listdir(folder_path)
if file.endswith('.gif')]
i = 1
for gif_file in gif_files:
gif_splitter = cls(os.path.join(folder_path, gif_file))
gif_splitter.export_frames(save_folder)
print(f'文件夹处理进度: {i}/{len(gif_files)}')
i = i + 1
if __name__ == '__main__':
# 分割单个gif文件
gif_splitter = GifSplitter('test.gif')
gif_splitter.export_frames(save_folder="gif")
# 分割文件夹内所有gif文件
GifSplitter.split_gifs_in_folder('gif_folder')








