[mod_python] Image handling handler

Damjan gdamjan at mail.net.mk
Tue Sep 21 17:53:26 EDT 2004


I've hacked this last evening (stayed a bit longer that should've).
Its an handler that allows modifications of images on the fly, but also
cache's the results... its a bit hackish but anyway I'll sahre it here
as a demo of mod_python.

I enable it with this .htaccess file
	AcceptPathInfo On
	AddHandler mod_python .png .py .jpg .jpeg
	PythonHandler image | .png .jpg .jpeg
	PythonHandler mptest | .py
	PythonDebug On
	PythonOption Cache on
	PythonOption CacheDir /tmp/cache

Ok what exactly the modules does?
Say you have e picture at the /images/me.jpg URL

Retrieving /images/me.jpg will let Apache handle the request
(apache.DECLINED), that way proper caching is allowed etc.

But getting /images/me.jpg/size?width=100;height=200 will resize the
image with PIL, store the resized image as
/tmp/cache/images/me.jpg/size?width=100;height=200 (but only if 
"Cache on") and send back the resized image to the user.

Other methods are also possible, there's also /thumb?... similar to /size?
but retains the aspect-ratio of the original. /datemodified returns
text/plain content with the data of the last modification of the image
file.
Other methods could extract other meta info from images, implement other
transformations, filters etc...


TODO:
- more error checking is needed

-- 
damjan | дамјан
This is my jabber ID --> damjan at bagra.net.mk <-- not my mail address!!!
-------------- next part --------------
# image.py, mod_python handler
# adds methods to image files (.png, jpeg, .gif and other supported by PIL)
# minimal penalty when no method is used
# on error: raise apache.SERVER_RETURN, apache.HTTP_NOT_IMPLEMENTED
#
# !!! = may throw exception
#
from mod_python import apache
from mod_python import util
from os import path
import os

def handler(req):
    if not path.exists(req.filename):
        return apache.HTTP_NOT_FOUND
    obj = ImageHandler(req)   # !!!
    methodname = 'handle_'+req.path_info[1:]
    method = getattr(obj, methodname, obj.default)
    args = util.parse_qs(req.args or '')
    return method(**args)     # !!!

class ImageHandler(object):
    def __init__(self, req):
        self.req = req
        self.filename = req.filename
        config = req.get_options()
        self.cache_dir = config.get('CacheDir', None)
        self.usecache = config.get('Cache', 'off').lower() in ('on', 'yes')

    def handle_thumb(self, **args):
        # find in cache or make the thumbnail
        # cache it if needed
        from PIL import Image
        key = self.req.unparsed_uri
        filename = self.getcached(key)
        if filename:
            self.req.sendfile(filename)
            return apache.OK
        img = Image.open(self.filename)
        width, height = img.size
        width =  int(args.get('width', args.get('w', (width,) )) [0])
        height = int(args.get('height', args.get('h', (height,) )) [0])
        img.thumbnail((width, height), resample=Image.ANTIALIAS)
        img.save(self.req, format=img.format)
        self.putincache(key, img)
        return apache.OK

    def handle_size(self, **args):
        from PIL import Image
        key = self.req.unparsed_uri
        filename = self.getcached(key)
        if filename:
            self.req.sendfile(filename)
            return apache.OK
        img = Image.open(self.filename)
        width, height = img.size
        width =  int(args.get('width', args.get('w', (width,) )) [0])
        height = int(args.get('height', args.get('h', (height,) )) [0])
        i2 = img.resize((width, height), resample=Image.ANTIALIAS)
        i2.format = img.format
        i2.save(self.req, format=i2.format)
        self.putincache(key, i2)
        return apache.OK

    def handle_view(self, **args):
        self.req.sendfile(self.filename)
        return apache.OK

    def handle_datemodified(self, **args):
        import time
        import locale
        locale.setlocale(locale.LC_ALL, 'mk_MK.UTF-8')
        self.req.content_type = 'text/plain'
        ss=os.stat(self.filename)
        tt=time.localtime(ss.st_mtime)
        s=time.strftime('%c', tt)
        self.req.write(s)
        return apache.OK

    def default(self, **args):
        return apache.DECLINED

    def getcached(self, key):
        cached = self.key2filename(key)
        try:
            css = os.stat(cached)
            fss = os.stat(self.filename)
        except OSError:
            return None
        if css.st_mtime < fss.st_mtime:
            return None
        return cached

    def putincache(self, key, img):
        if not self.usecache:
            return
        filename = self.key2filename(key)
        dirname = path.dirname(filename)
        if not path.exists(dirname):
            os.makedirs(dirname)
        try:
            fp = file(filename,'w')
            img.save(fp, img.format)
            fp.close()
        except:
            pass

    def key2filename(self, key):
        filename = path.join(self.cache_dir, key[1:])
        return filename


More information about the Mod_python mailing list