用wxPython给图片格式转换器做个GUI

  用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, "选择图片目录", 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线程里,需要单独使用线程处理。

发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章