DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Snippets has posted 5883 posts at DZone. View Full User Profile

Latest And Greatest Directory Thumbnailer

03.08.2006
| 3157 views |
  • submit to reddit
        This does basically the same thing as my original code (http://www.bigbold.com/snippets/posts/show/1296), but significantly faster. Thumbnail sizes are cached between executions, and they could probably be kept around as static data in the mod_python environment if I could figure out how.

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