
()
用wxPython写一个简单的图片格式转换器,把遇到的一些问题记录下来。
开发环境:win10、python3.8.10、wxPython4.1.1
直接上代码
importosimportwxfromPILimportImage,ImageOps,ImageFile#支持的图片文件格式(扩展名)IMAGE_FILE_EXTS=['.png','.jpg','.jpeg','.gif','.bmp','.ico','.tif','.webp']#遍历文件,将所有文件的路径放入一个列表里deffile_walk(root_path):file_list=[]fordirPath,dirNames,fileNamesinos.walk(root_path):forfileNameinfileNames:ext=os.path.splitext(fileName)[1]#分离出文件扩展名ifextinIMAGE_FILE_EXTS:#根据文件扩展名判断是不是图片文件,如果是添加到列表中filePath=os.path.join(dirPath,fileName)#用文件目录和文件名拼接出完整的文件绝对路径file_list.append(filePath)#添加到文件列表returnfile_listclassMainFrame(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#字号加1panel.SetFont(font)#设置字体为修改后的字体#创建一个布局管理器panelSizer=wx.BoxSizer(wx.VERTICAL)iPanel=self.CreateInputPanel(panel)#创建输入相关控件面板oPanel=self.CreateOutputPanel(panel)#创建输出相关控件面板cPanel=self.CreateConvertPanel(panel)#创建转换相关控件面板#添加到布局管理器panelSizer.Add(iPanel,wx.EXPAND|wx.TOP,10)panelSizer.Add(oPanel,10)panelSizer.Add(cPanel,10)#创建提示信息面板self.tip=wx.StaticText(panel,"")panelSizer.Add(self.tip,wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP,10)panel.SetSizer(panelSizer)#创建输入相关控件面板defCreateInputPanel(self,panel):inputPanel=wx.Panel(panel)inputSizer=wx.BoxSizer(wx.HORIZONTAL)inputPanel.SetSizer(inputSizer)label=wx.StaticText(inputPanel,"图片输入路径:")inputSizer.Add(label,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,'浏览...')browseButton.Bind(wx.EVT_BUTTON,self.ChangeSrcDirButtonEvent)inputSizer.Add(browseButton,wx.RIGHT,10)returninputPanel#创建输出相关控件面板defCreateOutputPanel(self,panel):outputPanel=wx.Panel(panel)outputSizer=wx.BoxSizer(wx.HORIZONTAL)outputPanel.SetSizer(outputSizer)label=wx.StaticText(outputPanel,"图片输出路径:")outputSizer.Add(label,10)self.dstPathTextCtrl=wx.TextCtrl(outputPanel)self.dstPathTextCtrl.SetEditable(False)outputSizer.Add(self.dstPathTextCtrl,5)browseButton=wx.Button(outputPanel,'浏览...')电脑browseButton.Bind(wx.EVT_BUTTON,self.ChangeDstDirButtonEvent)outputSizer.Add(browseButton,10)returnoutputPanel#创建转换相关控件面板defCreateConvertPanel(self,panel):cPanel=wx.Panel(panel)cSizer=wx.BoxSizer(wx.HORIZONTAL)cPanel.SetSizer(cSizer)label=wx.StaticText(cPanel,'图片输出格式:')cSizer.Add(label,10)self.extComboBox=wx.ComboBox(cPanel,"",(-1,-1),(60,IMAGE_FILE_EXTS,wx.CB_DROPDOWN)self.extComboBox.SetSelection(0)cSizer.Add(self.extComboBox,0)cSizer.Addspacer(10)browseButton=wx.Button(cPanel,'转换格式')browseButton.Bind(wx.EVT_BUTTON,self.ConvertButtonEvent)cSizer.Add(browseButton,10)returncPanel#点击图片输入路径浏览按钮,触发此方法,打开文件选择对话框,选择目录并返回该目录路径地址defChangeSrcDirButtonEvent(self,event):dialog=wx.DirDialog(self,"选择图片目录&电脑#34;,os.getcwd(),wx.DD_DEFAULT_STYLE)ifdialog.ShowModal()==wx.ID_OK:dirPath=dialog.GetPath()self.srcPathTextCtrl.SetValue(dirPath)ifself.dstPathTextCtrl.GetValue()=='':self.dstPathTextCtrl.SetValue(dirPath)#点击图片输出路径浏览按钮,触发此方法,打开文件选择对话框,选择目录并返回该目录路径地址defChangeDstDirButtonEvent(self,"选择图片目录",wx.DD_DEFAULT_STYLE)ifdialog.ShowModal()==wx.ID_OK:dirPath=dialog.GetPath()self.dstPathTextCtrl.SetValue(dirPath)#点击转换格式按钮,触发此方法,获取图片输入输出路径和图片输出类型,转换图片。defConvertButtonEvent(self,event):srcPath=self.srcPathTextCtrl.GetValue()dstPath=self.dstPathTextCtrl.GetValue()ifsrcPath=='':wx.MessageBox('请选择图片输入路径','消息',wx.OK|wx.ICON_informatION)returnifdstPath=='':wx.MessageBox('请选择图片输出路径',wx.OK|wx.ICON_informatION)电脑returnext=self.extComboBox.GetValue()file_list=file_walk(srcPath)forsrcImagePathinfile_list:image=Image.open(srcImagePath)image=ImageOps.exif_transpose(image)srcImageName=os.path.split(srcImagePath)[1]dstimageName=os.path.splitext(srcImageName)[0]+extdstimagePath=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)forsrcImagePathinfile_list:print(srcImagePath)ifos.path.getsize(srcImagePath)==0:continueimage=Image.open(srcImagePath)image=ImageOps.exif_transpose(image)srcImageName=os.path.split(srcImagePath)[1]dstimageName=os.path.splitext(srcImageName)[0]+extdstimagePath=os.path.join(dstPath,dstimageName)image.save(dstimagePath)self.tip.SetLabel('正在转换:%s'%srcImagePath)
再来运行一下
继续检查图片
对于图片损坏的问题,无法处理。但是不能让程序中止,还要完成后面图片的转换。我们需要捕捉异常,并继续循环。
file_list=file_walk(srcPath)forsrcImagePathinfile_list:print(srcImagePath)ifos.path.getsize(srcImagePath)==0:continuetry:image=Image.open(srcImagePath)image=ImageOps.exif_transpose(image)srcImageName=os.path.split(srcImagePath)[1]dstimageName=os.path.splitext(srcImageName)[0]+extdstimagePath=os.path.join(dstPath,dstimageName)image.save(dstimagePath)self.tip.SetLabel('正在转换:%s'%srcImagePath)exceptExceptionase:print(e)continueself.tip.SetLabel('转换完成')
图片批量转换完成。
上面测试的是几百张小图片,我们再来测试一下批量处理照片,照片的文件比较大,每张都有好几M。
果真出问题了,界面卡死了。目标文件夹有新的图片还在不断生成,说明程序仍在运行,但是界面已经卡死。在处理复杂的任务的时候,不能把任务写在UI线程里,需要单独使用线程处理。
电脑