pngtile/handlers.py
author Tero Marttila <terom@fixme.fi>
Wed, 27 Jan 2010 02:18:58 +0200
changeset 126 2e0f7cbe528f
parent 107 9fcf58fb113a
permissions -rw-r--r--
remove print output
import os, os.path
import pypngtile as pt

from werkzeug import Response, exceptions

from pngtile import render

# path to images
DATA_ROOT = os.environ.get("PNGTILE_DATA_PATH") or os.path.abspath('data/')

# only open each image once
IMAGE_CACHE = {}

### Parse request data
def get_path (req_path) :
    """
        Returns the name and path requested
    """
    
    # check DATA_ROOT exists..
    if not os.path.isdir(DATA_ROOT) :
        raise exceptions.InternalServerError("Missing DATA_ROOT")

    # path to image
    image_name = req_path.lstrip('/')
    
    # build absolute path
    image_path = os.path.abspath(os.path.join(DATA_ROOT, image_name))

    # ensure the path points inside the data root
    if not image_path.startswith(DATA_ROOT) :
        raise exceptions.NotFound(image_name)

    return image_name, image_path

def get_image (name, path) :
    """
        Gets an Image object from the cache, ensuring that the cached is available
    """

    # get Image object
    if path in IMAGE_CACHE :
        # get from cache
        image = IMAGE_CACHE[path]

    else :
        # open
        image = pt.Image(path)

        # check
        if image.status() not in (pt.CACHE_FRESH, pt.CACHE_STALE) :
            raise exceptions.InternalServerError("Image cache not available: %s" % name)

        # load
        image.open()

        # cache
        IMAGE_CACHE[path] = image
    
    return image


### Handle werkzeug.Request objects -> werkzeug.Response
def handle_dir (req, name, path) :
    """
        Handle request for a directory
    """
    
    prefix = req.script_root
    
    return Response(render.dir_html(prefix, name, path), content_type="text/html")



def handle_img_viewport (req, image, name) :
    """
        Handle request for image viewport
    """
    
    prefix = req.script_root

    # viewport
    return Response(render.img_html(prefix, name, image), content_type="text/html")


def handle_img_region (req, image, cache) :
    """
        Handle request for an image region
    """

    # specific image
    width = int(req.args['w'])
    height = int(req.args['h'])
    cx = int(req.args['cx'])
    cy = int(req.args['cy'])
    zoom = int(req.args.get('zl', "0"))
    
    try :
        # yay full render
        return Response(render.img_png_region(image, cx, cy, zoom, width, height, cache), content_type="image/png")

    except ValueError, ex :
        # too large
        raise exceptions.Forbidden(str(ex))


def handle_img_tile (req, image, cache) :
    """
        Handle request for image tile
    """

    # tile
    x = int(req.args['x'])
    y = int(req.args['y'])
    zoom = int(req.args.get('zl', "0"))

    # cache?
        
    # yay render
    return Response(render.img_png_tile(image, x, y, zoom, cache), content_type="image/png")

## Dispatch req to handle_img_*
def handle_img (req, name, path, cache) :
    """
        Handle request for an image
    """

    # get image object
    image = get_image(name, path)

    # what view?
    if not req.args :
        return handle_img_viewport(req, image, name)

    elif 'w' in req.args and 'h' in req.args and 'cx' in req.args and 'cy' in req.args :
        return handle_img_region(req, image, cache)

    elif 'x' in req.args and 'y' in req.args :
        return handle_img_tile(req, image, cache)

    else :
        raise exceptions.BadRequest("Unknown args")



## Dispatch request to handle_*
def handle_req (req, cache) :
    """
        Main request handler
    """
    
    # decode req
    name, path = get_path(req.path)

    # determine dir/image
    if os.path.isdir(path) :
        # directory
        return handle_dir(req, name, path)
    
    elif not os.path.exists(path) :
        # no such file
        raise exceptions.NotFound(name)

    elif not name or not name.endswith('.png') :
        # invalid file
        raise exceptions.BadRequest("Not a PNG file")
    
    else :
        # image
        return handle_img(req, name, path, cache)