Python Programming – Photo Web Gallery Generator

Introduction

After some time learning Python and tinkering with it, I decided that it was time to use it in a “real world” application. After some thinking, I came up with the idea to program a web gallery generator, which would not be a too big project to work on my spare time and would also be useful to maintain my web site.

Requirements

So I took some time to brainstorm about the functionality to put into the application and came up with the following list:

  • Able to process jpeg files
  • Generate an index page with thumbnails and a main page for each picture
  • The generated html files should be based on templates
  • The settings should be persistent and stored in an xml file
  • A first version should work with the command line, a second one should have a gui
  • The gallery generation should be asynchronous and cancelable at any time

Looking at these requirements, it became quickly obvious that a standard Python distribution would be able to handle most of these requirements, except the image manipulation part. After some research on the net, I found that the Python Imaging Library would be the ideal candidate for this part. For the graphical interface, I decided to stick with Tkinter, which is a defacto standard for Python Gui’s.

Design and Coding

The design phase revealed the need for about a dozen classes and coding was rather straightforward, except for some problems that will be described in the next section.

Even if the application is a small project, it displays some interesting techniques with Python:

  • Image manipulation
  • XML processing
  • Tkinter gui’s
  • Multithreading

Problems encountered

Minidom’s Parse

A first annoying problem I encountered was that the xml.dom.minidom.parse(file) function seems to add empty elements when the xml stored in the file is stored on multiple lines.

This seems odd as the minidom is the standard DOM implementation delivered with Python. Anyway, the workaround was to read the file line for line in memory, to remove the line endings and then to concatenate it into a string. The string is then parsed using the xml.dom.minidom.parseString() function

f = file(Configuration.__xmlFileName, "r")
try:
    # We don't use xml.dom.minidom.parse() because it has a bug that
    # inserts empty elements if the xml files contains spaces and \n's. 
    # So we need to workaround this :-(
    stringConfig = ""
    for line in f.readlines():
        line = line.strip()
        stringConfig += line
	
    self.document = xml.dom.minidom.parseString(stringConfig)
finally:
    f.close()

Validating numeric input in Tkinter Entry fields

I encountered a second annoying problem when I tried to validate numeric input in TKinter Entry fields. This is no standard Tkinter functionality and you have to know the underlying Tk toolkit to know what to do. So I tried to recall the little Tk knowledge I possessed and after some googling and Python/Tk voodoo came up with a solution that subclasses the Tkinter Entry class:

class IntEntry(Entry):
    """
    Class that validates that an entry is an integer.
    Put together after much hacking :-(. These are really low level Tkinter and
    TCL details...
    """
    def __init__(self, master, **kwargs):
        kwargs['validate'] = 'key'
        kwargs['vcmd'] = master.register(self.validatecommand) + ' %P'
        kwargs['invcmd'] = self.invalidcommand
        Entry.__init__(self, master, kwargs)
        
    def validatecommand(self, new):
        try:
            int(new)
            return True
        except:
            return False
    
    def invalidcommand(self):
        return True

Now don’t ask me why it exactly works all I can say is that it works ๐Ÿ˜‰

Image quality

Even if the quality of the resized images is good, it is still below the quality of images resized with other tools, for example BreezeBrowser. In comparison the images generated with PIL are a little bit more blurry, even at the best JPEG quality available. I think the quality is good enough to generate Web Galleries, but an improved quality would be welcome nevertheless.

Screenshots

Main window

KecGalleryGenerator1

Generate gallery dialog

KecGalleryGenerator2

Download

The Gallery Generator was coded using Python 2.4.3, PIL 1.1.6 and wxPython 2.8.4. You need to install those (or a later version) to use the Gallery Generator

Download Kec’s Gallery Generator: Version 0.6.1

Extract the zip file into a folder, then execute WxGui.py to start the WxPython GUI. If you wish to start the Tkinter GUI, execute TkGui.py. Note that the Tkinter GUI is not up-to-date and will be dropped in the future.

The archive also contains two sample template folders, one with very simple templates and on with the actual templates I use for my web site.

Future improvements

Currently the Gallery Generator has already a good level of functionality and suits my needs well, however I’m thinking on adding the following things to improve the generator:

  • Delivery as a stand-alone executable or installable on Windows platforms
  • Option to keep image proportions when resizing

Conclusion

This small project has shown me that Python is much more than a simple scripting language but must be seen as a full-blown programming language that incidentally happens to be interpreted. It provides an extensive standard library and modules for many application domains can easily be found on the net.

However, it also has its quirks as we have seen above which can be annoying. I my opinion, the productivity claims of some Python evangelists must be seen as wishful thinking, and this for the following reasons:

  • The language is not simpler than for example Java. It has operator overloading, lambdas, modules, advanced metaprogramming, generators, etc…
  • Dynamic typing. In my opinion, dynamic typing has the following drawbacks which lead to decreased productivity:
    • It forces the programmer to play the role of the compiler to check for obvious programming errors.
    • Less readable code as type information is not always obvious in function or method signatures.
    • Less intelligent development environments because type information is not available when you write the code (refactorings, intellisense, code navigation, etc…).
  • The documentation is only average for the standard library and sometimes bad or non-existent for add-in modules. A standard documentation format and documenter tool ร  la Javadoc would be a huge step forward
  • Code quality of libraries seems a little bit below the quality of the libraries of commercial languages
  • The gui library delivered with the language has only a basic level of functionality and it is better to use other ones for serious development.

That being said, Python is a fun language to work with but like any languages it has its learning curve which must not be underestimated. ๐Ÿ™‚