(说明: 这是我2007年写在cublog(China Unix)上的博客,现在把它转到这里来.)
上次写了一个图片转ascii的程序,由于没有图像界面,用起来难免不爽,所以就学习了一下wxwidgets GUI库,写了一个图形界面.
一共建立两个类,主程序类 mainApp(wx.app),子类swindow(wx.Frame).主程序类很简单,就是在main函数里面实例化swindow类,然后显示出来就行了.子类比较复杂,所有功能都在里面,以下是swindow.py的代码:
import wx
import os
import Image
wildcard = "jpg file(*.jpg)|*.jpg|" \
"bmp file(*.bmp)|*.bmp|" \
"gif file(*.gif)|*.gif|" \
"All files (*.*)|*.*"
wildcard2 = "Text file(*.txt)|*.txt|" \
"All files (*.*)|*.*"
def create(parent):
return Frame1(parent)
[wxID_FRAME1, wxID_FRAME1BUTTON1, wxID_FRAME1BUTTON2, wxID_FRAME1CHECKBOX1,
wxID_FRAME1STATICBITMAP1, wxID_FRAME1STATICBOX1, wxID_FRAME1STATICTEXT1,
wxID_FRAME1TEXTCTRL1, wxID_FRAME1TEXTWIDTH,
] = [wx.NewId() for _init_ctrls in range(9)]
class swindow(wx.Frame):
def _init_ctrls(self, prnt):
# generated method, don't edit
wx.Frame.__init__(self, id=wxID_FRAME1, name='', parent=prnt,
pos=wx.Point(318, 225), size=wx.Size(640, 371),
style=wx.DEFAULT_FRAME_STYLE | wx.ALWAYS_SHOW_SB | wx.STATIC_BORDER | wx.CLIP_CHILDREN | wx.FRAME_SHAPED | wx.CLOSE_BOX | wx.CAPTION | wx.MINIMIZE_BOX | wx.MINIMIZE,
title='\xcd\xbc\xc6\xac\xd7\xaa\xbb\xaf\xce\xaaASCII')
self.SetClientSize(wx.Size(632, 337))
self.SetBackgroundColour(wx.Colour(128, 128, 255))
self.SetToolTipString('')
self.SetWindowVariant(wx.WINDOW_VARIANT_SMALL)
self.SetThemeEnabled(True)
self.Bind(wx.EVT_CLOSE, self.OnFrame1Close)
self.checkBox1 = wx.CheckBox(id=wxID_FRAME1CHECKBOX1,
label='\xb6\xfe\xd6\xb5\xcd\xbc\xcf\xf1', name='checkBox1',
parent=self, pos=wx.Point(416, 248), size=wx.Size(112, 22),
style=0)
self.checkBox1.SetValue(False)
self.checkBox1.SetFont(wx.Font(11, wx.SWISS, wx.NORMAL, wx.NORMAL,
False, '\xcb\xce\xcc\xe5'))
self.staticBitmap1 = wx.StaticBitmap(id=wxID_FRAME1STATICBITMAP1,
name='staticBitmap1', parent=self, pos=wx.Point(9, 10),
size=wx.Size(208, 197), style=wx.STATIC_BORDER)
self.staticBitmap1.SetHelpText('')
self.staticBitmap1.SetLabel('')
self.staticBitmap1.Show(True)
self.staticBitmap1.SetAutoLayout(False)
self.textCtrl1 = wx.TextCtrl(id=wxID_FRAME1TEXTCTRL1, name='textCtrl1',
parent=self, pos=wx.Point(224, 8), size=wx.Size(400, 200),
style=wx.VSCROLL | wx.HSCROLL | wx.TE_LEFT|wx.TE_MULTILINE,
value='')
self.textCtrl1.SetFont(wx.Font(4, wx.SWISS, wx.NORMAL, wx.BOLD, False,
'Courier New'))
self.textCtrl1.SetEditable(True)
self.textCtrl1.SetHelpText('')
self.button1 = wx.Button(id=wxID_FRAME1BUTTON1,
label='\xb4\xf2\xbf\xaa\xce\xc4\xbc\xfe', name='button1',
parent=self, pos=wx.Point(240, 296), size=wx.Size(80, 24),
style=0)
self.button1.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL, False,
'Tahoma'))
self.button1.Bind(wx.EVT_LEFT_UP, self.OnButton1LeftUp)
self.button2 = wx.Button(id=wxID_FRAME1BUTTON2,
label='\xc9\xfa\xb3\xc9ASCII', name='button2', parent=self,
pos=wx.Point(360, 296), size=wx.Size(80, 24), style=0)
self.button2.SetFont(wx.Font(11, wx.SWISS, wx.NORMAL, wx.NORMAL, False,
'Tahoma'))
self.button2.Bind(wx.EVT_LEFT_UP, self.OnButton2LeftUp)
self.staticBox1 = wx.StaticBox(id=wxID_FRAME1STATICBOX1, label='',
name='staticBox1', parent=self, pos=wx.Point(144, 224),
size=wx.Size(392, 100), style=0)
self.textWidth = wx.TextCtrl(id=wxID_FRAME1TEXTWIDTH, name='textWidth',
parent=self, pos=wx.Point(272, 248), size=wx.Size(72, 18),
style=0, value='100')
self.textWidth.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL,
False, 'Courier New'))
self.staticText1 = wx.StaticText(id=wxID_FRAME1STATICTEXT1,
label='\xc3\xbf\xd0\xd0\xd7\xd6\xb7\xfb\xca\xfd:',
name='staticText1', parent=self, pos=wx.Point(176, 248),
size=wx.Size(83, 15), style=0)
self.staticText1.SetFont(wx.Font(11, wx.SWISS, wx.NORMAL, wx.NORMAL,
False, '\xcb\xce\xcc\xe5'))
self.savefile = 'image.txt'
def __init__(self, parent):
self._init_ctrls(parent)
def gray21(self,im):
a,b = im.size
for i in range(a):
for j in range(b):
if im.getpixel((i,j)) > 128:
im.putpixel((i,j),255)
else:
im.putpixel((i,j),0)
return im
def image2ascii(self,imfile):
table = "#8XOHLTI)i=+;:,. "
im = Image.open(imfile)
if im.mode != "L":
im = im.convert("L")
w = int(self.textWidth.GetValue())
h = int(float(w) * float(im.size[1])/float(im.size[0]))
im = im.resize((w,h))
if self.checkBox1.GetValue():
#im = im.convert('1')
im =self.gray21(im)
f = open(self.savefile,'w+')
a = im.size[0]
b = im.size[1]
for i in range(1,b,2):
line = ''
for j in range(a):
line += table[int((float(im.getpixel((j,i)))/256.0)*len(table))]
line += "\n"
f.write(line)
f.close()
def OnButton1LeftUp(self, event):
dlg = wx.FileDialog(
self, message="Please choose an image",
defaultDir=os.getcwd(),
defaultFile="*.jpg",
wildcard=wildcard,
style=wx.OPEN | wx.MULTIPLE | wx.CHANGE_DIR
)
if dlg.ShowModal() == wx.ID_OK:
self.imfile = dlg.GetPath()
im = Image.open(self.imfile)
im = im.resize((208, 197))
im.save('temp.jpg','JPEG')
self.staticBitmap1.SetBitmap(bitmap=wx.Bitmap('temp.jpg',wx.BITMAP_TYPE_JPEG))
dlg.Destroy()
event.Skip()
def OnButton2LeftUp(self, event):
dlg = wx.FileDialog(
self, message="Save txt file as ...", defaultDir=os.getcwd(),
defaultFile="", wildcard=wildcard2 , style=wx.SAVE
)
if dlg.ShowModal() == wx.ID_OK:
self.savefile = dlg.GetPath()
dlg.Destroy()
self.image2ascii('temp.jpg')
f = open(self.savefile,'r')
text = ''
for x in f.readlines():
text += x
self.textCtrl1.SetValue(text)
f.close()
event.Skip()
def OnFrame1Close(self, event):
if os.path.exists("temp.jpg"):
os.remove("temp.jpg")
event.Skip()
主要有几个关键:
1,中间使用了temp.jpg作为临时文件,在程序结束的时候删除.因为pyimaging的Image(处理时用到)和wxwidgets的staticbitmap(显示时用到)不能直接转换,只能使用临时文件来连接这两个数据类型.
2,显示文本的时候,只能用等宽字体才能有效果,否则这些字符会错位的.
wxwidgets的界面相当漂亮,程序的运行结果如下:
[已经编译成exe文件,只是有点大,大概7M,呵呵]
关于wxpython的相关内容,请参见: wxwidgets