Question

I am looking for a simple solution to display thumbnails using wxPython. This is not about creating the thumbnails. I have a directory of thumbnails and want to display them on the screen. I am purposely not using terms like (Panel, Frame, Window, ScrolledWindow) because I am open to various solutions.

Also note I have found multiple examples for displaying a single image, so referencing any such solution will not help me. The solution must be for displaying multiple images at the same time in wx.

It seems that what I want to do is being done in ThumbnailCtrl, but Andrea's code is complex and I cannot find the portion that does the display to screen. I did find a simple solution in Mark Lutz's Programming Python book, but while his viewer_thumbs.py example definitely has the simplicity that I am looking for, it was done using Tkinter.

So please any wx solution will be greatly appreciated.

EDIT: I am adding a link to one place where Mark Lutz's working Tkinter code can be found. Can anyone think of a wx equivalent?

http://codeidol.com/community/python/viewing-and-processing-images-with-pil/17565/#part-33

Was it helpful?

Solution 2

Not sure if I am supposed to answer my own question but I did find a solution to my problem and I wanted to share. I was using wx version 2.8. I found that in 2.9 and 3.0 there was a widget added called WrapSizer. Once I updated my version of wx to 3.0 that made the solution beyond simple. Here are the code snippets that matter.

    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

I got the pil_to_image portion from another stackoverflow post and I wrote the ResizeAndCenterImage portion to make all of my thumbnails the same size while keeping the aspect ration intact and not do any cropping. The resize and center call can be skipped all together if you like.

OTHER TIPS

I would recommend using the ThumbNailCtrl widget: http://wxpython.org/Phoenix/docs/html/lib.agw.thumbnailctrl.html. There is a good example in the wxPython demo. Or you could use this one from the documentation. Note that the ThumbNailCtrl requires the Python Imaging Library to be installed.

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()

Just change the line thumbnail.ShowDir(os.getcwd()) so that it points at the right folder on your machine.

I also wrote up an article for viewing photos here: http://www.blog.pythonlibrary.org/2010/03/26/creating-a-simple-photo-viewer-with-wxpython/ It doesn't use thumbnails though.

I would just display them as wx.Image inside a frame.

http://www.wxpython.org/docs/api/wx.Image-class.html

From the class: "A platform-independent image class. An image can be created from data, or using wx.Bitmap.ConvertToImage, or loaded from a file in a variety of formats. Functions are available to set and get image bits, so it can be used for basic image manipulation."

Seems it should be able to do what you want, unless I'm missing something.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top