“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')