guiformat使用教程-()

电脑教程 次浏览手机阅读
()

  用wxPython写一个简单的图片格式转换器,把遇到的一些问题记录下来。

开发环境:win10、Python3.8.10、wxPython4.1.1

直接上代码

import osimport wxfrom PIL import Image, ImageOps, ImageFile# 支持的图片文件格式(扩展名)IMAGE_FILE_EXTS = ['.png', '.jpg', '.jpeg', '.gif', '.bmp', '.ico', '.tif', '.webp']# 遍历文件,将所有文件的路径放入一个列表里def file_walk(root_path): file_list = [] for dirPath, dirNames, fileNames in os.walk(root_path): for fileName in fileNames: ext = os.path.splitext(fileName)[1] # 分离出文件扩展名 if ext in IMAGE_FILE_EXTS: # 根据文件扩展名判断是不是图片文件,如果是添加到列表中 filePath = os.path.join(dirPath, fileName) # 用文件目录和文件名拼接出完整的文件绝对路径 file_list.append(filePath) # 添加到文件列表 return file_listclass MainFrame(wx.Frame): def __init__(self, parent): wx.Frame.__init__(self, parent, wx.ID_ANY, "图片格式转换器", size=(550, 200)) self.extCombobox = None # 文件扩展名下拉框控件 self.srcPathTextCtrl = None # 图片输入路径文本框控件 self.dstPathTextCtrl = None # 图片输出路径文件框控件 panel = wx.Panel(self) font = panel.GetFont() # 获取当前窗口字体 font.PointSize += 1 # 字号加1 panel.SetFont(font) # 设置字体为修改后的字体 # 创建一个布局管理器 panelSizer = wx.BoxSizer(wx.VERTICAL) iPanel = self.CreateInputPanel(panel) # 创建输入相关控件面板 oPanel = self.CreateOutputPanel(panel) # 创建输出相关控件面板 cPanel = self.CreateConvertPanel(panel) # 创建转换相关控件面板 # 添加到布局管理器 panelSizer.Add(iPanel, 0, wx.EXPAND | wx.TOP, 10) panelSizer.Add(oPanel, 0, wx.EXPAND | wx.TOP, 10) panelSizer.Add(cPanel, 0, wx.EXPAND | wx.TOP, 10) # 创建提示信息面板 self.tip = wx.StaticText(panel, wx.ID_ANY, "") panelSizer.Add(self.tip, 0, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, 10) panel.SetSizer(panelSizer)# 创建输入相关控件面板def CreateInputPanel(self, panel): inputPanel = wx.Panel(panel) inputSizer = wx.BoxSizer(wx.HORIZONTAL) inputPanel.SetSizer(inputSizer) label = wx.StaticText(inputPanel, wx.ID_ANY, "图片输入路径:") inputSizer.Add(label, 0, wx.ALIGN_CENTER | wx.LEFT, 10) self.srcPathTextCtrl = wx.TextCtrl(inputPanel) self.srcPathTextCtrl.SetEditable(False) inputSizer.Add(self.srcPathTextCtrl, 1, wx.EXPAND | wx.RIGHT, 5) browseButton = wx.Button(inputPanel, wx.ID_ANY, '浏览...') browseButton.Bind(wx.EVT_BUTTON, self.ChangeSrcDirButtonEvent) inputSizer.Add(browseButton, 0, wx.RIGHT, 10) return inputPanel# 创建输出相关控件面板def CreateOutputPanel(self, panel): outputPanel = wx.Panel(panel) outputSizer = wx.BoxSizer(wx.HORIZONTAL) outputPanel.SetSizer(outputSizer) label = wx.StaticText(outputPanel, wx.ID_ANY, "图片输出路径:") outputSizer.Add(label, 0, wx.ALIGN_CENTER | wx.LEFT, 10) self.dstPathTextCtrl = wx.TextCtrl(outputPanel) self.dstPathTextCtrl.SetEditable(False) outputSizer.Add(self.dstPathTextCtrl, 1, wx.EXPAND | wx.RIGHT, 5) browseButton = wx.Button(outputPanel, wx.ID_ANY, '浏览...') 电脑 browseButton.Bind(wx.EVT_BUTTON, self.ChangeDstDirButtonEvent) outputSizer.Add(browseButton, 0, wx.RIGHT, 10) return outputPanel# 创建转换相关控件面板def CreateConvertPanel(self, panel): cPanel = wx.Panel(panel) cSizer = wx.BoxSizer(wx.HORIZONTAL) cPanel.SetSizer(cSizer) label = wx.StaticText(cPanel, wx.ID_ANY, '图片输出格式:') cSizer.Add(label, 0, wx.ALIGN_CENTER | wx.LEFT, 10) self.extCombobox = wx.ComboBox(cPanel, wx.ID_ANY, "", (-1, -1), (60, -1), IMAGE_FILE_EXTS, wx.CB_DROPDOWN) self.extCombobox.SetSelection(0) cSizer.Add(self.extCombobox, 0) cSizer.AddSpacer(10) browseButton = wx.Button(cPanel, wx.ID_ANY, '转换格式') browseButton.Bind(wx.EVT_BUTTON, self.ConvertButtonEvent) cSizer.Add(browseButton, 0, wx.RIGHT, 10) return cPanel# 点击图片输入路径浏览按钮,触发此方法,打开文件选择对话框,选择目录并返回该目录路径地址def ChangeSrcDirButtonEvent(self, event): dialog = wx.DirDialog(self, "选择图片目录&电脑#34;, os.getcwd(), wx.DD_DEFAULT_STYLE) if dialog.ShowModal() == wx.ID_OK: dirPath = dialog.GetPath() self.srcPathTextCtrl.SetValue(dirPath) if self.dstPathTextCtrl.GetValue() == '': self.dstPathTextCtrl.SetValue(dirPath)# 点击图片输出路径浏览按钮,触发此方法,打开文件选择对话框,选择目录并返回该目录路径地址def ChangeDstDirButtonEvent(self, event): dialog = wx.DirDialog(self, "选择图片目录", os.getcwd(), wx.DD_DEFAULT_STYLE) if dialog.ShowModal() == wx.ID_OK: dirPath = dialog.GetPath() self.dstPathTextCtrl.SetValue(dirPath)# 点击转换格式按钮,触发此方法,获取图片输入输出路径和图片输出类型,转换图片。def ConvertButtonEvent(self, event): srcPath = self.srcPathTextCtrl.GetValue() dstPath = self.dstPathTextCtrl.GetValue() if srcPath == '': wx.MessageBox('请选择图片输入路径', '消息', wx.OK | wx.ICON_INFORMATION) return if dstPath == '': wx.MessageBox('请选择图片输出路径', '消息', wx.OK | wx.ICON_INFORMATION) 电脑 return ext = self.extCombobox.GetValue() file_list = file_walk(srcPath) for srcImagePath in file_list: image = Image.open(srcImagePath) image = ImageOps.exif_transpose(image) srcImageName = os.path.split(srcImagePath)[1] dstImageName = os.path.splitext(srcImageName)[0] + ext dstImagePath = os.path.join(dstPath, dstImageName) image.save(dstImagePath) self.tip.SetLabel('正在转换:%s' % srcImagePath) self.tip.SetLabel('转换完成')if __name__ == '__main__': app = wx.App(0) frame = MainFrame(None) frame.CenterOnScreen() frame.Show(True) app.MainLoop()

运行起来

我们来转换一批图片来测试一下

卡在这里不动了,看一下报了什么错

检查一下这张图片

这张图片是0字节的,我们在处理图片之前判断一下图片

file_list = file_walk(srcPath)for srcImagePath in file_list: print(srcImagePath) if os.path.getsize(srcImagePath) == 0: continue image = Image.open(srcImagePath) image = ImageOps.exif_transpose(image) srcImageName = os.path.split(srcImagePath)[1] dstImageName = os.path.splitext(srcImageName)[0] + ext dstImagePath = os.path.join(dstPath, dstImageName) image.save(dstImagePath) self.tip.SetLabel('正在转换:%s' % srcImagePath)

再来运行一下

继续检查图片

对于图片损坏的问题,无法处理。但是不能让程序中止,还要完成后面图片的转换。我们需要捕捉异常,并继续循环。

file_list = file_walk(srcPath)for srcImagePath in file_list: print(srcImagePath) if os.path.getsize(srcImagePath) == 0: continue try: image = Image.open(srcImagePath) image = ImageOps.exif_transpose(image) srcImageName = os.path.split(srcImagePath)[1] dstImageName = os.path.splitext(srcImageName)[0] + ext dstImagePath = os.path.join(dstPath, dstImageName) image.save(dstImagePath) self.tip.SetLabel('正在转换:%s' % srcImagePath) except Exception as e: print(e) continue self.tip.SetLabel('转换完成')

图片批量转换完成。

上面测试的是几百张小图片,我们再来测试一下批量处理照片,照片的文件比较大,每张都有好几M。

果真出问题了,界面卡死了。目标文件夹有新的图片还在不断生成,说明程序仍在运行,但是界面已经卡死。在处理复杂的任务的时候,不能把任务写在UI线程里,需要单独使用线程处理。


电脑
喜欢 ()