版权所有,转载请注明出处:http://guangboo.org/2013/02/27/wxpython-pyembeddedimage-script
当我们在开发windows程序时,无论是.net编写的还是MFC编写的窗体程序,经常会使用一些图标或图片进行装饰,通常这些媒体文件都是保存在一个或多个资源文件的中。当程序编译成一个dll或exe文件时,这些资源将被嵌如dll或exe文件中,你可以使用一些查看PE文件格式的工具来查看dll或exe文件的格式,如了解dll或exe文件格式的更多信息可以参考:http://msdn.microsoft.com/en-us/library/windows/hardware/gg463119.aspx.
磁盘文件
然而使用wxPython开发windows程序时,却没有类似资源文件的概念,我们不得不将图片等一些媒体文件一个一个的保存到程序的某个目录下面,待需要时从磁盘读取。如:
icon = wx.Bitmap('icons/chat.ico', wx.BITMAP_TYPE_ICO)
icon = wx.IconFromLocation(wx.IconLocation(r'icons/chat.ico', 0))
icon = wx.Icon(r'icons/chat.ico', wx.BITMAP_TYPE_ICO)
以上几种方式都可以取到chat.ico图标文件,当然还有其他方法。为避免在程序的目录下出现太多的这样的媒体文件,可以将这些文件进行序列化成base64编码的字符串,并在py文件中存在,当程序加载时,这些字符串则直接存在于内存,当需要这些媒体文件时,就可以直接从内存解码出文件流。
PyEmbeddedImage类
wxPython在wx.lib.embeddedimage模块下有PyEmbeddedImage类,专门用于将经过base64编码过的图片的字符串解码成文件流,并提供了接口,将文件流转化成相应的图片格式。如:
from wx.lib.embeddedimage import PyEmbeddedImage
tree_expand = PyEmbeddedImage(
"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAAA3NCSVQICAjb4U/gAAAACVBMVEX/"
"//8AAAAAAAB+UaldAAAAA3RSTlMAEf+ErQhDAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAFnRFWHRD"
"cmVhdGlvbiBUaW1lADEyLzAxLzEyCkHB3wAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtz"
"IENTNAay06AAAAAeSURBVAiZY2DADSRARAYQM64AEmwgQgpEaK3ArQcAe9kDbDbxTbEAAAAASUVO"
"RK5CYII=")
代码中PyEmbeddedImage的参数为一个字符串,这个字符串是一个图片的base64编码,这样我们就可以将图片保存在py文件中,并可以随py文件一同编译和执行,就不需要在目录中存储图片文件了。当我们需要使用这个图片是,可以这样调用:
icon = tree_expand.GetIcon()
bitmap = tree_expand.GetBitmap()
img = tree_expand.GetImage()
当然要根据需要来选择调用哪个方法。当然要想活动这样的好处,首先要把图片进行base64编码,并将编码后的字符串保存到py文件中。然而在开发过程中可能会有很多这样的图片,并且这样的图片还有可能在开发过程中发生变化,如果要一个一个的手动把图片都进行base64编码,那将是一个非常麻烦的事情。因此这里提供一个简单的脚步,帮助快速生成“资源”文件。
帮助脚步
我们可以先按照原来的方式,将图片都保存到一个目录下面,然后使用脚步,将目录下所有的图片文件都进行base64编码,并将这些编码后的“资源”文件保存到一个resource.py文件中。当然资源的名称要符合python的命名规范,因为在resource.py中,资源名就是pythond的变量名。因此这里并以没有子目录,并将图片名称中出现的“-”转化成“资源”名的“_”,如果你有子目录的需求,可以根据自己需要对“资源”名的命名规则进行修改。如下脚步:
# -*- coding:utf-8 -*-
import base64
from StringIO import StringIO
import os
import glob
def encode_file(fn, buffer):
print 'Encode >>', fn
_, ext = os.path.splitext(fn)
if ext in ['.png', '.ico', '.jpg']:
file = open(fn, 'rb')
pic = file.read()
b64 = pic.encode('base64')
buffer.write('%s = PyEmbeddedImage(\n"%s")\n\n' % (os.path.basename(fn).split('.')[0].replace('-', '_'), b64.strip().replace('\n', '"\n"')))
def encode(dir, buffer):
if os.path.isdir(dir):
lst = glob.glob(os.path.join(dir, '*.*'))
for fn in lst:
encode_file(fn, buffer)
else:
encode_file(dir, buffer)
def main(src_dir, res_file):
print 'Out file >> ', os.path.abspath(src_dir), '\n\n'
output = open(src_dir, 'w')
output.write('# -×- coding:utf-8 -*-\n'
'from wx.lib.embeddedimage import PyEmbeddedImage\n\n')
encode(src_dir, output)
output.flush()
output.close()
if __name__ == '__main__':
main('root/icons', 'root/resource.py')
脚步中,方法main函数接受两个参数,第一个参数src_dir为图片的目录,第二个参数res_file为资源文件名,即程序将src_dir目录下的所有图片都进行base64编码,并保持到res_file文件中。生成的文件就像这样:
# -×- coding:utf-8 -*-
from wx.lib.embeddedimage import PyEmbeddedImage
camera24 = PyEmbeddedImage("...............")
chat = PyEmbeddedImage("...............")
emotion32 = PyEmbeddedImage("...............")
video32 = PyEmbeddedImage("...............")
这样当有新增加图片或有修改图片时,资源执行以下脚步,就可以实现资源文件的更新了。