Also note that the thumbnailing function no longer returns a complete page, but rather a single table (compatible with either HTML or XHTML). This allows the code to be embedded into something like a photo gallery.
A simple function is shown at the end of this snippet, to set up thumbnailing with mod_python on apache.
from os.path import join,exists from os import stat,mkdir,listdir import re from PIL import Image import cPickle images_per_row = 5 max_width,max_height = 150,150 search = re.compile("(.*\.jpe?g$)|(.*\.png$)|(.*\.gif$)", re.IGNORECASE) def list_directory(path): thumbnail_size_cache = {} thumbnail_size_cache_changed = False return_value = [] dir_list = listdir(path) images = [file for file in dir_list if search.match(file)] if len(images) < 1: return '' # Interesting directories thumbsdir = join(path, ".thumbnails") # Try to load the size cache from a file cache_file_path = join(thumbsdir, "thumbnail_size_cache.dat") if exists (cache_file_path): cache_file = open(cache_file_path, "r") thumbnail_size_cache = cPickle.load(cache_file) cache_file.close() images.sort() return_value.append('<table width="100%" border="0"><tr>\n') row_template = '<td><a href="%(name)s"><img src=".thumbnails/%(name)s" alt="%(name)s" width="%(width)d" height="%(height)d"/></a>' # If the thumbnail directory does not exist, create it if not exists(thumbsdir): mkdir(thumbsdir) image_num = 0 for image in images: image_num += 1 thumbfile = join(thumbsdir, image) filepath = join(path, image) width,height = 0,0 # Check if there is an already-existing thumbnail create_new_thumbnail = True if exists(thumbfile): thumb_stat = stat(thumbfile) img_stat = stat(filepath) # Check if the thumbnail is newer than the image if img_stat.st_mtime < thumb_stat.st_mtime: try: width,height = thumbnail_size_cache[image] create_new_thumbnail = False except KeyError: pass if create_new_thumbnail: # Thumbnail the image thumbnail = Image.open(filepath) thumbnail.thumbnail((max_width, max_height), Image.ANTIALIAS) thumbnail.save(thumbfile) thumbnail_size_cache[image] = thumbnail.size thumbnail_size_cache_changed = True width,height = thumbnail.size return_value.append(row_template % {'name': image, 'width': width, 'height': height}) if image_num % images_per_row: return_value.append('</td>\n') else: return_value.append('</td></tr><tr>\n') return_value.append("</tr></table>") # Save the cache if thumbnail_size_cache_changed: return_value.append("Saved cache") cache_file = open(cache_file_path, "w") cPickle.dump(thumbnail_size_cache, cache_file, cPickle.HIGHEST_PROTOCOL) cache_file.close() return ''.join(return_value) #################################### ### mod_python stuff starts here ### #################################### from mod_python import apache html_header = '''<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head><title>Directory Listing</title></head> <body><div>''' xhtml_header = '''<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml111/DTD/xhtml111.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> <head><title>Directory Listing</title></head> <body><div>''' def handler(req): if not os.path.isdir(req.filename): file = open(req.filename) req.write(file.read()) return apache.OK return_value = [] # Check for XHTML acceptance accept_types = req.headers_in["Accept"].split(",") # Don't do any measure of preference for now if "application/xhtml+xml" in accept_types: # Accepts XHTML return_value.append(xhtml_header) req.content_type="application/xhtml+xml" else: # Does not accept XHTML return_value.append(html_header) req.content_type="text/html" return_value.append(list_directory(req.filename)) return_value.append("</div></body></html>") req.write(''.join(return_value)) return apache.OK