使用wxPython显示缩略图的简单方法
我在找一个简单的方法,用wxPython来显示缩略图。这不是关于如何创建缩略图的问题。我有一个存放缩略图的文件夹,想把它们显示在屏幕上。我故意不使用像(面板、框架、窗口、滚动窗口)这样的术语,因为我对各种解决方案都持开放态度。
另外,我发现了很多关于显示单张图片的例子,所以提到这些解决方案对我没有帮助。我的需求是要同时显示多张图片。
看起来我想做的事情可以通过ThumbnailCtrl来实现,但Andrea的代码比较复杂,我找不到负责在屏幕上显示的那部分。我在Mark Lutz的《Programming Python》一书中找到了一个简单的解决方案,但他的viewer_thumbs.py例子虽然简单,但使用的是Tkinter。
所以,如果有任何wx的解决方案,我将非常感激。
补充:我添加了一个链接,里面有Mark Lutz的Tkinter代码。有没有人能想到wx的对应解决方案呢?
http://codeidol.com/community/python/viewing-and-processing-images-with-pil/17565/#part-33
3 个回答
我建议你把它们显示为 wx.Image,放在一个框架里。
http://www.wxpython.org/docs/api/wx.Image-class.html
根据这个类的介绍:“这是一个平台无关的图像类。你可以通过数据创建图像,或者使用 wx.Bitmap.ConvertToImage,或者从多种格式的文件中加载图像。它提供了一些功能,可以设置和获取图像的像素,所以可以用来做一些基本的图像处理。”
看起来这个方法应该能满足你的需求,除非我漏掉了什么。
我建议你使用ThumbNailCtrl这个小部件:http://wxpython.org/Phoenix/docs/html/lib.agw.thumbnailctrl.html。在wxPython的演示中有个不错的例子。或者你也可以参考文档中的这个例子。需要注意的是,ThumbNailCtrl需要安装Python图像库。
import os
import wx
import wx.lib.agw.thumbnailctrl as TC
class MyFrame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, -1, "ThumbnailCtrl Demo")
panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL)
thumbnail = TC.ThumbnailCtrl(panel, imagehandler=TC.NativeImageHandler)
sizer.Add(thumbnail, 1, wx.EXPAND | wx.ALL, 10)
thumbnail.ShowDir(os.getcwd())
panel.SetSizer(sizer)
# our normal wxApp-derived class, as usual
app = wx.App(0)
frame = MyFrame(None)
app.SetTopWindow(frame)
frame.Show()
app.MainLoop()
只需要把thumbnail.ShowDir(os.getcwd())这一行改成指向你电脑上正确的文件夹。
我还写了一篇关于查看照片的文章,地址在这里:http://www.blog.pythonlibrary.org/2010/03/26/creating-a-simple-photo-viewer-with-wxpython/。不过那篇文章没有使用缩略图。
我不太确定自己是否应该回答自己的问题,但我找到了解决办法,想和大家分享一下。我之前用的是wx版本2.8。后来我发现,在2.9和3.0版本中新增了一个叫做WrapSizer的小工具。于是我把wx更新到3.0版本,这样解决问题就变得非常简单了。下面是相关的代码片段。
self.PhotoMaxWidth = 100
self.PhotoMaxHeight = 100
self.GroupOfThumbnailsSizer = wx.WrapSizer()
self.CreateThumbNails(len(ListOfPhotots),ListOfPhotots)
self.GroupOfThumbnailsSizer.SetSizeHints(self.whateverPanel)
self.whateverPanel.SetSizer(self.GroupOfThumbnailsSizer)
self.whateverPanel.Layout()
def CreateThumbNails(self, n, ListOfFiles):
thumbnails = []
backgroundcolor = "white"
for i in range(n):
ThumbnailSizer = wx.BoxSizer(wx.VERTICAL)
self.GroupOfThumbnailsSizer.Add(ThumbnailSizer, 0, 0, 0)
thumbnails.append(ThumbnailSizer)
for thumbnailcounter, thumbsizer in enumerate(thumbnails):
image = Image.open(ListOfFiles[thumbnailcounter])
image = self.ResizeAndCenterImage(image, self.PhotoMaxWidth, self.PhotoMaxHeight, backgroundcolor)
img = self.pil_to_image(image)
thumb= wx.StaticBitmap(self.timelinePanel, wx.ID_ANY, wx.BitmapFromImage(img))
thumbsizer.Add(thumb, 0, wx.ALL, 5)
return
def pil_to_image(self, pil, alpha=True):
""" Method will convert PIL Image to wx.Image """
if alpha:
image = apply( wx.EmptyImage, pil.size )
image.SetData( pil.convert( "RGB").tostring() )
image.SetAlphaData(pil.convert("RGBA").tostring()[3::4])
else:
image = wx.EmptyImage(pil.size[0], pil.size[1])
new_image = pil.convert('RGB')
data = new_image.tostring()
image.SetData(data)
return image
def ResizeAndCenterImage(self, image, NewWidth, NewHeight, backgroundcolor):
width_ratio = NewWidth / float(image.size[0])
temp_height = int(image.size[1] * width_ratio)
if temp_height < NewHeight:
img2 = image.resize((NewWidth, temp_height), Image.ANTIALIAS)
else:
height_ratio = NewHeight / float(image.size[1])
temp_width = int(image.size[0] * height_ratio)
img2 = image.resize((temp_width, NewHeight), Image.ANTIALIAS)
background = Image.new("RGB", (NewWidth, NewHeight), backgroundcolor)
masterwidth = background.size[0]
masterheight = background.size[1]
subwidth = img2.size[0]
subheight = img2.size[1]
mastercenterwidth = masterwidth // 2
mastercenterheight = masterheight // 2
subcenterwidth = subwidth // 2
subcenterheight = subheight // 2
insertpointwidth = mastercenterwidth - subcenterwidth
insertpointheight = mastercenterheight - subcenterheight
background.paste(img2, (insertpointwidth, insertpointheight))
return background
我从另一个StackOverflow的帖子中得到了pil_to_image的部分代码,而ResizeAndCenterImage的部分是我自己写的,目的是让我的所有缩略图大小一致,同时保持图片的比例,不进行裁剪。如果你愿意,可以完全不调用resize和center的部分。